diff options
137 files changed, 3467 insertions, 855 deletions
diff --git a/Android.bp b/Android.bp index 32bd40861839..e096c9df5662 100644 --- a/Android.bp +++ b/Android.bp @@ -535,6 +535,7 @@ java_defaults { "telephony/java/android/telephony/ims/aidl/IImsServiceController.aidl", "telephony/java/android/telephony/ims/aidl/IImsServiceControllerListener.aidl", "telephony/java/android/telephony/ims/aidl/IImsSmsListener.aidl", + "telephony/java/android/telephony/ims/aidl/IRcs.aidl", "telephony/java/android/telephony/mbms/IMbmsDownloadSessionCallback.aidl", "telephony/java/android/telephony/mbms/IMbmsStreamingSessionCallback.aidl", "telephony/java/android/telephony/mbms/IMbmsGroupCallSessionCallback.aidl", @@ -611,7 +612,6 @@ java_defaults { "telephony/java/com/android/internal/telephony/euicc/ISetDefaultSmdpAddressCallback.aidl", "telephony/java/com/android/internal/telephony/euicc/ISetNicknameCallback.aidl", "telephony/java/com/android/internal/telephony/euicc/ISwitchToProfileCallback.aidl", - "telephony/java/com/android/internal/telephony/rcs/IRcs.aidl", "wifi/java/android/net/wifi/INetworkRequestMatchCallback.aidl", "wifi/java/android/net/wifi/INetworkRequestUserSelectionCallback.aidl", "wifi/java/android/net/wifi/ISoftApCallback.aidl", diff --git a/Android.mk b/Android.mk index 92e33e988249..e3cc2754fed3 100644 --- a/Android.mk +++ b/Android.mk @@ -72,6 +72,11 @@ $(OUT_DOCS)/offline-sdk-timestamp: $(OUT_DOCS)/offline-sdk-docs-docs.zip $(hide) mkdir -p $(OUT_DOCS)/offline-sdk ( unzip -qo $< -d $(OUT_DOCS)/offline-sdk && touch -f $@ ) || exit 1 +# Run this for checkbuild +checkbuild: doc-comment-check-docs +# Check comment when you are updating the API +update-api: doc-comment-check-docs + # ==== hiddenapi lists ======================================= .KATI_RESTAT: $(INTERNAL_PLATFORM_HIDDENAPI_FLAGS) $(INTERNAL_PLATFORM_HIDDENAPI_FLAGS): \ diff --git a/api/current.txt b/api/current.txt index f1f37896a3db..aac5cc1fbac1 100644 --- a/api/current.txt +++ b/api/current.txt @@ -57,6 +57,7 @@ package android { field public static final java.lang.String BROADCAST_SMS = "android.permission.BROADCAST_SMS"; field public static final java.lang.String BROADCAST_STICKY = "android.permission.BROADCAST_STICKY"; field public static final java.lang.String BROADCAST_WAP_PUSH = "android.permission.BROADCAST_WAP_PUSH"; + field public static final java.lang.String CALL_COMPANION_APP = "android.permission.CALL_COMPANION_APP"; field public static final java.lang.String CALL_PHONE = "android.permission.CALL_PHONE"; field public static final java.lang.String CALL_PRIVILEGED = "android.permission.CALL_PRIVILEGED"; field public static final java.lang.String CAMERA = "android.permission.CAMERA"; @@ -91,7 +92,6 @@ package android { field public static final java.lang.String LOCATION_HARDWARE = "android.permission.LOCATION_HARDWARE"; field public static final java.lang.String MANAGE_DOCUMENTS = "android.permission.MANAGE_DOCUMENTS"; field public static final java.lang.String MANAGE_OWN_CALLS = "android.permission.MANAGE_OWN_CALLS"; - field public static final java.lang.String CALL_COMPANION_APP = "android.permission.CALL_COMPANION_APP"; field public static final java.lang.String MASTER_CLEAR = "android.permission.MASTER_CLEAR"; field public static final java.lang.String MEDIA_CONTENT_CONTROL = "android.permission.MEDIA_CONTENT_CONTROL"; field public static final java.lang.String MODIFY_AUDIO_SETTINGS = "android.permission.MODIFY_AUDIO_SETTINGS"; @@ -11227,6 +11227,15 @@ package android.content.pm { field public static final int FLAG_MATCH_PINNED_BY_ANY_LAUNCHER = 1024; // 0x400 } + public final class ModuleInfo implements android.os.Parcelable { + method public int describeContents(); + method public java.lang.String getName(); + method public java.lang.String getPackageName(); + method public boolean isHidden(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.content.pm.ModuleInfo> CREATOR; + } + public class PackageInfo implements android.os.Parcelable { ctor public PackageInfo(); method public int describeContents(); @@ -11443,6 +11452,7 @@ package android.content.pm { method public abstract android.graphics.drawable.Drawable getDefaultActivityIcon(); method public abstract android.graphics.drawable.Drawable getDrawable(java.lang.String, int, android.content.pm.ApplicationInfo); method public abstract java.util.List<android.content.pm.ApplicationInfo> getInstalledApplications(int); + method public java.util.List<android.content.pm.ModuleInfo> getInstalledModules(int); method public abstract java.util.List<android.content.pm.PackageInfo> getInstalledPackages(int); method public abstract java.lang.String getInstallerPackageName(java.lang.String); method public abstract byte[] getInstantAppCookie(); @@ -11450,6 +11460,7 @@ package android.content.pm { method public abstract android.content.pm.InstrumentationInfo getInstrumentationInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException; method public abstract android.content.Intent getLaunchIntentForPackage(java.lang.String); method public abstract android.content.Intent getLeanbackLaunchIntentForPackage(java.lang.String); + method public android.content.pm.ModuleInfo getModuleInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException; method public abstract java.lang.String getNameForUid(int); method public android.content.pm.PackageInfo getPackageArchiveInfo(java.lang.String, int); method public abstract int[] getPackageGids(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException; @@ -13561,6 +13572,46 @@ package android.graphics { ctor public BitmapShader(android.graphics.Bitmap, android.graphics.Shader.TileMode, android.graphics.Shader.TileMode); } + public final class BlendMode extends java.lang.Enum { + method public static android.graphics.BlendMode valueOf(java.lang.String); + method public static final android.graphics.BlendMode[] values(); + enum_constant public static final android.graphics.BlendMode CLEAR; + enum_constant public static final android.graphics.BlendMode COLOR; + enum_constant public static final android.graphics.BlendMode COLOR_BURN; + enum_constant public static final android.graphics.BlendMode COLOR_DODGE; + enum_constant public static final android.graphics.BlendMode DARKEN; + enum_constant public static final android.graphics.BlendMode DIFFERENCE; + enum_constant public static final android.graphics.BlendMode DST; + enum_constant public static final android.graphics.BlendMode DST_ATOP; + enum_constant public static final android.graphics.BlendMode DST_IN; + enum_constant public static final android.graphics.BlendMode DST_OUT; + enum_constant public static final android.graphics.BlendMode DST_OVER; + enum_constant public static final android.graphics.BlendMode EXCLUSION; + enum_constant public static final android.graphics.BlendMode HARD_LIGHT; + enum_constant public static final android.graphics.BlendMode HUE; + enum_constant public static final android.graphics.BlendMode LIGHTEN; + enum_constant public static final android.graphics.BlendMode LUMINOSITY; + enum_constant public static final android.graphics.BlendMode MODULATE; + enum_constant public static final android.graphics.BlendMode MULTIPLY; + enum_constant public static final android.graphics.BlendMode OVERLAY; + enum_constant public static final android.graphics.BlendMode PLUS; + enum_constant public static final android.graphics.BlendMode SATURATION; + enum_constant public static final android.graphics.BlendMode SCREEN; + enum_constant public static final android.graphics.BlendMode SOFT_LIGHT; + enum_constant public static final android.graphics.BlendMode SRC; + enum_constant public static final android.graphics.BlendMode SRC_ATOP; + enum_constant public static final android.graphics.BlendMode SRC_IN; + enum_constant public static final android.graphics.BlendMode SRC_OUT; + enum_constant public static final android.graphics.BlendMode SRC_OVER; + enum_constant public static final android.graphics.BlendMode XOR; + } + + public final class BlendModeColorFilter extends android.graphics.ColorFilter { + ctor public BlendModeColorFilter(int, android.graphics.BlendMode); + method public int getColor(); + method public android.graphics.BlendMode getMode(); + } + public class BlurMaskFilter extends android.graphics.MaskFilter { ctor public BlurMaskFilter(float, android.graphics.BlurMaskFilter.Blur); } @@ -13623,7 +13674,8 @@ package android.graphics { method public void drawBitmapMesh(android.graphics.Bitmap, int, int, float[], int, int[], int, android.graphics.Paint); method public void drawCircle(float, float, float, android.graphics.Paint); method public void drawColor(int); - method public void drawColor(int, android.graphics.PorterDuff.Mode); + method public deprecated void drawColor(int, android.graphics.PorterDuff.Mode); + method public void drawColor(int, android.graphics.BlendMode); method public void drawDoubleRoundRect(android.graphics.RectF, float, float, android.graphics.RectF, float, float, android.graphics.Paint); method public void drawDoubleRoundRect(android.graphics.RectF, float[], android.graphics.RectF, float[], android.graphics.Paint); method public void drawLine(float, float, float, float, android.graphics.Paint); @@ -14245,6 +14297,7 @@ package android.graphics { method public float descent(); method public boolean equalsForTextMeasurement(android.graphics.Paint); method public int getAlpha(); + method public android.graphics.BlendMode getBlendMode(); method public int getColor(); method public android.graphics.ColorFilter getColorFilter(); method public boolean getFillPath(android.graphics.Path, android.graphics.Path); @@ -14299,7 +14352,7 @@ package android.graphics { method public float getUnderlinePosition(); method public float getUnderlineThickness(); method public float getWordSpacing(); - method public android.graphics.Xfermode getXfermode(); + method public deprecated android.graphics.Xfermode getXfermode(); method public boolean hasGlyph(java.lang.String); method public final boolean isAntiAlias(); method public final boolean isDither(); @@ -14319,6 +14372,7 @@ package android.graphics { method public void setARGB(int, int, int, int); method public void setAlpha(int); method public void setAntiAlias(boolean); + method public void setBlendMode(android.graphics.BlendMode); method public void setColor(int); method public android.graphics.ColorFilter setColorFilter(android.graphics.ColorFilter); method public void setDither(boolean); @@ -14352,7 +14406,7 @@ package android.graphics { method public android.graphics.Typeface setTypeface(android.graphics.Typeface); method public void setUnderlineText(boolean); method public void setWordSpacing(float); - method public android.graphics.Xfermode setXfermode(android.graphics.Xfermode); + method public deprecated android.graphics.Xfermode setXfermode(android.graphics.Xfermode); field public static final int ANTI_ALIAS_FLAG = 1; // 0x1 field public static final int CURSOR_AFTER = 0; // 0x0 field public static final int CURSOR_AT = 4; // 0x4 @@ -14634,7 +14688,7 @@ package android.graphics { enum_constant public static final android.graphics.PorterDuff.Mode XOR; } - public class PorterDuffColorFilter extends android.graphics.ColorFilter { + public deprecated class PorterDuffColorFilter extends android.graphics.ColorFilter { ctor public PorterDuffColorFilter(int, android.graphics.PorterDuff.Mode); } @@ -15190,7 +15244,7 @@ package android.graphics.drawable { method public final void setCallback(android.graphics.drawable.Drawable.Callback); method public void setChangingConfigurations(int); method public abstract void setColorFilter(android.graphics.ColorFilter); - method public void setColorFilter(int, android.graphics.PorterDuff.Mode); + method public deprecated void setColorFilter(int, android.graphics.PorterDuff.Mode); method public deprecated void setDither(boolean); method public void setFilterBitmap(boolean); method public void setHotspot(float, float); @@ -26266,9 +26320,12 @@ package android.media.audiofx { field public static final int SUCCESS = 0; // 0x0 } - public static class AudioEffect.Descriptor { + public static final class AudioEffect.Descriptor implements android.os.Parcelable { ctor public AudioEffect.Descriptor(); ctor public AudioEffect.Descriptor(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String); + method public int describeContents(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.media.audiofx.AudioEffect.Descriptor> CREATOR; field public java.lang.String connectMode; field public java.lang.String implementor; field public java.lang.String name; @@ -37479,25 +37536,37 @@ package android.provider { method public static android.net.Uri buildSearchDocumentsUri(java.lang.String, java.lang.String, java.lang.String); method public static android.net.Uri buildTreeDocumentUri(java.lang.String, java.lang.String); method public static android.net.Uri copyDocument(android.content.ContentInterface, android.net.Uri, android.net.Uri) throws java.io.FileNotFoundException; + method public static deprecated android.net.Uri copyDocument(android.content.ContentResolver, android.net.Uri, android.net.Uri) throws java.io.FileNotFoundException; method public static android.net.Uri createDocument(android.content.ContentInterface, android.net.Uri, java.lang.String, java.lang.String) throws java.io.FileNotFoundException; + method public static deprecated android.net.Uri createDocument(android.content.ContentResolver, android.net.Uri, java.lang.String, java.lang.String) throws java.io.FileNotFoundException; method public static android.content.IntentSender createWebLinkIntent(android.content.ContentInterface, android.net.Uri, android.os.Bundle) throws java.io.FileNotFoundException; + method public static deprecated android.content.IntentSender createWebLinkIntent(android.content.ContentResolver, android.net.Uri, android.os.Bundle) throws java.io.FileNotFoundException; method public static boolean deleteDocument(android.content.ContentInterface, android.net.Uri) throws java.io.FileNotFoundException; + method public static deprecated boolean deleteDocument(android.content.ContentResolver, android.net.Uri) throws java.io.FileNotFoundException; method public static void ejectRoot(android.content.ContentInterface, android.net.Uri); + method public static deprecated void ejectRoot(android.content.ContentResolver, android.net.Uri); method public static android.provider.DocumentsContract.Path findDocumentPath(android.content.ContentInterface, android.net.Uri) throws java.io.FileNotFoundException; + method public static deprecated android.provider.DocumentsContract.Path findDocumentPath(android.content.ContentResolver, android.net.Uri) throws java.io.FileNotFoundException; method public static java.lang.String getDocumentId(android.net.Uri); method public static android.os.Bundle getDocumentMetadata(android.content.ContentInterface, android.net.Uri) throws java.io.FileNotFoundException; + method public static deprecated android.os.Bundle getDocumentMetadata(android.content.ContentResolver, android.net.Uri) throws java.io.FileNotFoundException; method public static android.graphics.Bitmap getDocumentThumbnail(android.content.ContentInterface, android.net.Uri, android.graphics.Point, android.os.CancellationSignal) throws java.io.FileNotFoundException; + method public static deprecated android.graphics.Bitmap getDocumentThumbnail(android.content.ContentResolver, android.net.Uri, android.graphics.Point, android.os.CancellationSignal) throws java.io.FileNotFoundException; method public static java.lang.String getRootId(android.net.Uri); method public static java.lang.String getSearchDocumentsQuery(android.net.Uri); method public static java.lang.String getTreeDocumentId(android.net.Uri); method public static boolean isChildDocument(android.content.ContentInterface, android.net.Uri, android.net.Uri) throws java.io.FileNotFoundException; + method public static deprecated boolean isChildDocument(android.content.ContentResolver, android.net.Uri, android.net.Uri) throws java.io.FileNotFoundException; method public static boolean isDocumentUri(android.content.Context, android.net.Uri); method public static boolean isRootUri(android.content.Context, android.net.Uri); method public static boolean isRootsUri(android.content.Context, android.net.Uri); method public static boolean isTreeUri(android.net.Uri); method public static android.net.Uri moveDocument(android.content.ContentInterface, android.net.Uri, android.net.Uri, android.net.Uri) throws java.io.FileNotFoundException; + method public static deprecated android.net.Uri moveDocument(android.content.ContentResolver, android.net.Uri, android.net.Uri, android.net.Uri) throws java.io.FileNotFoundException; method public static boolean removeDocument(android.content.ContentInterface, android.net.Uri, android.net.Uri) throws java.io.FileNotFoundException; + method public static deprecated boolean removeDocument(android.content.ContentResolver, android.net.Uri, android.net.Uri) throws java.io.FileNotFoundException; method public static android.net.Uri renameDocument(android.content.ContentInterface, android.net.Uri, java.lang.String) throws java.io.FileNotFoundException; + method public static deprecated android.net.Uri renameDocument(android.content.ContentResolver, android.net.Uri, java.lang.String) throws java.io.FileNotFoundException; field public static final java.lang.String ACTION_DOCUMENT_SETTINGS = "android.provider.action.DOCUMENT_SETTINGS"; field public static final java.lang.String EXTRA_ERROR = "error"; field public static final java.lang.String EXTRA_EXCLUDE_SELF = "android.provider.extra.EXCLUDE_SELF"; @@ -43168,6 +43237,7 @@ package android.telecom { field public static final java.lang.String EXTRA_INCOMING_CALL_EXTRAS = "android.telecom.extra.INCOMING_CALL_EXTRAS"; field public static final java.lang.String EXTRA_INCOMING_VIDEO_STATE = "android.telecom.extra.INCOMING_VIDEO_STATE"; field public static final java.lang.String EXTRA_IS_DEFAULT_CALL_SCREENING_APP = "android.telecom.extra.IS_DEFAULT_CALL_SCREENING_APP"; + field public static final java.lang.String EXTRA_IS_ENABLED = "android.telecom.extra.IS_ENABLED"; field public static final java.lang.String EXTRA_NOTIFICATION_COUNT = "android.telecom.extra.NOTIFICATION_COUNT"; field public static final java.lang.String EXTRA_NOTIFICATION_PHONE_NUMBER = "android.telecom.extra.NOTIFICATION_PHONE_NUMBER"; field public static final java.lang.String EXTRA_OUTGOING_CALL_EXTRAS = "android.telecom.extra.OUTGOING_CALL_EXTRAS"; @@ -43175,14 +43245,13 @@ package android.telecom { field public static final java.lang.String EXTRA_START_CALL_WITH_RTT = "android.telecom.extra.START_CALL_WITH_RTT"; field public static final java.lang.String EXTRA_START_CALL_WITH_SPEAKERPHONE = "android.telecom.extra.START_CALL_WITH_SPEAKERPHONE"; field public static final java.lang.String EXTRA_START_CALL_WITH_VIDEO_STATE = "android.telecom.extra.START_CALL_WITH_VIDEO_STATE"; - field public static final java.lang.String EXTRA_IS_ENABLED = "android.telecom.extra.IS_ENABLED"; field public static final java.lang.String GATEWAY_ORIGINAL_ADDRESS = "android.telecom.extra.GATEWAY_ORIGINAL_ADDRESS"; field public static final java.lang.String GATEWAY_PROVIDER_PACKAGE = "android.telecom.extra.GATEWAY_PROVIDER_PACKAGE"; field public static final java.lang.String METADATA_INCLUDE_EXTERNAL_CALLS = "android.telecom.INCLUDE_EXTERNAL_CALLS"; field public static final java.lang.String METADATA_INCLUDE_SELF_MANAGED_CALLS = "android.telecom.INCLUDE_SELF_MANAGED_CALLS"; + field public static final java.lang.String METADATA_IN_CALL_SERVICE_CAR_MODE_UI = "android.telecom.IN_CALL_SERVICE_CAR_MODE_UI"; field public static final java.lang.String METADATA_IN_CALL_SERVICE_RINGING = "android.telecom.IN_CALL_SERVICE_RINGING"; field public static final java.lang.String METADATA_IN_CALL_SERVICE_UI = "android.telecom.IN_CALL_SERVICE_UI"; - field public static final java.lang.String METADATA_IN_CALL_SERVICE_CAR_MODE_UI = "android.telecom.IN_CALL_SERVICE_CAR_MODE_UI"; field public static final int PRESENTATION_ALLOWED = 1; // 0x1 field public static final int PRESENTATION_PAYPHONE = 4; // 0x4 field public static final int PRESENTATION_RESTRICTED = 2; // 0x2 diff --git a/api/removed.txt b/api/removed.txt index e3e8b6397e6f..f7106d2207ec 100644 --- a/api/removed.txt +++ b/api/removed.txt @@ -508,21 +508,6 @@ package android.provider { field public static final deprecated java.lang.String TIMESTAMP = "timestamp"; } - public final class DocumentsContract { - method public static android.net.Uri copyDocument(android.content.ContentResolver, android.net.Uri, android.net.Uri) throws java.io.FileNotFoundException; - method public static android.net.Uri createDocument(android.content.ContentResolver, android.net.Uri, java.lang.String, java.lang.String) throws java.io.FileNotFoundException; - method public static android.content.IntentSender createWebLinkIntent(android.content.ContentResolver, android.net.Uri, android.os.Bundle) throws java.io.FileNotFoundException; - method public static boolean deleteDocument(android.content.ContentResolver, android.net.Uri) throws java.io.FileNotFoundException; - method public static void ejectRoot(android.content.ContentResolver, android.net.Uri); - method public static android.provider.DocumentsContract.Path findDocumentPath(android.content.ContentResolver, android.net.Uri) throws java.io.FileNotFoundException; - method public static android.os.Bundle getDocumentMetadata(android.content.ContentResolver, android.net.Uri) throws java.io.FileNotFoundException; - method public static android.graphics.Bitmap getDocumentThumbnail(android.content.ContentResolver, android.net.Uri, android.graphics.Point, android.os.CancellationSignal) throws java.io.FileNotFoundException; - method public static boolean isChildDocument(android.content.ContentResolver, android.net.Uri, android.net.Uri) throws java.io.FileNotFoundException; - method public static android.net.Uri moveDocument(android.content.ContentResolver, android.net.Uri, android.net.Uri, android.net.Uri) throws java.io.FileNotFoundException; - method public static boolean removeDocument(android.content.ContentResolver, android.net.Uri, android.net.Uri) throws java.io.FileNotFoundException; - method public static android.net.Uri renameDocument(android.content.ContentResolver, android.net.Uri, java.lang.String) throws java.io.FileNotFoundException; - } - public static final class Settings.Global extends android.provider.Settings.NameValueTable { field public static final deprecated java.lang.String CONTACT_METADATA_SYNC = "contact_metadata_sync"; } diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index f58caff76d27..410bd198a227 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -2394,16 +2394,23 @@ message KernelWakelock { } /** - * Pulls low power state information. This includes platform and subsystem sleep state information, - * PowerStatePlatformSleepState, PowerStateVoter or PowerStateSubsystemSleepState as defined in + * Pulls low power state information. If power.stats HAL is not available, this + * includes platform and subsystem sleep state information, + * PowerStatePlatformSleepState, PowerStateVoter or PowerStateSubsystemSleepState + * as defined in: * hardware/interfaces/power/1.0/types.hal * hardware/interfaces/power/1.1/types.hal + * If power.stats HAL is available, this includes PowerEntityStateResidencyResult + * as defined in: + * hardware/interfaces/power/stats/1.0/types.hal */ message SubsystemSleepState { // Subsystem name optional string subsystem_name = 1; // For PlatformLowPowerStats (hal 1.0), this is the voter name, which could be empty. // For SubsystemLowPowerStats (hal 1.1), this is the sleep state name. + // For PowerEntityStateResidencyResult (hal power/stats/1.0) this is the + // powerEntityStateName from the corresponding PowerEntityStateInfo. optional string subname = 2; // The number of times it entered, or voted for entering the sleep state optional uint64 count = 3; @@ -2540,15 +2547,19 @@ message BluetoothActivityInfo { /* * Logs the memory stats for a process. + * + * Pulled from StatsCompanionService for all managed processes (from ActivityManagerService). */ message ProcessMemoryState { // The uid if available. -1 means not available. optional int32 uid = 1 [(is_uid) = true]; // The process name. + // Usually package name, "system" for system server. + // Provided by ActivityManagerService. optional string process_name = 2; - // oom adj score. + // Current OOM score adjustment. Value read from ProcessRecord. optional int32 oom_adj_score = 3; // # of page-faults @@ -2558,12 +2569,18 @@ message ProcessMemoryState { optional int64 page_major_fault = 5; // RSS + // Value is read from /proc/PID/stat, field 24. Or from memory.stat, field + // total_rss if per-app memory cgroups are enabled. optional int64 rss_in_bytes = 6; // CACHE + // Value is read from memory.stat, field total_cache if per-app memory + // cgroups are enabled. Otherwise, 0. optional int64 cache_in_bytes = 7; // SWAP + // Value is read from memory.stat, field total_swap if per-app memory + // cgroups are enabled. Otherwise, 0. optional int64 swap_in_bytes = 8; // Deprecated: use ProcessMemoryHighWaterMark atom instead. Always 0. @@ -2576,12 +2593,15 @@ message ProcessMemoryState { /* * Logs the memory stats for a native process (from procfs). + * + * Pulled from StatsCompanionService for selected native processes. */ message NativeProcessMemoryState { // The uid if available. -1 means not available. optional int32 uid = 1 [(is_uid) = true]; // The process name. + // Value read from /proc/PID/cmdline. optional string process_name = 2; // # of page-faults @@ -2591,6 +2611,7 @@ message NativeProcessMemoryState { optional int64 page_major_fault = 4; // RSS + // Value read from /proc/PID/stat, field 24. optional int64 rss_in_bytes = 5; // Deprecated: use ProcessMemoryHighWaterMark atom instead. Always 0. @@ -2603,13 +2624,17 @@ message NativeProcessMemoryState { /* * Logs the memory high-water mark for a process. - * Recorded in ActivityManagerService. + * + * Pulled from StatsCompanionService for all managed processes (from ActivityManagerServie) + * and for selected native processes. */ message ProcessMemoryHighWaterMark { // The uid if available. -1 means not available. optional int32 uid = 1 [(is_uid) = true]; - // The process name. Provided by ActivityManagerService or read from /proc/PID/cmdline. + // The process name. + // Usually package name or process cmdline. + // Provided by ActivityManagerService or read from /proc/PID/cmdline. optional string process_name = 2; // RSS high-water mark. Peak RSS usage of the process. Read from the VmHWM field in @@ -3586,4 +3611,4 @@ message DocsUIUserActionReported { */ message DocsUIInvalidScopedAccessRequestReported { optional android.stats.docsui.InvalidScopedAccess type = 1; -}
\ No newline at end of file +} diff --git a/cmds/statsd/src/external/SubsystemSleepStatePuller.cpp b/cmds/statsd/src/external/SubsystemSleepStatePuller.cpp index 4501b64ad47e..c8c392016e52 100644 --- a/cmds/statsd/src/external/SubsystemSleepStatePuller.cpp +++ b/cmds/statsd/src/external/SubsystemSleepStatePuller.cpp @@ -19,6 +19,8 @@ #include <android/hardware/power/1.0/IPower.h> #include <android/hardware/power/1.1/IPower.h> +#include <android/hardware/power/stats/1.0/IPowerStats.h> + #include <fcntl.h> #include <hardware/power.h> #include <hardware_legacy/power.h> @@ -42,9 +44,12 @@ using android::hardware::hidl_vec; using android::hardware::power::V1_0::IPower; using android::hardware::power::V1_0::PowerStatePlatformSleepState; using android::hardware::power::V1_0::PowerStateVoter; -using android::hardware::power::V1_0::Status; using android::hardware::power::V1_1::PowerStateSubsystem; using android::hardware::power::V1_1::PowerStateSubsystemSleepState; +using android::hardware::power::stats::V1_0::PowerEntityInfo; +using android::hardware::power::stats::V1_0::PowerEntityStateResidencyResult; +using android::hardware::power::stats::V1_0::PowerEntityStateSpace; + using android::hardware::Return; using android::hardware::Void; @@ -55,44 +60,209 @@ namespace android { namespace os { namespace statsd { +std::function<bool(vector<shared_ptr<LogEvent>>* data)> gPuller = {}; + sp<android::hardware::power::V1_0::IPower> gPowerHalV1_0 = nullptr; sp<android::hardware::power::V1_1::IPower> gPowerHalV1_1 = nullptr; +sp<android::hardware::power::stats::V1_0::IPowerStats> gPowerStatsHalV1_0 = nullptr; + +std::unordered_map<uint32_t, std::string> gEntityNames = {}; +std::unordered_map<uint32_t, std::unordered_map<uint32_t, std::string>> gStateNames = {}; + std::mutex gPowerHalMutex; -bool gPowerHalExists = true; -bool getPowerHal() { - if (gPowerHalExists && gPowerHalV1_0 == nullptr) { - gPowerHalV1_0 = android::hardware::power::V1_0::IPower::getService(); - if (gPowerHalV1_0 != nullptr) { - gPowerHalV1_1 = android::hardware::power::V1_1::IPower::castFrom(gPowerHalV1_0); - ALOGI("Loaded power HAL service"); - } else { - ALOGW("Couldn't load power HAL service"); - gPowerHalExists = false; +// The caller must be holding gPowerHalMutex. +void deinitPowerStatsLocked() { + gPowerHalV1_0 = nullptr; + gPowerHalV1_1 = nullptr; + gPowerStatsHalV1_0 = nullptr; +} + +struct PowerHalDeathRecipient : virtual public hardware::hidl_death_recipient { + virtual void serviceDied(uint64_t cookie, + const wp<android::hidl::base::V1_0::IBase>& who) override { + // The HAL just died. Reset all handles to HAL services. + std::lock_guard<std::mutex> lock(gPowerHalMutex); + deinitPowerStatsLocked(); + } +}; + +sp<PowerHalDeathRecipient> gDeathRecipient = new PowerHalDeathRecipient(); + +SubsystemSleepStatePuller::SubsystemSleepStatePuller() : + StatsPuller(android::util::SUBSYSTEM_SLEEP_STATE) { +} + +// The caller must be holding gPowerHalMutex. +bool checkResultLocked(const Return<void> &ret, const char* function) { + if (!ret.isOk()) { + ALOGE("%s failed: requested HAL service not available. Description: %s", + function, ret.description().c_str()); + if (ret.isDeadObject()) { + deinitPowerStatsLocked(); + } + return false; + } + return true; +} + +// The caller must be holding gPowerHalMutex. +// gPowerStatsHalV1_0 must not be null +bool initializePowerStats() { + using android::hardware::power::stats::V1_0::Status; + + // Clear out previous content if we are re-initializing + gEntityNames.clear(); + gStateNames.clear(); + + Return<void> ret; + ret = gPowerStatsHalV1_0->getPowerEntityInfo([](auto infos, auto status) { + if (status != Status::SUCCESS) { + ALOGE("Error getting power entity info"); + return; + } + + // construct lookup table of powerEntityId to power entity name + for (auto info : infos) { + gEntityNames.emplace(info.powerEntityId, info.powerEntityName); } + }); + if (!checkResultLocked(ret, __func__)) { + return false; } - return gPowerHalV1_0 != nullptr; + + ret = gPowerStatsHalV1_0->getPowerEntityStateInfo({}, [](auto stateSpaces, auto status) { + if (status != Status::SUCCESS) { + ALOGE("Error getting state info"); + return; + } + + // construct lookup table of powerEntityId, powerEntityStateId to power entity state name + for (auto stateSpace : stateSpaces) { + std::unordered_map<uint32_t, std::string> stateNames = {}; + for (auto state : stateSpace.states) { + stateNames.emplace(state.powerEntityStateId, + state.powerEntityStateName); + } + gStateNames.emplace(stateSpace.powerEntityId, stateNames); + } + }); + if (!checkResultLocked(ret, __func__)) { + return false; + } + + return (!gEntityNames.empty()) && (!gStateNames.empty()); } -SubsystemSleepStatePuller::SubsystemSleepStatePuller() : StatsPuller(android::util::SUBSYSTEM_SLEEP_STATE) { +// The caller must be holding gPowerHalMutex. +bool getPowerStatsHalLocked() { + if(gPowerStatsHalV1_0 == nullptr) { + gPowerStatsHalV1_0 = android::hardware::power::stats::V1_0::IPowerStats::getService(); + if (gPowerStatsHalV1_0 == nullptr) { + ALOGE("Unable to get power.stats HAL service."); + return false; + } + + // Link death recipient to power.stats service handle + hardware::Return<bool> linked = gPowerStatsHalV1_0->linkToDeath(gDeathRecipient, 0); + if (!linked.isOk()) { + ALOGE("Transaction error in linking to power.stats HAL death: %s", + linked.description().c_str()); + deinitPowerStatsLocked(); + return false; + } else if (!linked) { + ALOGW("Unable to link to power.stats HAL death notifications"); + // We should still continue even though linking failed + } + return initializePowerStats(); + } + return true; } -bool SubsystemSleepStatePuller::PullInternal(vector<shared_ptr<LogEvent>>* data) { - std::lock_guard<std::mutex> lock(gPowerHalMutex); +// The caller must be holding gPowerHalMutex. +bool getIPowerStatsDataLocked(vector<shared_ptr<LogEvent>>* data) { + using android::hardware::power::stats::V1_0::Status; - if (!getPowerHal()) { - ALOGE("Power Hal not loaded"); + if(!getPowerStatsHalLocked()) { return false; } int64_t wallClockTimestampNs = getWallClockNs(); int64_t elapsedTimestampNs = getElapsedRealtimeNs(); - data->clear(); + // Get power entity state residency data + bool success = false; + Return<void> ret = gPowerStatsHalV1_0->getPowerEntityStateResidencyData({}, + [&data, &success, wallClockTimestampNs, elapsedTimestampNs] + (auto results, auto status) { + if (status == Status::NOT_SUPPORTED) { + ALOGW("getPowerEntityStateResidencyData is not supported"); + success = false; + return; + } + + for(auto result : results) { + for(auto stateResidency : result.stateResidencyData) { + auto statePtr = make_shared<LogEvent>( + android::util::SUBSYSTEM_SLEEP_STATE, + wallClockTimestampNs, elapsedTimestampNs); + statePtr->write(gEntityNames.at(result.powerEntityId)); + statePtr->write(gStateNames.at(result.powerEntityId) + .at(stateResidency.powerEntityStateId)); + statePtr->write(stateResidency.totalStateEntryCount); + statePtr->write(stateResidency.totalTimeInStateMs); + statePtr->init(); + data->emplace_back(statePtr); + } + } + success = true; + }); + // Intentionally not returning early here. + // bool success determines if this succeeded or not. + checkResultLocked(ret, __func__); - Return<void> ret; + return success; +} + +// The caller must be holding gPowerHalMutex. +bool getPowerHalLocked() { + if(gPowerHalV1_0 == nullptr) { + gPowerHalV1_0 = android::hardware::power::V1_0::IPower::getService(); + if(gPowerHalV1_0 == nullptr) { + ALOGE("Unable to get power HAL service."); + return false; + } + gPowerHalV1_1 = android::hardware::power::V1_1::IPower::castFrom(gPowerHalV1_0); + + // Link death recipient to power service handle + hardware::Return<bool> linked = gPowerHalV1_0->linkToDeath(gDeathRecipient, 0); + if (!linked.isOk()) { + ALOGE("Transaction error in linking to power HAL death: %s", + linked.description().c_str()); + gPowerHalV1_0 = nullptr; + return false; + } else if (!linked) { + ALOGW("Unable to link to power. death notifications"); + // We should still continue even though linking failed + } + } + return true; +} + +// The caller must be holding gPowerHalMutex. +bool getIPowerDataLocked(vector<shared_ptr<LogEvent>>* data) { + using android::hardware::power::V1_0::Status; + + if(!getPowerHalLocked()) { + return false; + } + + int64_t wallClockTimestampNs = getWallClockNs(); + int64_t elapsedTimestampNs = getElapsedRealtimeNs(); + Return<void> ret; ret = gPowerHalV1_0->getPlatformLowPowerStats( - [&data, wallClockTimestampNs, elapsedTimestampNs](hidl_vec<PowerStatePlatformSleepState> states, Status status) { + [&data, wallClockTimestampNs, elapsedTimestampNs] + (hidl_vec<PowerStatePlatformSleepState> states, Status status) { if (status != Status::SUCCESS) return; for (size_t i = 0; i < states.size(); i++) { @@ -128,9 +298,7 @@ bool SubsystemSleepStatePuller::PullInternal(vector<shared_ptr<LogEvent>>* data) } } }); - if (!ret.isOk()) { - ALOGE("getLowPowerStats() failed: power HAL service not available"); - gPowerHalV1_0 = nullptr; + if (!checkResultLocked(ret, __func__)) { return false; } @@ -139,35 +307,68 @@ bool SubsystemSleepStatePuller::PullInternal(vector<shared_ptr<LogEvent>>* data) android::hardware::power::V1_1::IPower::castFrom(gPowerHalV1_0); if (gPowerHal_1_1 != nullptr) { ret = gPowerHal_1_1->getSubsystemLowPowerStats( - [&data, wallClockTimestampNs, elapsedTimestampNs](hidl_vec<PowerStateSubsystem> subsystems, Status status) { - if (status != Status::SUCCESS) return; - - if (subsystems.size() > 0) { - for (size_t i = 0; i < subsystems.size(); i++) { - const PowerStateSubsystem& subsystem = subsystems[i]; - for (size_t j = 0; j < subsystem.states.size(); j++) { - const PowerStateSubsystemSleepState& state = - subsystem.states[j]; - auto subsystemStatePtr = make_shared<LogEvent>( - android::util::SUBSYSTEM_SLEEP_STATE, - wallClockTimestampNs, elapsedTimestampNs); - subsystemStatePtr->write(subsystem.name); - subsystemStatePtr->write(state.name); - subsystemStatePtr->write(state.totalTransitions); - subsystemStatePtr->write(state.residencyInMsecSinceBoot); - subsystemStatePtr->init(); - data->push_back(subsystemStatePtr); - VLOG("subsystemstate: %s, %s, %lld, %lld, %lld", - subsystem.name.c_str(), state.name.c_str(), - (long long)state.residencyInMsecSinceBoot, - (long long)state.totalTransitions, - (long long)state.lastEntryTimestampMs); - } - } + [&data, wallClockTimestampNs, elapsedTimestampNs] + (hidl_vec<PowerStateSubsystem> subsystems, Status status) { + if (status != Status::SUCCESS) return; + + if (subsystems.size() > 0) { + for (size_t i = 0; i < subsystems.size(); i++) { + const PowerStateSubsystem& subsystem = subsystems[i]; + for (size_t j = 0; j < subsystem.states.size(); j++) { + const PowerStateSubsystemSleepState& state = + subsystem.states[j]; + auto subsystemStatePtr = make_shared<LogEvent>( + android::util::SUBSYSTEM_SLEEP_STATE, + wallClockTimestampNs, elapsedTimestampNs); + subsystemStatePtr->write(subsystem.name); + subsystemStatePtr->write(state.name); + subsystemStatePtr->write(state.totalTransitions); + subsystemStatePtr->write(state.residencyInMsecSinceBoot); + subsystemStatePtr->init(); + data->push_back(subsystemStatePtr); + VLOG("subsystemstate: %s, %s, %lld, %lld, %lld", + subsystem.name.c_str(), state.name.c_str(), + (long long)state.residencyInMsecSinceBoot, + (long long)state.totalTransitions, + (long long)state.lastEntryTimestampMs); } - }); + } + } + }); } - return true; + return true; +} + +// The caller must be holding gPowerHalMutex. +std::function<bool(vector<shared_ptr<LogEvent>>* data)> getPullerLocked() { + std::function<bool(vector<shared_ptr<LogEvent>>* data)> ret = {}; + + // First see if power.stats HAL is available. Fall back to power HAL if + // power.stats HAL is unavailable. + if(android::hardware::power::stats::V1_0::IPowerStats::getService() != nullptr) { + ALOGI("Using power.stats HAL"); + ret = getIPowerStatsDataLocked; + } else if(android::hardware::power::V1_0::IPower::getService() != nullptr) { + ALOGI("Using power HAL"); + ret = getIPowerDataLocked; + } + + return ret; +} + +bool SubsystemSleepStatePuller::PullInternal(vector<shared_ptr<LogEvent>>* data) { + std::lock_guard<std::mutex> lock(gPowerHalMutex); + + if(!gPuller) { + gPuller = getPullerLocked(); + } + + if(gPuller) { + return gPuller(data); + } + + ALOGE("Unable to load Power Hal or power.stats HAL"); + return false; } } // namespace statsd diff --git a/cmds/statsd/tools/localtools/src/com/android/statsd/shelltools/Utils.java b/cmds/statsd/tools/localtools/src/com/android/statsd/shelltools/Utils.java index 597377e34ac3..8464b8df03d0 100644 --- a/cmds/statsd/tools/localtools/src/com/android/statsd/shelltools/Utils.java +++ b/cmds/statsd/tools/localtools/src/com/android/statsd/shelltools/Utils.java @@ -70,9 +70,16 @@ public class Utils { /** * Dumps the report from the device and converts it to a ConfigMetricsReportList. * Erases the data if clearData is true. + * @param configId id of the config + * @param clearData whether to erase the report data from statsd after getting the report. + * @param useShellUid Pulls data for the {@link SHELL_UID} instead of the caller's uid. + * @param logger Logger to log error messages + * @return + * @throws IOException + * @throws InterruptedException */ public static ConfigMetricsReportList getReportList(long configId, boolean clearData, - Logger logger) throws IOException, InterruptedException { + boolean useShellUid, Logger logger) throws IOException, InterruptedException { try { File outputFile = File.createTempFile("statsdret", ".bin"); outputFile.deleteOnExit(); @@ -82,7 +89,7 @@ public class Utils { "adb", "shell", CMD_DUMP_REPORT, - SHELL_UID, + useShellUid ? SHELL_UID : "", String.valueOf(configId), clearData ? "" : "--keep_data", "--include_current_bucket", @@ -93,8 +100,8 @@ public class Utils { } catch (com.google.protobuf.InvalidProtocolBufferException e) { logger.severe("Failed to fetch and parse the statsd output report. " + "Perhaps there is not a valid statsd config for the requested " - + "uid=" + SHELL_UID - + ", configId=" + configId + + (useShellUid ? ("uid=" + SHELL_UID + ", ") : "") + + "configId=" + configId + "."); throw (e); } diff --git a/cmds/statsd/tools/localtools/src/com/android/statsd/shelltools/localdrive/LocalDrive.java b/cmds/statsd/tools/localtools/src/com/android/statsd/shelltools/localdrive/LocalDrive.java index 08074ede9d31..67fb906c2570 100644 --- a/cmds/statsd/tools/localtools/src/com/android/statsd/shelltools/localdrive/LocalDrive.java +++ b/cmds/statsd/tools/localtools/src/com/android/statsd/shelltools/localdrive/LocalDrive.java @@ -165,7 +165,7 @@ public class LocalDrive { try { Utils.runCommand(null, sLogger, "adb", "shell", Utils.CMD_REMOVE_CONFIG, Utils.SHELL_UID, String.valueOf(configId)); - Utils.getReportList(configId, true /* clearData */, sLogger); + Utils.getReportList(configId, true /* clearData */, true /* SHELL_UID */, sLogger); } catch (InterruptedException | IOException e) { sLogger.severe("Failed to remove config: " + e.getMessage()); return false; @@ -234,7 +234,7 @@ public class LocalDrive { // Even if the args request no modifications, we still parse it to make sure it's valid. ConfigMetricsReportList reportList; try { - reportList = Utils.getReportList(configId, clearData, sLogger); + reportList = Utils.getReportList(configId, clearData, true /* SHELL_UID */, sLogger); } catch (IOException | InterruptedException e) { sLogger.severe("Failed to get report list: " + e.getMessage()); return false; @@ -278,7 +278,7 @@ public class LocalDrive { sLogger.fine(String.format("cmdClear with %d", configId)); try { - Utils.getReportList(configId, true /* clearData */, sLogger); + Utils.getReportList(configId, true /* clearData */, true /* SHELL_UID */, sLogger); } catch (IOException | InterruptedException e) { sLogger.severe("Failed to get report list: " + e.getMessage()); return false; diff --git a/cmds/statsd/tools/localtools/src/com/android/statsd/shelltools/testdrive/TestDrive.java b/cmds/statsd/tools/localtools/src/com/android/statsd/shelltools/testdrive/TestDrive.java index f7bd44aeab62..e3fe928a1309 100644 --- a/cmds/statsd/tools/localtools/src/com/android/statsd/shelltools/testdrive/TestDrive.java +++ b/cmds/statsd/tools/localtools/src/com/android/statsd/shelltools/testdrive/TestDrive.java @@ -165,7 +165,7 @@ public class TestDrive { } private void dumpMetrics() throws Exception { - ConfigMetricsReportList reportList = Utils.getReportList(CONFIG_ID, true, logger); + ConfigMetricsReportList reportList = Utils.getReportList(CONFIG_ID, true, false, logger); // We may get multiple reports. Take the last one. ConfigMetricsReport report = reportList.getReports(reportList.getReportsCount() - 1); // Really should be only one metric. diff --git a/config/hiddenapi-greylist.txt b/config/hiddenapi-greylist.txt index bacb991012fd..bf1443867aff 100644 --- a/config/hiddenapi-greylist.txt +++ b/config/hiddenapi-greylist.txt @@ -2730,8 +2730,6 @@ Lcom/android/internal/telephony/CommandsInterface;->acknowledgeLastIncomingGsmSm Lcom/android/internal/telephony/CommandsInterface;->changeBarringPassword(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Landroid/os/Message;)V Lcom/android/internal/telephony/CommandsInterface;->deleteSmsOnRuim(ILandroid/os/Message;)V Lcom/android/internal/telephony/CommandsInterface;->deleteSmsOnSim(ILandroid/os/Message;)V -Lcom/android/internal/telephony/CommandsInterface;->dial(Ljava/lang/String;ILandroid/os/Message;)V -Lcom/android/internal/telephony/CommandsInterface;->dial(Ljava/lang/String;ILcom/android/internal/telephony/UUSInfo;Landroid/os/Message;)V Lcom/android/internal/telephony/CommandsInterface;->exitEmergencyCallbackMode(Landroid/os/Message;)V Lcom/android/internal/telephony/CommandsInterface;->getBasebandVersion(Landroid/os/Message;)V Lcom/android/internal/telephony/CommandsInterface;->getCdmaBroadcastConfig(Landroid/os/Message;)V @@ -2861,7 +2859,6 @@ Lcom/android/internal/telephony/dataconnection/DataConnection;->mActivatingState Lcom/android/internal/telephony/dataconnection/DataConnection;->mActiveState:Lcom/android/internal/telephony/dataconnection/DataConnection$DcActiveState; Lcom/android/internal/telephony/dataconnection/DataConnection;->mConnectionParams:Lcom/android/internal/telephony/dataconnection/DataConnection$ConnectionParams; Lcom/android/internal/telephony/dataconnection/DataConnection;->mDataRegState:I -Lcom/android/internal/telephony/dataconnection/DataConnection;->mDcFailCause:Lcom/android/internal/telephony/dataconnection/DcFailCause; Lcom/android/internal/telephony/dataconnection/DataConnection;->mDct:Lcom/android/internal/telephony/dataconnection/DcTracker; Lcom/android/internal/telephony/dataconnection/DataConnection;->mDisconnectingErrorCreatingConnection:Lcom/android/internal/telephony/dataconnection/DataConnection$DcDisconnectionErrorCreatingConnection; Lcom/android/internal/telephony/dataconnection/DataConnection;->mDisconnectingState:Lcom/android/internal/telephony/dataconnection/DataConnection$DcDisconnectingState; @@ -2872,10 +2869,8 @@ Lcom/android/internal/telephony/dataconnection/DataConnection;->mLinkProperties: Lcom/android/internal/telephony/dataconnection/DataConnection;->mNetworkInfo:Landroid/net/NetworkInfo; Lcom/android/internal/telephony/dataconnection/DataConnection;->mPhone:Lcom/android/internal/telephony/Phone; Lcom/android/internal/telephony/dataconnection/DataConnection;->mRilRat:I -Lcom/android/internal/telephony/dataconnection/DataConnection;->notifyAllDisconnectCompleted(Lcom/android/internal/telephony/dataconnection/DcFailCause;)V Lcom/android/internal/telephony/dataconnection/DataConnection;->notifyAllOfConnected(Ljava/lang/String;)V Lcom/android/internal/telephony/dataconnection/DataConnection;->notifyAllOfDisconnectDcRetrying(Ljava/lang/String;)V -Lcom/android/internal/telephony/dataconnection/DataConnection;->notifyConnectCompleted(Lcom/android/internal/telephony/dataconnection/DataConnection$ConnectionParams;Lcom/android/internal/telephony/dataconnection/DcFailCause;Z)V Lcom/android/internal/telephony/dataconnection/DataConnection;->notifyDisconnectCompleted(Lcom/android/internal/telephony/dataconnection/DataConnection$DisconnectParams;Z)V Lcom/android/internal/telephony/dataconnection/DataConnection;->onConnect(Lcom/android/internal/telephony/dataconnection/DataConnection$ConnectionParams;)V Lcom/android/internal/telephony/dataconnection/DataConnection;->tearDownData(Ljava/lang/Object;)V @@ -2884,22 +2879,6 @@ Lcom/android/internal/telephony/dataconnection/DcController;->lr(Ljava/lang/Stri Lcom/android/internal/telephony/dataconnection/DcController;->mDcListActiveByCid:Ljava/util/HashMap; Lcom/android/internal/telephony/dataconnection/DcController;->mDct:Lcom/android/internal/telephony/dataconnection/DcTracker; Lcom/android/internal/telephony/dataconnection/DcController;->mDcTesterDeactivateAll:Lcom/android/internal/telephony/dataconnection/DcTesterDeactivateAll; -Lcom/android/internal/telephony/dataconnection/DcFailCause;->ACTIVATION_REJECT_GGSN:Lcom/android/internal/telephony/dataconnection/DcFailCause; -Lcom/android/internal/telephony/dataconnection/DcFailCause;->ACTIVATION_REJECT_UNSPECIFIED:Lcom/android/internal/telephony/dataconnection/DcFailCause; -Lcom/android/internal/telephony/dataconnection/DcFailCause;->APN_TYPE_CONFLICT:Lcom/android/internal/telephony/dataconnection/DcFailCause; -Lcom/android/internal/telephony/dataconnection/DcFailCause;->INSUFFICIENT_RESOURCES:Lcom/android/internal/telephony/dataconnection/DcFailCause; -Lcom/android/internal/telephony/dataconnection/DcFailCause;->MISSING_UNKNOWN_APN:Lcom/android/internal/telephony/dataconnection/DcFailCause; -Lcom/android/internal/telephony/dataconnection/DcFailCause;->NSAPI_IN_USE:Lcom/android/internal/telephony/dataconnection/DcFailCause; -Lcom/android/internal/telephony/dataconnection/DcFailCause;->ONLY_IPV4_ALLOWED:Lcom/android/internal/telephony/dataconnection/DcFailCause; -Lcom/android/internal/telephony/dataconnection/DcFailCause;->ONLY_IPV6_ALLOWED:Lcom/android/internal/telephony/dataconnection/DcFailCause; -Lcom/android/internal/telephony/dataconnection/DcFailCause;->ONLY_SINGLE_BEARER_ALLOWED:Lcom/android/internal/telephony/dataconnection/DcFailCause; -Lcom/android/internal/telephony/dataconnection/DcFailCause;->OPERATOR_BARRED:Lcom/android/internal/telephony/dataconnection/DcFailCause; -Lcom/android/internal/telephony/dataconnection/DcFailCause;->PROTOCOL_ERRORS:Lcom/android/internal/telephony/dataconnection/DcFailCause; -Lcom/android/internal/telephony/dataconnection/DcFailCause;->SERVICE_OPTION_NOT_SUBSCRIBED:Lcom/android/internal/telephony/dataconnection/DcFailCause; -Lcom/android/internal/telephony/dataconnection/DcFailCause;->SERVICE_OPTION_NOT_SUPPORTED:Lcom/android/internal/telephony/dataconnection/DcFailCause; -Lcom/android/internal/telephony/dataconnection/DcFailCause;->SERVICE_OPTION_OUT_OF_ORDER:Lcom/android/internal/telephony/dataconnection/DcFailCause; -Lcom/android/internal/telephony/dataconnection/DcFailCause;->UNKNOWN_PDP_ADDRESS_TYPE:Lcom/android/internal/telephony/dataconnection/DcFailCause; -Lcom/android/internal/telephony/dataconnection/DcFailCause;->USER_AUTHENTICATION:Lcom/android/internal/telephony/dataconnection/DcFailCause; Lcom/android/internal/telephony/dataconnection/DcTracker$RecoveryAction;->isAggressiveRecovery(I)Z Lcom/android/internal/telephony/dataconnection/DcTracker;->cancelReconnectAlarm(Lcom/android/internal/telephony/dataconnection/ApnContext;)V Lcom/android/internal/telephony/dataconnection/DcTracker;->cleanUpAllConnections(Ljava/lang/String;)V @@ -3763,8 +3742,6 @@ Lcom/android/internal/telephony/TelephonyCapabilities;->supportsAdn(I)Z Lcom/android/internal/telephony/TelephonyProperties;->PROPERTY_ICC_OPERATOR_NUMERIC:Ljava/lang/String; Lcom/android/internal/telephony/test/InterpreterEx;-><init>(Ljava/lang/String;)V Lcom/android/internal/telephony/test/SimulatedCommands;->acceptCall(Landroid/os/Message;)V -Lcom/android/internal/telephony/test/SimulatedCommands;->dial(Ljava/lang/String;ILandroid/os/Message;)V -Lcom/android/internal/telephony/test/SimulatedCommands;->dial(Ljava/lang/String;ILcom/android/internal/telephony/UUSInfo;Landroid/os/Message;)V Lcom/android/internal/telephony/test/SimulatedCommands;->mDcSuccess:Z Lcom/android/internal/telephony/test/SimulatedCommands;->resultFail(Landroid/os/Message;Ljava/lang/Object;Ljava/lang/Throwable;)V Lcom/android/internal/telephony/test/SimulatedCommands;->resultSuccess(Landroid/os/Message;Ljava/lang/Object;)V diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 5e445d14a08b..b584d5d4c3b4 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -2545,7 +2545,7 @@ public class Activity extends ContextThemeWrapper * picture-in-picture. * * @return true if the system successfully put this activity into picture-in-picture mode or was - * already in picture-in-picture mode (@see {@link #isInPictureInPictureMode()). If the device + * already in picture-in-picture mode (see {@link #isInPictureInPictureMode()}). If the device * does not support picture-in-picture, return false. */ public boolean enterPictureInPictureMode(@NonNull PictureInPictureParams params) { diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index 67d9ad6e93c6..2b81c86e1b0d 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -44,6 +44,7 @@ import android.content.pm.InstantAppInfo; import android.content.pm.InstrumentationInfo; import android.content.pm.IntentFilterVerificationInfo; import android.content.pm.KeySet; +import android.content.pm.ModuleInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageInstaller; import android.content.pm.PackageItemInfo; @@ -791,6 +792,16 @@ public class ApplicationPackageManager extends PackageManager { throw new NameNotFoundException("No shared userid for user:"+sharedUserName); } + @Override + public List<ModuleInfo> getInstalledModules(int flags) { + return null; + } + + @Override + public ModuleInfo getModuleInfo(String packageName, int flags) throws NameNotFoundException { + return null; + } + @SuppressWarnings("unchecked") @Override public List<PackageInfo> getInstalledPackages(int flags) { diff --git a/core/java/android/app/RemoteInput.java b/core/java/android/app/RemoteInput.java index ebbf317ad05d..392921e813f9 100644 --- a/core/java/android/app/RemoteInput.java +++ b/core/java/android/app/RemoteInput.java @@ -173,7 +173,7 @@ public final class RemoteInput implements Parcelable { /** * Returns true if the input only accepts data, meaning {@link #getAllowFreeFormInput} - * is false, {@link #getChoices} is null or empty, and {@link #getAllowedDataTypes is + * is false, {@link #getChoices} is null or empty, and {@link #getAllowedDataTypes} is * non-null and not empty. */ public boolean isDataOnly() { diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java index 43e183665435..f4fd5d132069 100644 --- a/core/java/android/app/SystemServiceRegistry.java +++ b/core/java/android/app/SystemServiceRegistry.java @@ -154,7 +154,7 @@ import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.telephony.euicc.EuiccCardManager; import android.telephony.euicc.EuiccManager; -import android.telephony.rcs.RcsManager; +import android.telephony.ims.RcsManager; import android.util.ArrayMap; import android.util.Log; import android.view.ContextThemeWrapper; diff --git a/core/java/android/app/VrManager.java b/core/java/android/app/VrManager.java index 6248e7c38ec1..5b87de48210f 100644 --- a/core/java/android/app/VrManager.java +++ b/core/java/android/app/VrManager.java @@ -5,7 +5,6 @@ import android.annotation.NonNull; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; -import android.annotation.TestApi; import android.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; @@ -222,7 +221,6 @@ public class VrManager { * @param componentName ComponentName of a VR InputMethod that should be set as selected * input by InputMethodManagerService. */ - @TestApi @RequiresPermission(android.Manifest.permission.RESTRICTED_VR_ACCESS) public void setVrInputMethod(ComponentName componentName) { try { diff --git a/core/java/android/app/WaitResult.java b/core/java/android/app/WaitResult.java index 5baf2e22bc31..ad9f680ad196 100644 --- a/core/java/android/app/WaitResult.java +++ b/core/java/android/app/WaitResult.java @@ -16,11 +16,14 @@ package android.app; +import android.annotation.IntDef; import android.content.ComponentName; import android.os.Parcel; import android.os.Parcelable; import java.io.PrintWriter; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; /** * Information returned after waiting for an activity start. @@ -28,11 +31,43 @@ import java.io.PrintWriter; * @hide */ public class WaitResult implements Parcelable { + + /** + * The state at which a launch sequence had started. + * + * @see <a href="https://developer.android.com/topic/performance/vitals/launch-time"App startup + * time</a> + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = {"LAUNCH_STATE_"}, value = { + LAUNCH_STATE_COLD, + LAUNCH_STATE_WARM, + LAUNCH_STATE_HOT + }) + public @interface LaunchState { + } + + /** + * Cold launch sequence: a new process has started. + */ + public static final int LAUNCH_STATE_COLD = 1; + + /** + * Warm launch sequence: process reused, but activity has to be created. + */ + public static final int LAUNCH_STATE_WARM = 2; + + /** + * Hot launch sequence: process reused, activity brought-to-top. + */ + public static final int LAUNCH_STATE_HOT = 3; + public static final int INVALID_DELAY = -1; public int result; public boolean timeout; public ComponentName who; public long totalTime; + public @LaunchState int launchState; public WaitResult() { } @@ -48,6 +83,7 @@ public class WaitResult implements Parcelable { dest.writeInt(timeout ? 1 : 0); ComponentName.writeToParcel(who, dest); dest.writeLong(totalTime); + dest.writeInt(launchState); } public static final Parcelable.Creator<WaitResult> CREATOR @@ -68,6 +104,7 @@ public class WaitResult implements Parcelable { timeout = source.readInt() != 0; who = ComponentName.readFromParcel(source); totalTime = source.readLong(); + launchState = source.readInt(); } public void dump(PrintWriter pw, String prefix) { @@ -76,5 +113,19 @@ public class WaitResult implements Parcelable { pw.println(prefix + " timeout=" + timeout); pw.println(prefix + " who=" + who); pw.println(prefix + " totalTime=" + totalTime); + pw.println(prefix + " launchState=" + launchState); + } + + public static String launchStateToString(@LaunchState int type) { + switch (type) { + case LAUNCH_STATE_COLD: + return "COLD"; + case LAUNCH_STATE_WARM: + return "WARM"; + case LAUNCH_STATE_HOT: + return "HOT"; + default: + return "UNKNOWN (" + type + ")"; + } } }
\ No newline at end of file diff --git a/core/java/android/app/slice/SliceProvider.java b/core/java/android/app/slice/SliceProvider.java index ca60e140ba8e..0ccd49f2e028 100644 --- a/core/java/android/app/slice/SliceProvider.java +++ b/core/java/android/app/slice/SliceProvider.java @@ -209,7 +209,7 @@ public abstract class SliceProvider extends ContentProvider { * * @param sliceUri Uri to bind. * @param supportedSpecs List of supported specs. - * @see Slice. + * @see Slice * @see Slice#HINT_PARTIAL */ public Slice onBindSlice(Uri sliceUri, Set<SliceSpec> supportedSpecs) { diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java index 8e6a3856d51b..87b64797f3c6 100644 --- a/core/java/android/bluetooth/BluetoothAdapter.java +++ b/core/java/android/bluetooth/BluetoothAdapter.java @@ -643,6 +643,7 @@ public final class BluetoothAdapter { private final IBluetoothManager mManagerService; @UnsupportedAppUsage private IBluetooth mService; + private Context mContext; private final ReentrantReadWriteLock mServiceLock = new ReentrantReadWriteLock(); private final Object mLock = new Object(); @@ -1541,6 +1542,23 @@ public final class BluetoothAdapter { } /** + * Set the context for this BluetoothAdapter (only called from BluetoothManager) + * @hide + */ + public void setContext(Context context) { + mContext = context; + } + + private String getOpPackageName() { + // Workaround for legacy API for getting a BluetoothAdapter not + // passing a context + if (mContext != null) { + return mContext.getOpPackageName(); + } + return ActivityThread.currentOpPackageName(); + } + + /** * Start the remote device discovery process. * <p>The discovery process usually involves an inquiry scan of about 12 * seconds, followed by a page scan of each new device to retrieve its @@ -1577,7 +1595,7 @@ public final class BluetoothAdapter { try { mServiceLock.readLock().lock(); if (mService != null) { - return mService.startDiscovery(); + return mService.startDiscovery(getOpPackageName()); } } catch (RemoteException e) { Log.e(TAG, "", e); diff --git a/core/java/android/bluetooth/BluetoothManager.java b/core/java/android/bluetooth/BluetoothManager.java index e3672a7e064f..e08d405324ea 100644 --- a/core/java/android/bluetooth/BluetoothManager.java +++ b/core/java/android/bluetooth/BluetoothManager.java @@ -67,6 +67,7 @@ public final class BluetoothManager { } // Legacy api - getDefaultAdapter does not take in the context mAdapter = BluetoothAdapter.getDefaultAdapter(); + mAdapter.setContext(context); } /** diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java index ad1891123b7f..f138d39b7fb0 100644 --- a/core/java/android/content/ContentProvider.java +++ b/core/java/android/content/ContentProvider.java @@ -1184,12 +1184,12 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall * Implement this to handle query requests where the arguments are packed into a {@link Bundle}. * Arguments may include traditional SQL style query arguments. When present these * should be handled according to the contract established in - * {@link #query(Uri, String[], String, String[], String, CancellationSignal). + * {@link #query(Uri, String[], String, String[], String, CancellationSignal)}. * * <p>Traditional SQL arguments can be found in the bundle using the following keys: - * <li>{@link ContentResolver#QUERY_ARG_SQL_SELECTION} - * <li>{@link ContentResolver#QUERY_ARG_SQL_SELECTION_ARGS} - * <li>{@link ContentResolver#QUERY_ARG_SQL_SORT_ORDER} + * <li>{@link android.content.ContentResolver#QUERY_ARG_SQL_SELECTION} + * <li>{@link android.content.ContentResolver#QUERY_ARG_SQL_SELECTION_ARGS} + * <li>{@link android.content.ContentResolver#QUERY_ARG_SQL_SORT_ORDER} * * <p>This method can be called from multiple threads, as described in * <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes @@ -1246,8 +1246,8 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall return cursor;</pre> * <p> - * @see #query(Uri, String[], String, String[], String, CancellationSignal) for - * implementation details. + * See {@link #query(Uri, String[], String, String[], String, CancellationSignal)} + * for implementation details. * * @param uri The URI to query. This will be the full URI sent by the client. * @param projection The list of columns to put into the cursor. diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index d7d3cb543af9..b39010d9d14e 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -4462,7 +4462,7 @@ public abstract class Context { /** * Use with {@link #getSystemService(String)} to retrieve an - * {@link android.telephony.rcs.RcsManager}. + * {@link android.telephony.ims.RcsManager}. * @hide */ public static final String TELEPHONY_RCS_SERVICE = "ircs"; diff --git a/core/java/android/content/pm/ModuleInfo.java b/core/java/android/content/pm/ModuleInfo.java new file mode 100644 index 000000000000..07e640b1ba61 --- /dev/null +++ b/core/java/android/content/pm/ModuleInfo.java @@ -0,0 +1,146 @@ +/* + * 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; + +import android.annotation.Nullable; +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.Objects; + +/** + * Information you can retrieve about a particular system + * module. + */ +public final class ModuleInfo implements Parcelable { + + // NOTE: When adding new data members be sure to update the copy-constructor, Parcel + // constructor, and writeToParcel. + + /** Public name of this module. */ + private String mName; + + /** The package name of this module. */ + private String mPackageName; + + /** Whether or not this module is hidden from the user. */ + private boolean mHidden; + + // TODO: Decide whether we need an additional metadata bundle to support out of band + // updates to ModuleInfo. + // + // private Bundle mMetadata; + + /** @hide */ + public ModuleInfo() { + } + + /** @hide */ + public ModuleInfo(ModuleInfo orig) { + mName = orig.mName; + mPackageName = orig.mPackageName; + mHidden = orig.mHidden; + } + + /** @hide Sets the public name of this module. */ + public ModuleInfo setName(String name) { + mName = name; + return this; + } + + /** Gets the public name of this module. */ + public @Nullable String getName() { + return mName; + } + + /** @hide Sets the package name of this module. */ + public ModuleInfo setPackageName(String packageName) { + mPackageName = packageName; + return this; + } + + /** Gets the package name of this module. */ + public @Nullable String getPackageName() { + return mPackageName; + } + + /** @hide Sets whether or not this package is hidden. */ + public ModuleInfo setHidden(boolean hidden) { + mHidden = hidden; + return this; + } + + /** Gets whether or not this package is hidden. */ + public boolean isHidden() { + return mHidden; + } + + /** Returns a string representation of this object. */ + public String toString() { + return "ModuleInfo{" + + Integer.toHexString(System.identityHashCode(this)) + + " " + mName + "}"; + } + + /** Describes the kinds of special objects contained in this object. */ + public int describeContents() { + return 0; + } + + @Override + public int hashCode() { + int hashCode = 0; + hashCode = 31 * hashCode + Objects.hashCode(mName); + hashCode = 31 * hashCode + Objects.hashCode(mPackageName); + hashCode = 31 * hashCode + Boolean.hashCode(mHidden); + return hashCode; + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof ModuleInfo)) { + return false; + } + final ModuleInfo other = (ModuleInfo) obj; + return Objects.equals(mName, other.mName) + && Objects.equals(mPackageName, other.mPackageName) + && mHidden == other.mHidden; + } + + /** Flattens this object into the given {@link Parcel}. */ + public void writeToParcel(Parcel dest, int parcelableFlags) { + dest.writeString(mName); + dest.writeString(mPackageName); + dest.writeBoolean(mHidden); + } + + private ModuleInfo(Parcel source) { + mName = source.readString(); + mPackageName = source.readString(); + mHidden = source.readBoolean(); + } + + public static final Parcelable.Creator<ModuleInfo> CREATOR = + new Parcelable.Creator<ModuleInfo>() { + public ModuleInfo createFromParcel(Parcel source) { + return new ModuleInfo(source); + } + public ModuleInfo[] newArray(int size) { + return new ModuleInfo[size]; + } + }; +} diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 34cdfee3f959..566017b7372e 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -220,6 +220,12 @@ public abstract class PackageManager { /** @hide */ @IntDef(flag = true, prefix = { "GET_", "MATCH_" }, value = { + }) + @Retention(RetentionPolicy.SOURCE) + public @interface ModuleInfoFlags {} + + /** @hide */ + @IntDef(flag = true, prefix = { "GET_", "MATCH_" }, value = { GET_META_DATA, }) @Retention(RetentionPolicy.SOURCE) @@ -3467,6 +3473,35 @@ public abstract class PackageManager { @ComponentInfoFlags int flags) throws NameNotFoundException; /** + * Retrieve information for a particular module. + * + * @param packageName The name of the module. + * @param flags Additional option flags to modify the data returned. + * @return A {@link ModuleInfo} object containing information about the + * module. + * @throws NameNotFoundException if a module with the given name cannot be + * found on the system. + */ + public ModuleInfo getModuleInfo(String packageName, @ModuleInfoFlags int flags) + throws NameNotFoundException { + throw new UnsupportedOperationException( + "getModuleInfo not implemented in subclass"); + } + + /** + * Return a List of all modules that are installed. + * + * @param flags Additional option flags to modify the data returned. + * @return A {@link List} of {@link ModuleInfo} objects, one for each installed + * module, containing information about the module. In the unlikely case + * there are no installed modules, an empty list is returned. + */ + public @NonNull List<ModuleInfo> getInstalledModules(@ModuleInfoFlags int flags) { + throw new UnsupportedOperationException( + "getInstalledModules not implemented in subclass"); + } + + /** * Return a List of all packages that are installed for the current user. * * @param flags Additional option flags to modify the data returned. diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java index c437dde2dacc..eae1aa5eb750 100644 --- a/core/java/android/os/BatteryStats.java +++ b/core/java/android/os/BatteryStats.java @@ -2283,7 +2283,8 @@ public abstract class BatteryStats implements Parcelable { static final String[] DATA_CONNECTION_NAMES = { "none", "gprs", "edge", "umts", "cdma", "evdo_0", "evdo_A", "1xrtt", "hsdpa", "hsupa", "hspa", "iden", "evdo_b", "lte", - "ehrpd", "hspap", "gsm", "td_scdma", "iwlan", "lte_ca", "other" + "ehrpd", "hspap", "gsm", "td_scdma", "iwlan", "lte_ca", "nr", + "other" }; public static final int NUM_DATA_CONNECTION_TYPES = DATA_CONNECTION_OTHER+1; @@ -4730,7 +4731,7 @@ public abstract class BatteryStats implements Parcelable { sb.append("\n "); sb.append(prefix); didOne = true; - sb.append(DATA_CONNECTION_NAMES[i]); + sb.append(i < DATA_CONNECTION_NAMES.length ? DATA_CONNECTION_NAMES[i] : "ERROR"); sb.append(" "); formatTimeMs(sb, time/1000); sb.append("("); diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index 17ce79b83aa8..0a60764428dc 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -1515,11 +1515,11 @@ public class UserManager { * background user; the result here does not distinguish between the two. * * <p>Note prior to Android Nougat MR1 (SDK version <= 24; - * {@link android.os.Build.VERSION_CODES#N), this API required a system permission + * {@link android.os.Build.VERSION_CODES#N}, this API required a system permission * in order to check other profile's status. * Since Android Nougat MR1 (SDK version >= 25; - * {@link android.os.Build.VERSION_CODES#N_MR1)), the restriction has been relaxed, and now - * it'll accept any {@link UserHandle} within the same profile group as the caller. + * {@link android.os.Build.VERSION_CODES#N_MR1}), the restriction has been relaxed, and now + * it'll accept any {@link android.os.UserHandle} within the same profile group as the caller. * * @param user The user to retrieve the running state for. */ @@ -1544,11 +1544,11 @@ public class UserManager { * (but is not yet fully stopped, and still running some code). * * <p>Note prior to Android Nougat MR1 (SDK version <= 24; - * {@link android.os.Build.VERSION_CODES#N), this API required a system permission + * {@link android.os.Build.VERSION_CODES#N}, this API required a system permission * in order to check other profile's status. * Since Android Nougat MR1 (SDK version >= 25; - * {@link android.os.Build.VERSION_CODES#N_MR1)), the restriction has been relaxed, and now - * it'll accept any {@link UserHandle} within the same profile group as the caller. + * {@link android.os.Build.VERSION_CODES#N_MR1}), the restriction has been relaxed, and now + * it'll accept any {@link android.os.UserHandle} within the same profile group as the caller. * * @param user The user to retrieve the running state for. */ diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java index a8726e9de3d0..cd991cc0d6fc 100644 --- a/core/java/android/provider/DocumentsContract.java +++ b/core/java/android/provider/DocumentsContract.java @@ -1275,7 +1275,7 @@ public final class DocumentsContract { } } - /** @removed */ + @Deprecated public static Bitmap getDocumentThumbnail(ContentResolver content, Uri documentUri, Point size, CancellationSignal signal) throws FileNotFoundException { return getDocumentThumbnail((ContentInterface) content, documentUri, size, signal); @@ -1307,7 +1307,7 @@ public final class DocumentsContract { } } - /** @removed */ + @Deprecated public static Uri createDocument(ContentResolver content, Uri parentDocumentUri, String mimeType, String displayName) throws FileNotFoundException { return createDocument((ContentInterface) content, parentDocumentUri, mimeType, displayName); @@ -1345,7 +1345,7 @@ public final class DocumentsContract { } } - /** @removed */ + @Deprecated public static boolean isChildDocument(ContentResolver content, Uri parentDocumentUri, Uri childDocumentUri) throws FileNotFoundException { return isChildDocument((ContentInterface) content, parentDocumentUri, childDocumentUri); @@ -1382,7 +1382,7 @@ public final class DocumentsContract { } } - /** @removed */ + @Deprecated public static Uri renameDocument(ContentResolver content, Uri documentUri, String displayName) throws FileNotFoundException { return renameDocument((ContentInterface) content, documentUri, displayName); @@ -1410,7 +1410,7 @@ public final class DocumentsContract { } } - /** @removed */ + @Deprecated public static boolean deleteDocument(ContentResolver content, Uri documentUri) throws FileNotFoundException { return deleteDocument((ContentInterface) content, documentUri); @@ -1441,7 +1441,7 @@ public final class DocumentsContract { } } - /** @removed */ + @Deprecated public static Uri copyDocument(ContentResolver content, Uri sourceDocumentUri, Uri targetParentDocumentUri) throws FileNotFoundException { return copyDocument((ContentInterface) content, sourceDocumentUri, targetParentDocumentUri); @@ -1474,7 +1474,7 @@ public final class DocumentsContract { } } - /** @removed */ + @Deprecated public static Uri moveDocument(ContentResolver content, Uri sourceDocumentUri, Uri sourceParentDocumentUri, Uri targetParentDocumentUri) throws FileNotFoundException { return moveDocument((ContentInterface) content, sourceDocumentUri, sourceParentDocumentUri, @@ -1508,7 +1508,7 @@ public final class DocumentsContract { } } - /** @removed */ + @Deprecated public static boolean removeDocument(ContentResolver content, Uri documentUri, Uri parentDocumentUri) throws FileNotFoundException { return removeDocument((ContentInterface) content, documentUri, parentDocumentUri); @@ -1531,7 +1531,7 @@ public final class DocumentsContract { } } - /** @removed */ + @Deprecated public static void ejectRoot(ContentResolver content, Uri rootUri) { ejectRoot((ContentInterface) content, rootUri); } @@ -1581,7 +1581,7 @@ public final class DocumentsContract { } } - /** @removed */ + @Deprecated public static Bundle getDocumentMetadata(ContentResolver content, Uri documentUri) throws FileNotFoundException { return getDocumentMetadata((ContentInterface) content, documentUri); @@ -1618,7 +1618,7 @@ public final class DocumentsContract { } } - /** @removed */ + @Deprecated public static Path findDocumentPath(ContentResolver content, Uri treeUri) throws FileNotFoundException { return findDocumentPath((ContentInterface) content, treeUri); @@ -1697,7 +1697,7 @@ public final class DocumentsContract { } } - /** @removed */ + @Deprecated public static IntentSender createWebLinkIntent(ContentResolver content, Uri uri, Bundle options) throws FileNotFoundException { return createWebLinkIntent((ContentInterface) content, uri, options); diff --git a/core/java/android/text/style/ImageSpan.java b/core/java/android/text/style/ImageSpan.java index d4edde9ec589..13ac9ff2ddaf 100644 --- a/core/java/android/text/style/ImageSpan.java +++ b/core/java/android/text/style/ImageSpan.java @@ -259,7 +259,8 @@ public class ImageSpan extends DynamicDrawableSpan { * Returns the source string that was saved during construction. * * @return the source string that was saved during construction - * @see #ImageSpan(Drawable, String) and this{@link #ImageSpan(Context, Uri)} + * @see #ImageSpan(Drawable, String) + * @see #ImageSpan(Context, Uri) */ @Nullable public String getSource() { diff --git a/core/java/android/view/contentcapture/ContentCaptureManager.java b/core/java/android/view/contentcapture/ContentCaptureManager.java index 1889692ea831..cc0264ac0bc9 100644 --- a/core/java/android/view/contentcapture/ContentCaptureManager.java +++ b/core/java/android/view/contentcapture/ContentCaptureManager.java @@ -31,7 +31,9 @@ import android.os.Handler; import android.os.HandlerThread; import android.os.IBinder; import android.os.RemoteException; +import android.os.SystemClock; import android.util.Log; +import android.util.TimeUtils; import android.view.View; import android.view.ViewStructure; import android.view.autofill.AutofillId; @@ -98,6 +100,12 @@ public final class ContentCaptureManager { */ public static final int STATE_DISABLED = 3; + /** + * Handler message used to flush the buffer. + */ + private static final int MSG_FLUSH = 1; + + private static final String BG_THREAD_NAME = "intel_svc_streamer_thread"; /** @@ -106,6 +114,12 @@ public final class ContentCaptureManager { // TODO(b/111276913): use settings private static final int MAX_BUFFER_SIZE = 100; + /** + * Frequency the buffer is flushed if stale. + */ + // TODO(b/111276913): use settings + private static final int FLUSHING_FREQUENCY_MS = 5_000; + @NonNull private final AtomicBoolean mDisabled = new AtomicBoolean(); @@ -136,6 +150,9 @@ public final class ContentCaptureManager { // held at the Application level private final Handler mHandler; + // Used just for debugging purposes (on dump) + private long mNextFlush; + /** @hide */ public ContentCaptureManager(@NonNull Context context, @Nullable IContentCaptureManager service) { @@ -207,9 +224,17 @@ public final class ContentCaptureManager { mEvents = new ArrayList<>(MAX_BUFFER_SIZE); } mEvents.add(event); + final int numberEvents = mEvents.size(); - if (numberEvents < MAX_BUFFER_SIZE && !forceFlush) { - // Buffering events, return right away... + + // TODO(b/120784831): need to optimize it so we buffer changes until a number of X are + // buffered (either total or per autofillid). For + // example, if the user typed "a", "b", "c" and the threshold is 3, we should buffer + // "a" and "b" then send "abc". + final boolean bufferEvent = numberEvents < MAX_BUFFER_SIZE; + + if (bufferEvent && !forceFlush) { + handleScheduleFlush(); return; } @@ -236,10 +261,38 @@ public final class ContentCaptureManager { return; } + handleForceFlush(); + } + + private void handleScheduleFlush() { + if (mHandler.hasMessages(MSG_FLUSH)) { + // "Renew" the flush message by removing the previous one + mHandler.removeMessages(MSG_FLUSH); + } + mNextFlush = SystemClock.elapsedRealtime() + FLUSHING_FREQUENCY_MS; + if (VERBOSE) { + Log.v(TAG, "Scheduled to flush in " + FLUSHING_FREQUENCY_MS + "ms: " + mNextFlush); + } + mHandler.sendMessageDelayed( + obtainMessage(ContentCaptureManager::handleFlushIfNeeded, this).setWhat(MSG_FLUSH), + FLUSHING_FREQUENCY_MS); + } + + private void handleFlushIfNeeded() { + if (mEvents.isEmpty()) { + if (VERBOSE) Log.v(TAG, "Nothing to flush"); + return; + } + handleForceFlush(); + } + + private void handleForceFlush() { + final int numberEvents = mEvents.size(); try { if (DEBUG) { Log.d(TAG, "Flushing " + numberEvents + " event(s) for " + getActivityDebugName()); } + mHandler.removeMessages(MSG_FLUSH); mService.sendEvents(mContext.getUserId(), mId, mEvents); // TODO(b/111276913): decide whether we should clear or set it to null, as each has // its own advantages: clearing will save extra allocations while the session is @@ -307,6 +360,7 @@ public final class ContentCaptureManager { mApplicationToken = null; mComponentName = null; mEvents = null; + mHandler.removeMessages(MSG_FLUSH); } /** @@ -443,7 +497,7 @@ public final class ContentCaptureManager { pw.print(prefix2); pw.print("component name: "); pw.println(mComponentName.flattenToShortString()); } - if (mEvents != null) { + if (mEvents != null && !mEvents.isEmpty()) { final int numberEvents = mEvents.size(); pw.print(prefix2); pw.print("buffered events: "); pw.print(numberEvents); pw.print('/'); pw.println(MAX_BUFFER_SIZE); @@ -455,6 +509,9 @@ public final class ContentCaptureManager { pw.println(); } } + pw.print(prefix2); pw.print("flush frequency: "); pw.println(FLUSHING_FREQUENCY_MS); + pw.print(prefix2); pw.print("next flush: "); + TimeUtils.formatDuration(mNextFlush - SystemClock.elapsedRealtime(), pw); pw.println(); } } diff --git a/core/java/com/android/internal/app/procstats/AssociationState.java b/core/java/com/android/internal/app/procstats/AssociationState.java index 3842f6659704..4da339165655 100644 --- a/core/java/com/android/internal/app/procstats/AssociationState.java +++ b/core/java/com/android/internal/app/procstats/AssociationState.java @@ -445,8 +445,18 @@ public final class AssociationState { } } + public boolean hasProcess(String procName) { + final int NSRC = mSources.size(); + for (int isrc = 0; isrc < NSRC; isrc++) { + if (mSources.keyAt(isrc).mProcess.equals(procName)) { + return true; + } + } + return false; + } + public void dumpStats(PrintWriter pw, String prefix, String prefixInner, String headerPrefix, - long now, long totalTime, boolean dumpDetails, boolean dumpAll) { + long now, long totalTime, String reqPackage, boolean dumpDetails, boolean dumpAll) { if (dumpAll) { pw.print(prefix); pw.print("mNumActive="); @@ -456,6 +466,9 @@ public final class AssociationState { for (int isrc = 0; isrc < NSRC; isrc++) { final SourceKey key = mSources.keyAt(isrc); final SourceState src = mSources.valueAt(isrc); + if (reqPackage != null && !reqPackage.equals(key.mProcess)) { + continue; + } pw.print(prefixInner); pw.print("<- "); pw.print(key.mProcess); diff --git a/core/java/com/android/internal/app/procstats/ProcessStats.java b/core/java/com/android/internal/app/procstats/ProcessStats.java index 19d8a836fc4c..9ee583a97b8d 100644 --- a/core/java/com/android/internal/app/procstats/ProcessStats.java +++ b/core/java/com/android/internal/app/procstats/ProcessStats.java @@ -1396,10 +1396,10 @@ public final class ProcessStats implements Parcelable { return as; } - // See b/118826162 -- to avoid logspaming, we rate limit the WTF. - private static final long INVERSE_PROC_STATE_WTF_MIN_INTERVAL_MS = 10_000L; - private long mNextInverseProcStateWtfUptime; - private int mSkippedInverseProcStateWtfCount; + // See b/118826162 -- to avoid logspaming, we rate limit the warnings. + private static final long INVERSE_PROC_STATE_WARNING_MIN_INTERVAL_MS = 10_000L; + private long mNextInverseProcStateWarningUptime; + private int mSkippedInverseProcStateWarningCount; public void updateTrackingAssociationsLocked(int curSeq, long now) { final int NUM = mTrackingAssociations.size(); @@ -1423,18 +1423,19 @@ public final class ProcessStats implements Parcelable { act.stopActive(now); if (act.mProcState < procState) { final long nowUptime = SystemClock.uptimeMillis(); - if (mNextInverseProcStateWtfUptime > nowUptime) { - mSkippedInverseProcStateWtfCount++; + if (mNextInverseProcStateWarningUptime > nowUptime) { + mSkippedInverseProcStateWarningCount++; } else { // TODO We still see it during boot related to GMS-core. // b/118826162 - Slog.wtf(TAG, "Tracking association " + act + " whose proc state " + Slog.w(TAG, "Tracking association " + act + " whose proc state " + act.mProcState + " is better than process " + proc + " proc state " + procState - + " (" + mSkippedInverseProcStateWtfCount + " skipped)"); - mSkippedInverseProcStateWtfCount = 0; - mNextInverseProcStateWtfUptime = - nowUptime + INVERSE_PROC_STATE_WTF_MIN_INTERVAL_MS; + + " (" + mSkippedInverseProcStateWarningCount + + " skipped)"); + mSkippedInverseProcStateWarningCount = 0; + mNextInverseProcStateWarningUptime = + nowUptime + INVERSE_PROC_STATE_WARNING_MIN_INTERVAL_MS; } } } @@ -1474,6 +1475,7 @@ public final class ProcessStats implements Parcelable { final int NSRVS = pkgState.mServices.size(); final int NASCS = pkgState.mAssociations.size(); final boolean pkgMatch = reqPackage == null || reqPackage.equals(pkgName); + boolean onlyAssociations = false; if (!pkgMatch) { boolean procMatch = false; for (int iproc = 0; iproc < NPROCS; iproc++) { @@ -1484,7 +1486,18 @@ public final class ProcessStats implements Parcelable { } } if (!procMatch) { - continue; + // Check if this app has any associations with the requested + // package, so that if so we print those. + for (int iasc = 0; iasc < NASCS; iasc++) { + AssociationState asc = pkgState.mAssociations.valueAt(iasc); + if (asc.hasProcess(reqPackage)) { + onlyAssociations = true; + break; + } + } + if (!onlyAssociations) { + continue; + } } } if (NPROCS > 0 || NSRVS > 0 || NASCS > 0) { @@ -1502,7 +1515,7 @@ public final class ProcessStats implements Parcelable { pw.print(vers); pw.println(":"); } - if ((section & REPORT_PKG_PROC_STATS) != 0) { + if ((section & REPORT_PKG_PROC_STATS) != 0 && !onlyAssociations) { if (!dumpSummary || dumpAll) { for (int iproc = 0; iproc < NPROCS; iproc++) { ProcessState proc = pkgState.mProcesses.valueAt(iproc); @@ -1549,7 +1562,7 @@ public final class ProcessStats implements Parcelable { now, totalTime); } } - if ((section & REPORT_PKG_SVC_STATS) != 0) { + if ((section & REPORT_PKG_SVC_STATS) != 0 && !onlyAssociations) { for (int isvc = 0; isvc < NSRVS; isvc++) { ServiceState svc = pkgState.mServices.valueAt(isvc); if (!pkgMatch && !reqPackage.equals(svc.getProcessName())) { @@ -1578,7 +1591,9 @@ public final class ProcessStats implements Parcelable { for (int iasc = 0; iasc < NASCS; iasc++) { AssociationState asc = pkgState.mAssociations.valueAt(iasc); if (!pkgMatch && !reqPackage.equals(asc.getProcessName())) { - continue; + if (!onlyAssociations || !asc.hasProcess(reqPackage)) { + continue; + } } if (activeOnly && !asc.isInUse()) { pw.print(" (Not active association: "); @@ -1596,7 +1611,8 @@ public final class ProcessStats implements Parcelable { pw.print(" Process: "); pw.println(asc.getProcessName()); asc.dumpStats(pw, " ", " ", " ", - now, totalTime, dumpDetails, dumpAll); + now, totalTime, onlyAssociations ? reqPackage : null, + dumpDetails, dumpAll); } } } diff --git a/core/java/com/android/internal/util/CollectionUtils.java b/core/java/com/android/internal/util/CollectionUtils.java index 151901be7b5b..470533f2d002 100644 --- a/core/java/com/android/internal/util/CollectionUtils.java +++ b/core/java/com/android/internal/util/CollectionUtils.java @@ -326,4 +326,8 @@ public class CollectionUtils { throw ExceptionUtils.propagate(e); } } + + public static @NonNull <T> List<T> defeatNullable(@Nullable List<T> val) { + return (val != null) ? val : Collections.emptyList(); + } } diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java index 2e674a5892c6..841e5b679f5f 100644 --- a/core/java/com/android/server/SystemConfig.java +++ b/core/java/com/android/server/SystemConfig.java @@ -67,6 +67,7 @@ public class SystemConfig { private static final int ALLOW_PRIVAPP_PERMISSIONS = 0x10; private static final int ALLOW_OEM_PERMISSIONS = 0x20; private static final int ALLOW_HIDDENAPI_WHITELISTING = 0x40; + private static final int ALLOW_ASSOCIATIONS = 0x80; private static final int ALLOW_ALL = ~0; // property for runtime configuration differentiation @@ -195,6 +196,12 @@ public class SystemConfig { final ArrayMap<String, ArrayMap<String, Boolean>> mOemPermissions = new ArrayMap<>(); + // Allowed associations between applications. If there are any entries + // for an app, those are the only associations allowed; otherwise, all associations + // are allowed. Allowing an association from app A to app B means app A can not + // associate with any other apps, but does not limit what apps B can associate with. + final ArrayMap<String, ArraySet<String>> mAllowedAssociations = new ArrayMap<>(); + public static SystemConfig getInstance() { synchronized (SystemConfig.class) { if (sInstance == null) { @@ -320,6 +327,10 @@ public class SystemConfig { return Collections.emptyMap(); } + public ArrayMap<String, ArraySet<String>> getAllowedAssociations() { + return mAllowedAssociations; + } + SystemConfig() { // Read configuration from system readPermissions(Environment.buildPath( @@ -329,8 +340,9 @@ public class SystemConfig { readPermissions(Environment.buildPath( Environment.getRootDirectory(), "etc", "permissions"), ALLOW_ALL); - // Vendors are only allowed to customze libs, features and privapp permissions - int vendorPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES | ALLOW_PRIVAPP_PERMISSIONS; + // Vendors are only allowed to customize these + int vendorPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES | ALLOW_PRIVAPP_PERMISSIONS + | ALLOW_ASSOCIATIONS; if (Build.VERSION.FIRST_SDK_INT <= Build.VERSION_CODES.O_MR1) { // For backward compatibility vendorPermissionFlag |= (ALLOW_PERMISSIONS | ALLOW_APP_CONFIGS); @@ -359,8 +371,8 @@ public class SystemConfig { odmPermissionFlag); } - // Allow OEM to customize features and OEM permissions - int oemPermissionFlag = ALLOW_FEATURES | ALLOW_OEM_PERMISSIONS; + // Allow OEM to customize these + int oemPermissionFlag = ALLOW_FEATURES | ALLOW_OEM_PERMISSIONS | ALLOW_ASSOCIATIONS; readPermissions(Environment.buildPath( Environment.getOemDirectory(), "etc", "sysconfig"), oemPermissionFlag); readPermissions(Environment.buildPath( @@ -423,6 +435,11 @@ public class SystemConfig { } } + private void logNotAllowedInPartition(String name, File permFile, XmlPullParser parser) { + Slog.w(TAG, "<" + name + "> not allowed in partition of " + + permFile + " at " + parser.getPositionDescription()); + } + private void readPermissionsFromXml(File permFile, int permissionFlag) { FileReader permReader = null; try { @@ -453,14 +470,17 @@ public class SystemConfig { + ": found " + parser.getName() + ", expected 'permissions' or 'config'"); } - boolean allowAll = permissionFlag == ALLOW_ALL; - boolean allowLibs = (permissionFlag & ALLOW_LIBS) != 0; - boolean allowFeatures = (permissionFlag & ALLOW_FEATURES) != 0; - boolean allowPermissions = (permissionFlag & ALLOW_PERMISSIONS) != 0; - boolean allowAppConfigs = (permissionFlag & ALLOW_APP_CONFIGS) != 0; - boolean allowPrivappPermissions = (permissionFlag & ALLOW_PRIVAPP_PERMISSIONS) != 0; - boolean allowOemPermissions = (permissionFlag & ALLOW_OEM_PERMISSIONS) != 0; - boolean allowApiWhitelisting = (permissionFlag & ALLOW_HIDDENAPI_WHITELISTING) != 0; + final boolean allowAll = permissionFlag == ALLOW_ALL; + final boolean allowLibs = (permissionFlag & ALLOW_LIBS) != 0; + final boolean allowFeatures = (permissionFlag & ALLOW_FEATURES) != 0; + final boolean allowPermissions = (permissionFlag & ALLOW_PERMISSIONS) != 0; + final boolean allowAppConfigs = (permissionFlag & ALLOW_APP_CONFIGS) != 0; + final boolean allowPrivappPermissions = (permissionFlag & ALLOW_PRIVAPP_PERMISSIONS) + != 0; + final boolean allowOemPermissions = (permissionFlag & ALLOW_OEM_PERMISSIONS) != 0; + final boolean allowApiWhitelisting = (permissionFlag & ALLOW_HIDDENAPI_WHITELISTING) + != 0; + final boolean allowAssociations = (permissionFlag & ALLOW_ASSOCIATIONS) != 0; while (true) { XmlUtils.nextElement(parser); if (parser.getEventType() == XmlPullParser.END_DOCUMENT) { @@ -468,297 +488,425 @@ public class SystemConfig { } String name = parser.getName(); - if ("group".equals(name) && allowAll) { - String gidStr = parser.getAttributeValue(null, "gid"); - if (gidStr != null) { - int gid = android.os.Process.getGidForName(gidStr); - mGlobalGids = appendInt(mGlobalGids, gid); - } else { - Slog.w(TAG, "<group> without gid in " + permFile + " at " - + parser.getPositionDescription()); - } - + if (name == null) { XmlUtils.skipCurrentTag(parser); continue; - } else if ("permission".equals(name) && allowPermissions) { - String perm = parser.getAttributeValue(null, "name"); - if (perm == null) { - Slog.w(TAG, "<permission> without name in " + permFile + " at " - + parser.getPositionDescription()); + } + switch (name) { + case "group": { + if (allowAll) { + String gidStr = parser.getAttributeValue(null, "gid"); + if (gidStr != null) { + int gid = android.os.Process.getGidForName(gidStr); + mGlobalGids = appendInt(mGlobalGids, gid); + } else { + Slog.w(TAG, "<" + name + "> without gid in " + permFile + " at " + + parser.getPositionDescription()); + } + } else { + logNotAllowedInPartition(name, permFile, parser); + } XmlUtils.skipCurrentTag(parser); - continue; - } - perm = perm.intern(); - readPermission(parser, perm); - - } else if ("assign-permission".equals(name) && allowPermissions) { - String perm = parser.getAttributeValue(null, "name"); - if (perm == null) { - Slog.w(TAG, "<assign-permission> without name in " + permFile + " at " - + parser.getPositionDescription()); + } break; + case "permission": { + if (allowPermissions) { + String perm = parser.getAttributeValue(null, "name"); + if (perm == null) { + Slog.w(TAG, "<" + name + "> without name in " + permFile + " at " + + parser.getPositionDescription()); + XmlUtils.skipCurrentTag(parser); + break; + } + perm = perm.intern(); + readPermission(parser, perm); + } else { + logNotAllowedInPartition(name, permFile, parser); + XmlUtils.skipCurrentTag(parser); + } + } break; + case "assign-permission": { + if (allowPermissions) { + String perm = parser.getAttributeValue(null, "name"); + if (perm == null) { + Slog.w(TAG, "<" + name + "> without name in " + permFile + + " at " + parser.getPositionDescription()); + XmlUtils.skipCurrentTag(parser); + break; + } + String uidStr = parser.getAttributeValue(null, "uid"); + if (uidStr == null) { + Slog.w(TAG, "<" + name + "> without uid in " + permFile + + " at " + parser.getPositionDescription()); + XmlUtils.skipCurrentTag(parser); + break; + } + int uid = Process.getUidForName(uidStr); + if (uid < 0) { + Slog.w(TAG, "<" + name + "> with unknown uid \"" + + uidStr + " in " + permFile + " at " + + parser.getPositionDescription()); + XmlUtils.skipCurrentTag(parser); + break; + } + perm = perm.intern(); + ArraySet<String> perms = mSystemPermissions.get(uid); + if (perms == null) { + perms = new ArraySet<String>(); + mSystemPermissions.put(uid, perms); + } + perms.add(perm); + } else { + logNotAllowedInPartition(name, permFile, parser); + } XmlUtils.skipCurrentTag(parser); - continue; - } - String uidStr = parser.getAttributeValue(null, "uid"); - if (uidStr == null) { - Slog.w(TAG, "<assign-permission> without uid in " + permFile + " at " - + parser.getPositionDescription()); + } break; + case "split-permission": { + if (allowPermissions) { + readSplitPermission(parser, permFile); + } else { + logNotAllowedInPartition(name, permFile, parser); + XmlUtils.skipCurrentTag(parser); + } + } break; + case "library": { + if (allowLibs) { + String lname = parser.getAttributeValue(null, "name"); + String lfile = parser.getAttributeValue(null, "file"); + String ldependency = parser.getAttributeValue(null, "dependency"); + if (lname == null) { + Slog.w(TAG, "<" + name + "> without name in " + permFile + " at " + + parser.getPositionDescription()); + } else if (lfile == null) { + Slog.w(TAG, "<" + name + "> without file in " + permFile + " at " + + parser.getPositionDescription()); + } else { + //Log.i(TAG, "Got library " + lname + " in " + lfile); + SharedLibraryEntry entry = new SharedLibraryEntry(lname, lfile, + ldependency == null ? new String[0] : ldependency.split(":")); + mSharedLibraries.put(lname, entry); + } + } else { + logNotAllowedInPartition(name, permFile, parser); + } XmlUtils.skipCurrentTag(parser); - continue; - } - int uid = Process.getUidForName(uidStr); - if (uid < 0) { - Slog.w(TAG, "<assign-permission> with unknown uid \"" - + uidStr + " in " + permFile + " at " - + parser.getPositionDescription()); + } break; + case "feature": { + if (allowFeatures) { + String fname = parser.getAttributeValue(null, "name"); + int fversion = XmlUtils.readIntAttribute(parser, "version", 0); + boolean allowed; + if (!lowRam) { + allowed = true; + } else { + String notLowRam = parser.getAttributeValue(null, "notLowRam"); + allowed = !"true".equals(notLowRam); + } + if (fname == null) { + Slog.w(TAG, "<" + name + "> without name in " + permFile + " at " + + parser.getPositionDescription()); + } else if (allowed) { + addFeature(fname, fversion); + } + } else { + logNotAllowedInPartition(name, permFile, parser); + } XmlUtils.skipCurrentTag(parser); - continue; - } - perm = perm.intern(); - ArraySet<String> perms = mSystemPermissions.get(uid); - if (perms == null) { - perms = new ArraySet<String>(); - mSystemPermissions.put(uid, perms); - } - perms.add(perm); - XmlUtils.skipCurrentTag(parser); - - } else if ("split-permission".equals(name) && allowPermissions) { - readSplitPermission(parser, permFile); - } else if ("library".equals(name) && allowLibs) { - String lname = parser.getAttributeValue(null, "name"); - String lfile = parser.getAttributeValue(null, "file"); - String ldependency = parser.getAttributeValue(null, "dependency"); - if (lname == null) { - Slog.w(TAG, "<library> without name in " + permFile + " at " - + parser.getPositionDescription()); - } else if (lfile == null) { - Slog.w(TAG, "<library> without file in " + permFile + " at " - + parser.getPositionDescription()); - } else { - //Log.i(TAG, "Got library " + lname + " in " + lfile); - SharedLibraryEntry entry = new SharedLibraryEntry(lname, lfile, - ldependency == null ? new String[0] : ldependency.split(":")); - mSharedLibraries.put(lname, entry); - } - XmlUtils.skipCurrentTag(parser); - continue; - } else if ("feature".equals(name) && allowFeatures) { - String fname = parser.getAttributeValue(null, "name"); - int fversion = XmlUtils.readIntAttribute(parser, "version", 0); - boolean allowed; - if (!lowRam) { - allowed = true; - } else { - String notLowRam = parser.getAttributeValue(null, "notLowRam"); - allowed = !"true".equals(notLowRam); - } - if (fname == null) { - Slog.w(TAG, "<feature> without name in " + permFile + " at " - + parser.getPositionDescription()); - } else if (allowed) { - addFeature(fname, fversion); - } - XmlUtils.skipCurrentTag(parser); - continue; - - } else if ("unavailable-feature".equals(name) && allowFeatures) { - String fname = parser.getAttributeValue(null, "name"); - if (fname == null) { - Slog.w(TAG, "<unavailable-feature> without name in " + permFile + " at " - + parser.getPositionDescription()); - } else { - mUnavailableFeatures.add(fname); - } - XmlUtils.skipCurrentTag(parser); - continue; - - } else if ("allow-in-power-save-except-idle".equals(name) && allowAll) { - String pkgname = parser.getAttributeValue(null, "package"); - if (pkgname == null) { - Slog.w(TAG, "<allow-in-power-save-except-idle> without package in " - + permFile + " at " + parser.getPositionDescription()); - } else { - mAllowInPowerSaveExceptIdle.add(pkgname); - } - XmlUtils.skipCurrentTag(parser); - continue; - - } else if ("allow-in-power-save".equals(name) && allowAll) { - String pkgname = parser.getAttributeValue(null, "package"); - if (pkgname == null) { - Slog.w(TAG, "<allow-in-power-save> without package in " + permFile + " at " - + parser.getPositionDescription()); - } else { - mAllowInPowerSave.add(pkgname); - } - XmlUtils.skipCurrentTag(parser); - continue; - - } else if ("allow-in-data-usage-save".equals(name) && allowAll) { - String pkgname = parser.getAttributeValue(null, "package"); - if (pkgname == null) { - Slog.w(TAG, "<allow-in-data-usage-save> without package in " + permFile - + " at " + parser.getPositionDescription()); - } else { - mAllowInDataUsageSave.add(pkgname); - } - XmlUtils.skipCurrentTag(parser); - continue; - - } else if ("allow-unthrottled-location".equals(name) && allowAll) { - String pkgname = parser.getAttributeValue(null, "package"); - if (pkgname == null) { - Slog.w(TAG, "<allow-unthrottled-location> without package in " - + permFile + " at " + parser.getPositionDescription()); - } else { - mAllowUnthrottledLocation.add(pkgname); - } - XmlUtils.skipCurrentTag(parser); - continue; - - } else if ("allow-implicit-broadcast".equals(name) && allowAll) { - String action = parser.getAttributeValue(null, "action"); - if (action == null) { - Slog.w(TAG, "<allow-implicit-broadcast> without action in " + permFile - + " at " + parser.getPositionDescription()); - } else { - mAllowImplicitBroadcasts.add(action); - } - XmlUtils.skipCurrentTag(parser); - continue; - - } else if ("app-link".equals(name) && allowAppConfigs) { - String pkgname = parser.getAttributeValue(null, "package"); - if (pkgname == null) { - Slog.w(TAG, "<app-link> without package in " + permFile + " at " - + parser.getPositionDescription()); - } else { - mLinkedApps.add(pkgname); - } - XmlUtils.skipCurrentTag(parser); - } else if ("system-user-whitelisted-app".equals(name) && allowAppConfigs) { - String pkgname = parser.getAttributeValue(null, "package"); - if (pkgname == null) { - Slog.w(TAG, "<system-user-whitelisted-app> without package in " + permFile - + " at " + parser.getPositionDescription()); - } else { - mSystemUserWhitelistedApps.add(pkgname); - } - XmlUtils.skipCurrentTag(parser); - } else if ("system-user-blacklisted-app".equals(name) && allowAppConfigs) { - String pkgname = parser.getAttributeValue(null, "package"); - if (pkgname == null) { - Slog.w(TAG, "<system-user-blacklisted-app without package in " + permFile - + " at " + parser.getPositionDescription()); - } else { - mSystemUserBlacklistedApps.add(pkgname); - } - XmlUtils.skipCurrentTag(parser); - } else if ("default-enabled-vr-app".equals(name) && allowAppConfigs) { - String pkgname = parser.getAttributeValue(null, "package"); - String clsname = parser.getAttributeValue(null, "class"); - if (pkgname == null) { - Slog.w(TAG, "<default-enabled-vr-app without package in " + permFile - + " at " + parser.getPositionDescription()); - } else if (clsname == null) { - Slog.w(TAG, "<default-enabled-vr-app without class in " + permFile - + " at " + parser.getPositionDescription()); - } else { - mDefaultVrComponents.add(new ComponentName(pkgname, clsname)); - } - XmlUtils.skipCurrentTag(parser); - } else if ("backup-transport-whitelisted-service".equals(name) && allowFeatures) { - String serviceName = parser.getAttributeValue(null, "service"); - if (serviceName == null) { - Slog.w(TAG, "<backup-transport-whitelisted-service> without service in " - + permFile + " at " + parser.getPositionDescription()); - } else { - ComponentName cn = ComponentName.unflattenFromString(serviceName); - if (cn == null) { - Slog.w(TAG, - "<backup-transport-whitelisted-service> with invalid service name " - + serviceName + " in "+ permFile - + " at " + parser.getPositionDescription()); + } break; + case "unavailable-feature": { + if (allowFeatures) { + String fname = parser.getAttributeValue(null, "name"); + if (fname == null) { + Slog.w(TAG, "<" + name + "> without name in " + permFile + + " at " + parser.getPositionDescription()); + } else { + mUnavailableFeatures.add(fname); + } } else { - mBackupTransportWhitelist.add(cn); + logNotAllowedInPartition(name, permFile, parser); } - } - XmlUtils.skipCurrentTag(parser); - } else if ("disabled-until-used-preinstalled-carrier-associated-app".equals(name) - && allowAppConfigs) { - String pkgname = parser.getAttributeValue(null, "package"); - String carrierPkgname = parser.getAttributeValue(null, "carrierAppPackage"); - if (pkgname == null || carrierPkgname == null) { - Slog.w(TAG, "<disabled-until-used-preinstalled-carrier-associated-app" - + " without package or carrierAppPackage in " + permFile + " at " - + parser.getPositionDescription()); - } else { - List<String> associatedPkgs = - mDisabledUntilUsedPreinstalledCarrierAssociatedApps.get( - carrierPkgname); - if (associatedPkgs == null) { - associatedPkgs = new ArrayList<>(); - mDisabledUntilUsedPreinstalledCarrierAssociatedApps.put( - carrierPkgname, associatedPkgs); + XmlUtils.skipCurrentTag(parser); + } break; + case "allow-in-power-save-except-idle": { + if (allowAll) { + String pkgname = parser.getAttributeValue(null, "package"); + if (pkgname == null) { + Slog.w(TAG, "<" + name + "> without package in " + + permFile + " at " + parser.getPositionDescription()); + } else { + mAllowInPowerSaveExceptIdle.add(pkgname); + } + } else { + logNotAllowedInPartition(name, permFile, parser); } - associatedPkgs.add(pkgname); - } - XmlUtils.skipCurrentTag(parser); - } else if ("disabled-until-used-preinstalled-carrier-app".equals(name) - && allowAppConfigs) { - String pkgname = parser.getAttributeValue(null, "package"); - if (pkgname == null) { - Slog.w(TAG, - "<disabled-until-used-preinstalled-carrier-app> without " - + "package in " + permFile + " at " - + parser.getPositionDescription()); - } else { - mDisabledUntilUsedPreinstalledCarrierApps.add(pkgname); - } - XmlUtils.skipCurrentTag(parser); - } else if ("privapp-permissions".equals(name) && allowPrivappPermissions) { - // privapp permissions from system, vendor, product and product_services - // partitions are stored separately. This is to prevent xml files in the vendor - // partition from granting permissions to priv apps in the system partition and - // vice versa. - boolean vendor = permFile.toPath().startsWith( - Environment.getVendorDirectory().toPath() + "/") - || permFile.toPath().startsWith( - Environment.getOdmDirectory().toPath() + "/"); - boolean product = permFile.toPath().startsWith( - Environment.getProductDirectory().toPath() + "/"); - boolean productServices = permFile.toPath().startsWith( - Environment.getProductServicesDirectory().toPath() + "/"); - if (vendor) { - readPrivAppPermissions(parser, mVendorPrivAppPermissions, - mVendorPrivAppDenyPermissions); - } else if (product) { - readPrivAppPermissions(parser, mProductPrivAppPermissions, - mProductPrivAppDenyPermissions); - } else if (productServices) { - readPrivAppPermissions(parser, mProductServicesPrivAppPermissions, - mProductServicesPrivAppDenyPermissions); - } else { - readPrivAppPermissions(parser, mPrivAppPermissions, - mPrivAppDenyPermissions); - } - } else if ("oem-permissions".equals(name) && allowOemPermissions) { - readOemPermissions(parser); - } else if ("hidden-api-whitelisted-app".equals(name) && allowApiWhitelisting) { - String pkgname = parser.getAttributeValue(null, "package"); - if (pkgname == null) { - Slog.w(TAG, "<hidden-api-whitelisted-app> without package in " + permFile - + " at " + parser.getPositionDescription()); - } else { - mHiddenApiPackageWhitelist.add(pkgname); - } - XmlUtils.skipCurrentTag(parser); - } else { - Slog.w(TAG, "Tag " + name + " is unknown or not allowed in " - + permFile.getParent()); - XmlUtils.skipCurrentTag(parser); - continue; + XmlUtils.skipCurrentTag(parser); + } break; + case "allow-in-power-save": { + if (allowAll) { + String pkgname = parser.getAttributeValue(null, "package"); + if (pkgname == null) { + Slog.w(TAG, "<" + name + "> without package in " + + permFile + " at " + parser.getPositionDescription()); + } else { + mAllowInPowerSave.add(pkgname); + } + } else { + logNotAllowedInPartition(name, permFile, parser); + } + XmlUtils.skipCurrentTag(parser); + } break; + case "allow-in-data-usage-save": { + if (allowAll) { + String pkgname = parser.getAttributeValue(null, "package"); + if (pkgname == null) { + Slog.w(TAG, "<" + name + "> without package in " + + permFile + " at " + parser.getPositionDescription()); + } else { + mAllowInDataUsageSave.add(pkgname); + } + } else { + logNotAllowedInPartition(name, permFile, parser); + } + XmlUtils.skipCurrentTag(parser); + } break; + case "allow-unthrottled-location": { + if (allowAll) { + String pkgname = parser.getAttributeValue(null, "package"); + if (pkgname == null) { + Slog.w(TAG, "<" + name + "> without package in " + + permFile + " at " + parser.getPositionDescription()); + } else { + mAllowUnthrottledLocation.add(pkgname); + } + } else { + logNotAllowedInPartition(name, permFile, parser); + } + XmlUtils.skipCurrentTag(parser); + } break; + case "allow-implicit-broadcast": { + if (allowAll) { + String action = parser.getAttributeValue(null, "action"); + if (action == null) { + Slog.w(TAG, "<" + name + "> without action in " + + permFile + " at " + parser.getPositionDescription()); + } else { + mAllowImplicitBroadcasts.add(action); + } + } else { + logNotAllowedInPartition(name, permFile, parser); + } + XmlUtils.skipCurrentTag(parser); + } break; + case "app-link": { + if (allowAppConfigs) { + String pkgname = parser.getAttributeValue(null, "package"); + if (pkgname == null) { + Slog.w(TAG, "<" + name + "> without package in " + permFile + + " at " + parser.getPositionDescription()); + } else { + mLinkedApps.add(pkgname); + } + } else { + logNotAllowedInPartition(name, permFile, parser); + } + XmlUtils.skipCurrentTag(parser); + } break; + case "system-user-whitelisted-app": { + if (allowAppConfigs) { + String pkgname = parser.getAttributeValue(null, "package"); + if (pkgname == null) { + Slog.w(TAG, "<" + name + "> without package in " + + permFile + " at " + parser.getPositionDescription()); + } else { + mSystemUserWhitelistedApps.add(pkgname); + } + } else { + logNotAllowedInPartition(name, permFile, parser); + } + XmlUtils.skipCurrentTag(parser); + } break; + case "system-user-blacklisted-app": { + if (allowAppConfigs) { + String pkgname = parser.getAttributeValue(null, "package"); + if (pkgname == null) { + Slog.w(TAG, "<" + name + "> without package in " + + permFile + " at " + parser.getPositionDescription()); + } else { + mSystemUserBlacklistedApps.add(pkgname); + } + } else { + logNotAllowedInPartition(name, permFile, parser); + } + XmlUtils.skipCurrentTag(parser); + } break; + case "default-enabled-vr-app": { + if (allowAppConfigs) { + String pkgname = parser.getAttributeValue(null, "package"); + String clsname = parser.getAttributeValue(null, "class"); + if (pkgname == null) { + Slog.w(TAG, "<" + name + "> without package in " + + permFile + " at " + parser.getPositionDescription()); + } else if (clsname == null) { + Slog.w(TAG, "<" + name + "> without class in " + + permFile + " at " + parser.getPositionDescription()); + } else { + mDefaultVrComponents.add(new ComponentName(pkgname, clsname)); + } + } else { + logNotAllowedInPartition(name, permFile, parser); + } + XmlUtils.skipCurrentTag(parser); + } break; + case "backup-transport-whitelisted-service": { + if (allowFeatures) { + String serviceName = parser.getAttributeValue(null, "service"); + if (serviceName == null) { + Slog.w(TAG, "<" + name + "> without service in " + + permFile + " at " + parser.getPositionDescription()); + } else { + ComponentName cn = ComponentName.unflattenFromString(serviceName); + if (cn == null) { + Slog.w(TAG, "<" + name + "> with invalid service name " + + serviceName + " in " + permFile + + " at " + parser.getPositionDescription()); + } else { + mBackupTransportWhitelist.add(cn); + } + } + } else { + logNotAllowedInPartition(name, permFile, parser); + } + XmlUtils.skipCurrentTag(parser); + } break; + case "disabled-until-used-preinstalled-carrier-associated-app": { + if (allowAppConfigs) { + String pkgname = parser.getAttributeValue(null, "package"); + String carrierPkgname = parser.getAttributeValue(null, + "carrierAppPackage"); + if (pkgname == null || carrierPkgname == null) { + Slog.w(TAG, "<" + name + + "> without package or carrierAppPackage in " + permFile + + " at " + parser.getPositionDescription()); + } else { + List<String> associatedPkgs = + mDisabledUntilUsedPreinstalledCarrierAssociatedApps.get( + carrierPkgname); + if (associatedPkgs == null) { + associatedPkgs = new ArrayList<>(); + mDisabledUntilUsedPreinstalledCarrierAssociatedApps.put( + carrierPkgname, associatedPkgs); + } + associatedPkgs.add(pkgname); + } + } else { + logNotAllowedInPartition(name, permFile, parser); + } + XmlUtils.skipCurrentTag(parser); + } break; + case "disabled-until-used-preinstalled-carrier-app": { + if (allowAppConfigs) { + String pkgname = parser.getAttributeValue(null, "package"); + if (pkgname == null) { + Slog.w(TAG, + "<" + name + "> without " + + "package in " + permFile + " at " + + parser.getPositionDescription()); + } else { + mDisabledUntilUsedPreinstalledCarrierApps.add(pkgname); + } + } else { + logNotAllowedInPartition(name, permFile, parser); + } + XmlUtils.skipCurrentTag(parser); + } break; + case "privapp-permissions": { + if (allowPrivappPermissions) { + // privapp permissions from system, vendor, product and product_services + // partitions are stored separately. This is to prevent xml files in + // the vendor partition from granting permissions to priv apps in the + // system partition and vice versa. + boolean vendor = permFile.toPath().startsWith( + Environment.getVendorDirectory().toPath() + "/") + || permFile.toPath().startsWith( + Environment.getOdmDirectory().toPath() + "/"); + boolean product = permFile.toPath().startsWith( + Environment.getProductDirectory().toPath() + "/"); + boolean productServices = permFile.toPath().startsWith( + Environment.getProductServicesDirectory().toPath() + "/"); + if (vendor) { + readPrivAppPermissions(parser, mVendorPrivAppPermissions, + mVendorPrivAppDenyPermissions); + } else if (product) { + readPrivAppPermissions(parser, mProductPrivAppPermissions, + mProductPrivAppDenyPermissions); + } else if (productServices) { + readPrivAppPermissions(parser, mProductServicesPrivAppPermissions, + mProductServicesPrivAppDenyPermissions); + } else { + readPrivAppPermissions(parser, mPrivAppPermissions, + mPrivAppDenyPermissions); + } + } else { + logNotAllowedInPartition(name, permFile, parser); + XmlUtils.skipCurrentTag(parser); + } + } break; + case "oem-permissions": { + if (allowOemPermissions) { + readOemPermissions(parser); + } else { + logNotAllowedInPartition(name, permFile, parser); + XmlUtils.skipCurrentTag(parser); + } + } break; + case "hidden-api-whitelisted-app": { + if (allowApiWhitelisting) { + String pkgname = parser.getAttributeValue(null, "package"); + if (pkgname == null) { + Slog.w(TAG, "<" + name + "> without package in " + + permFile + " at " + parser.getPositionDescription()); + } else { + mHiddenApiPackageWhitelist.add(pkgname); + } + } else { + logNotAllowedInPartition(name, permFile, parser); + } + XmlUtils.skipCurrentTag(parser); + } break; + case "allow-association": { + if (allowAssociations) { + String target = parser.getAttributeValue(null, "target"); + if (target == null) { + Slog.w(TAG, "<" + name + "> without target in " + permFile + + " at " + parser.getPositionDescription()); + XmlUtils.skipCurrentTag(parser); + break; + } + String allowed = parser.getAttributeValue(null, "allowed"); + if (allowed == null) { + Slog.w(TAG, "<" + name + "> without allowed in " + permFile + + " at " + parser.getPositionDescription()); + XmlUtils.skipCurrentTag(parser); + break; + } + target = target.intern(); + allowed = allowed.intern(); + ArraySet<String> associations = mAllowedAssociations.get(target); + if (associations == null) { + associations = new ArraySet<>(); + mAllowedAssociations.put(target, associations); + } + Slog.i(TAG, "Adding association: " + target + " <- " + allowed); + associations.add(allowed); + } else { + logNotAllowedInPartition(name, permFile, parser); + } + XmlUtils.skipCurrentTag(parser); + } break; + default: { + Slog.w(TAG, "Tag " + name + " is unknown in " + + permFile + " at " + parser.getPositionDescription()); + XmlUtils.skipCurrentTag(parser); + } break; } } } catch (XmlPullParserException e) { diff --git a/core/jni/android/graphics/ColorFilter.cpp b/core/jni/android/graphics/ColorFilter.cpp index 6ebf35c8e1dc..a54571b539da 100644 --- a/core/jni/android/graphics/ColorFilter.cpp +++ b/core/jni/android/graphics/ColorFilter.cpp @@ -36,7 +36,7 @@ public: return static_cast<jlong>(reinterpret_cast<uintptr_t>(&SafeUnref)); } - static jlong CreatePorterDuffFilter(JNIEnv* env, jobject, jint srcColor, jint modeHandle) { + static jlong CreateBlendModeFilter(JNIEnv* env, jobject, jint srcColor, jint modeHandle) { SkBlendMode mode = static_cast<SkBlendMode>(modeHandle); return reinterpret_cast<jlong>(SkColorFilter::MakeModeFilter(srcColor, mode).release()); } @@ -61,8 +61,8 @@ static const JNINativeMethod colorfilter_methods[] = { {"nativeGetFinalizer", "()J", (void*) SkColorFilterGlue::GetNativeFinalizer } }; -static const JNINativeMethod porterduff_methods[] = { - { "native_CreatePorterDuffFilter", "(II)J", (void*) SkColorFilterGlue::CreatePorterDuffFilter }, +static const JNINativeMethod blendmode_methods[] = { + { "native_CreateBlendModeFilter", "(II)J", (void*) SkColorFilterGlue::CreateBlendModeFilter }, }; static const JNINativeMethod lighting_methods[] = { @@ -76,8 +76,10 @@ static const JNINativeMethod colormatrix_methods[] = { int register_android_graphics_ColorFilter(JNIEnv* env) { android::RegisterMethodsOrDie(env, "android/graphics/ColorFilter", colorfilter_methods, NELEM(colorfilter_methods)); - android::RegisterMethodsOrDie(env, "android/graphics/PorterDuffColorFilter", porterduff_methods, - NELEM(porterduff_methods)); + android::RegisterMethodsOrDie(env, "android/graphics/PorterDuffColorFilter", blendmode_methods, + NELEM(blendmode_methods)); + android::RegisterMethodsOrDie(env, "android/graphics/BlendModeColorFilter", blendmode_methods, + NELEM(blendmode_methods)); android::RegisterMethodsOrDie(env, "android/graphics/LightingColorFilter", lighting_methods, NELEM(lighting_methods)); android::RegisterMethodsOrDie(env, "android/graphics/ColorMatrixColorFilter", diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp index c249e209b29f..df24bc4d2abc 100644 --- a/core/jni/android/graphics/Paint.cpp +++ b/core/jni/android/graphics/Paint.cpp @@ -845,12 +845,23 @@ namespace PaintGlue { static_assert(9 == static_cast<int>(SkBlendMode::kSrcATop), "xfermode_mismatch"); static_assert(10 == static_cast<int>(SkBlendMode::kDstATop), "xfermode_mismatch"); static_assert(11 == static_cast<int>(SkBlendMode::kXor), "xfermode_mismatch"); - static_assert(16 == static_cast<int>(SkBlendMode::kDarken), "xfermode_mismatch"); - static_assert(17 == static_cast<int>(SkBlendMode::kLighten), "xfermode_mismatch"); + static_assert(12 == static_cast<int>(SkBlendMode::kPlus), "xfermode_mismatch"); static_assert(13 == static_cast<int>(SkBlendMode::kModulate), "xfermode_mismatch"); static_assert(14 == static_cast<int>(SkBlendMode::kScreen), "xfermode_mismatch"); - static_assert(12 == static_cast<int>(SkBlendMode::kPlus), "xfermode_mismatch"); static_assert(15 == static_cast<int>(SkBlendMode::kOverlay), "xfermode_mismatch"); + static_assert(16 == static_cast<int>(SkBlendMode::kDarken), "xfermode_mismatch"); + static_assert(17 == static_cast<int>(SkBlendMode::kLighten), "xfermode_mismatch"); + static_assert(18 == static_cast<int>(SkBlendMode::kColorDodge), "xfermode mismatch"); + static_assert(19 == static_cast<int>(SkBlendMode::kColorBurn), "xfermode mismatch"); + static_assert(20 == static_cast<int>(SkBlendMode::kHardLight), "xfermode mismatch"); + static_assert(21 == static_cast<int>(SkBlendMode::kSoftLight), "xfermode mismatch"); + static_assert(22 == static_cast<int>(SkBlendMode::kDifference), "xfermode mismatch"); + static_assert(23 == static_cast<int>(SkBlendMode::kExclusion), "xfermode mismatch"); + static_assert(24 == static_cast<int>(SkBlendMode::kMultiply), "xfermode mismatch"); + static_assert(25 == static_cast<int>(SkBlendMode::kHue), "xfermode mismatch"); + static_assert(26 == static_cast<int>(SkBlendMode::kSaturation), "xfermode mismatch"); + static_assert(27 == static_cast<int>(SkBlendMode::kColor), "xfermode mismatch"); + static_assert(28 == static_cast<int>(SkBlendMode::kLuminosity), "xfermode mismatch"); SkBlendMode mode = static_cast<SkBlendMode>(xfermodeHandle); Paint* paint = reinterpret_cast<Paint*>(paintHandle); diff --git a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp index b708735616c4..24bafca9c386 100644 --- a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp +++ b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp @@ -35,7 +35,6 @@ #include "bpf/BpfUtils.h" #include "netdbpf/BpfNetworkStats.h" -using android::bpf::hasBpfSupport; using android::bpf::parseBpfNetworkStatsDetail; using android::bpf::stats_line; diff --git a/core/proto/android/app/settings_enums.proto b/core/proto/android/app/settings_enums.proto index 514f306953a5..3e1c5a334184 100644 --- a/core/proto/android/app/settings_enums.proto +++ b/core/proto/android/app/settings_enums.proto @@ -82,5 +82,7 @@ enum PageId { // OPEN: WifiDppEnrolleeActivity (android.settings.WIFI_DPP_ENROLLEE_XXX action intents) SETTINGS_WIFI_DPP_ENROLLEE = 1596; -} + // OPEN: Settings > Apps & Notifications -> Special app access -> Financial Apps Sms Access + SETTINGS_FINANCIAL_APPS_SMS_ACCESS = 1597; +} diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index b99b2dd41439..dca15bd49ca4 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -1121,10 +1121,10 @@ android:protectionLevel="normal" /> <!--Allows an app which implements the - {@link InCallService} API to be eligible to be enabled as a calling companion app. This - means that the Telecom framework will bind to the app's InCallService implementation when - there are calls active. The app can use the InCallService API to view information about - calls on the system and control these calls. + {@link android.telecom.InCallService InCallService} API to be eligible to be enabled as a + calling companion app. This means that the Telecom framework will bind to the app's + InCallService implementation when there are calls active. The app can use the InCallService + API to view information about calls on the system and control these calls. <p>Protection level: normal --> <permission android:name="android.permission.CALL_COMPANION_APP" diff --git a/core/tests/coretests/src/android/os/BinderWorkSourceTest.java b/core/tests/coretests/src/android/os/BinderWorkSourceTest.java index ef14b00f9775..5664df6e9744 100644 --- a/core/tests/coretests/src/android/os/BinderWorkSourceTest.java +++ b/core/tests/coretests/src/android/os/BinderWorkSourceTest.java @@ -23,6 +23,7 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; +import android.platform.test.annotations.Presubmit; import android.support.test.InstrumentationRegistry; import android.support.test.filters.LargeTest; import android.support.test.runner.AndroidJUnit4; @@ -37,6 +38,7 @@ import org.junit.runner.RunWith; * Test whether Binder calls work source is propagated correctly. */ @LargeTest +@Presubmit @RunWith(AndroidJUnit4.class) public class BinderWorkSourceTest { private static Context sContext; diff --git a/data/etc/OWNERS b/data/etc/OWNERS index bbec474c20fd..ea66ee373785 100644 --- a/data/etc/OWNERS +++ b/data/etc/OWNERS @@ -1 +1 @@ -per-file privapp-permissions-platform.xml = hackbod@android.com, jsharkey@android.com, svetoslavganov@google.com, toddke@google.com, yamasani@google.com +per-file privapp-permissions-platform.xml = hackbod@android.com, jsharkey@android.com, svetoslavganov@google.com, toddke@google.com, yamasani@google.com, cbrubaker@google.com, jeffv@google.com, moltmann@google.com diff --git a/docs/html/reference/images/graphics/blendmode_CLEAR.png b/docs/html/reference/images/graphics/blendmode_CLEAR.png Binary files differnew file mode 100644 index 000000000000..979782adef58 --- /dev/null +++ b/docs/html/reference/images/graphics/blendmode_CLEAR.png diff --git a/docs/html/reference/images/graphics/blendmode_COLOR.png b/docs/html/reference/images/graphics/blendmode_COLOR.png Binary files differnew file mode 100644 index 000000000000..2f41bfb03cfb --- /dev/null +++ b/docs/html/reference/images/graphics/blendmode_COLOR.png diff --git a/docs/html/reference/images/graphics/blendmode_COLOR_BURN.png b/docs/html/reference/images/graphics/blendmode_COLOR_BURN.png Binary files differnew file mode 100644 index 000000000000..26059ce858ee --- /dev/null +++ b/docs/html/reference/images/graphics/blendmode_COLOR_BURN.png diff --git a/docs/html/reference/images/graphics/blendmode_COLOR_DODGE.png b/docs/html/reference/images/graphics/blendmode_COLOR_DODGE.png Binary files differnew file mode 100644 index 000000000000..922f1d9e474d --- /dev/null +++ b/docs/html/reference/images/graphics/blendmode_COLOR_DODGE.png diff --git a/docs/html/reference/images/graphics/blendmode_DARKEN.png b/docs/html/reference/images/graphics/blendmode_DARKEN.png Binary files differnew file mode 100644 index 000000000000..6c04aa3a129f --- /dev/null +++ b/docs/html/reference/images/graphics/blendmode_DARKEN.png diff --git a/docs/html/reference/images/graphics/blendmode_DIFFERENCE.png b/docs/html/reference/images/graphics/blendmode_DIFFERENCE.png Binary files differnew file mode 100644 index 000000000000..aab2bcb8833a --- /dev/null +++ b/docs/html/reference/images/graphics/blendmode_DIFFERENCE.png diff --git a/docs/html/reference/images/graphics/blendmode_DST.png b/docs/html/reference/images/graphics/blendmode_DST.png Binary files differnew file mode 100644 index 000000000000..16f96b4752b8 --- /dev/null +++ b/docs/html/reference/images/graphics/blendmode_DST.png diff --git a/docs/html/reference/images/graphics/blendmode_DST_ATOP.png b/docs/html/reference/images/graphics/blendmode_DST_ATOP.png Binary files differnew file mode 100644 index 000000000000..d0ae2cde7b0f --- /dev/null +++ b/docs/html/reference/images/graphics/blendmode_DST_ATOP.png diff --git a/docs/html/reference/images/graphics/blendmode_DST_IN.png b/docs/html/reference/images/graphics/blendmode_DST_IN.png Binary files differnew file mode 100644 index 000000000000..9befe279af73 --- /dev/null +++ b/docs/html/reference/images/graphics/blendmode_DST_IN.png diff --git a/docs/html/reference/images/graphics/blendmode_DST_OUT.png b/docs/html/reference/images/graphics/blendmode_DST_OUT.png Binary files differnew file mode 100644 index 000000000000..e9227e9f06d3 --- /dev/null +++ b/docs/html/reference/images/graphics/blendmode_DST_OUT.png diff --git a/docs/html/reference/images/graphics/blendmode_DST_OVER.png b/docs/html/reference/images/graphics/blendmode_DST_OVER.png Binary files differnew file mode 100644 index 000000000000..015be0a4a730 --- /dev/null +++ b/docs/html/reference/images/graphics/blendmode_DST_OVER.png diff --git a/docs/html/reference/images/graphics/blendmode_EXCLUSION.png b/docs/html/reference/images/graphics/blendmode_EXCLUSION.png Binary files differnew file mode 100644 index 000000000000..307dec90ec33 --- /dev/null +++ b/docs/html/reference/images/graphics/blendmode_EXCLUSION.png diff --git a/docs/html/reference/images/graphics/blendmode_HARD_LIGHT.png b/docs/html/reference/images/graphics/blendmode_HARD_LIGHT.png Binary files differnew file mode 100644 index 000000000000..3b62b9855bf4 --- /dev/null +++ b/docs/html/reference/images/graphics/blendmode_HARD_LIGHT.png diff --git a/docs/html/reference/images/graphics/blendmode_HUE.png b/docs/html/reference/images/graphics/blendmode_HUE.png Binary files differnew file mode 100644 index 000000000000..012bd3332358 --- /dev/null +++ b/docs/html/reference/images/graphics/blendmode_HUE.png diff --git a/docs/html/reference/images/graphics/blendmode_LIGHTEN.png b/docs/html/reference/images/graphics/blendmode_LIGHTEN.png Binary files differnew file mode 100644 index 000000000000..1c3be656e40a --- /dev/null +++ b/docs/html/reference/images/graphics/blendmode_LIGHTEN.png diff --git a/docs/html/reference/images/graphics/blendmode_LUMINOSITY.png b/docs/html/reference/images/graphics/blendmode_LUMINOSITY.png Binary files differnew file mode 100644 index 000000000000..3549082e4c62 --- /dev/null +++ b/docs/html/reference/images/graphics/blendmode_LUMINOSITY.png diff --git a/docs/html/reference/images/graphics/blendmode_MODULATE.png b/docs/html/reference/images/graphics/blendmode_MODULATE.png Binary files differnew file mode 100644 index 000000000000..ed1b59d140e8 --- /dev/null +++ b/docs/html/reference/images/graphics/blendmode_MODULATE.png diff --git a/docs/html/reference/images/graphics/blendmode_MULTIPLY.png b/docs/html/reference/images/graphics/blendmode_MULTIPLY.png Binary files differnew file mode 100644 index 000000000000..c8c7ccb1e21a --- /dev/null +++ b/docs/html/reference/images/graphics/blendmode_MULTIPLY.png diff --git a/docs/html/reference/images/graphics/blendmode_OVERLAY.png b/docs/html/reference/images/graphics/blendmode_OVERLAY.png Binary files differnew file mode 100644 index 000000000000..6962f928dc7e --- /dev/null +++ b/docs/html/reference/images/graphics/blendmode_OVERLAY.png diff --git a/docs/html/reference/images/graphics/blendmode_PLUS.png b/docs/html/reference/images/graphics/blendmode_PLUS.png Binary files differnew file mode 100644 index 000000000000..015fa2b5d0e4 --- /dev/null +++ b/docs/html/reference/images/graphics/blendmode_PLUS.png diff --git a/docs/html/reference/images/graphics/blendmode_SATURATION.png b/docs/html/reference/images/graphics/blendmode_SATURATION.png Binary files differnew file mode 100644 index 000000000000..5ac96c32f648 --- /dev/null +++ b/docs/html/reference/images/graphics/blendmode_SATURATION.png diff --git a/docs/html/reference/images/graphics/blendmode_SCREEN.png b/docs/html/reference/images/graphics/blendmode_SCREEN.png Binary files differnew file mode 100644 index 000000000000..d2d70d25850d --- /dev/null +++ b/docs/html/reference/images/graphics/blendmode_SCREEN.png diff --git a/docs/html/reference/images/graphics/blendmode_SOFT_LIGHT.png b/docs/html/reference/images/graphics/blendmode_SOFT_LIGHT.png Binary files differnew file mode 100644 index 000000000000..89fbacd24dcc --- /dev/null +++ b/docs/html/reference/images/graphics/blendmode_SOFT_LIGHT.png diff --git a/docs/html/reference/images/graphics/blendmode_SRC.png b/docs/html/reference/images/graphics/blendmode_SRC.png Binary files differnew file mode 100644 index 000000000000..990ec94301b3 --- /dev/null +++ b/docs/html/reference/images/graphics/blendmode_SRC.png diff --git a/docs/html/reference/images/graphics/blendmode_SRC_ATOP.png b/docs/html/reference/images/graphics/blendmode_SRC_ATOP.png Binary files differnew file mode 100644 index 000000000000..d574dfd923f2 --- /dev/null +++ b/docs/html/reference/images/graphics/blendmode_SRC_ATOP.png diff --git a/docs/html/reference/images/graphics/blendmode_SRC_IN.png b/docs/html/reference/images/graphics/blendmode_SRC_IN.png Binary files differnew file mode 100644 index 000000000000..dda45d7319a4 --- /dev/null +++ b/docs/html/reference/images/graphics/blendmode_SRC_IN.png diff --git a/docs/html/reference/images/graphics/blendmode_SRC_OUT.png b/docs/html/reference/images/graphics/blendmode_SRC_OUT.png Binary files differnew file mode 100644 index 000000000000..f5d43c103dc2 --- /dev/null +++ b/docs/html/reference/images/graphics/blendmode_SRC_OUT.png diff --git a/docs/html/reference/images/graphics/blendmode_SRC_OVER.png b/docs/html/reference/images/graphics/blendmode_SRC_OVER.png Binary files differnew file mode 100644 index 000000000000..b1a405bc878d --- /dev/null +++ b/docs/html/reference/images/graphics/blendmode_SRC_OVER.png diff --git a/docs/html/reference/images/graphics/blendmode_XOR.png b/docs/html/reference/images/graphics/blendmode_XOR.png Binary files differnew file mode 100644 index 000000000000..31c110d98d27 --- /dev/null +++ b/docs/html/reference/images/graphics/blendmode_XOR.png diff --git a/graphics/java/android/graphics/BaseCanvas.java b/graphics/java/android/graphics/BaseCanvas.java index 3db240b54299..ca9dc475f7a1 100644 --- a/graphics/java/android/graphics/BaseCanvas.java +++ b/graphics/java/android/graphics/BaseCanvas.java @@ -241,10 +241,22 @@ public abstract class BaseCanvas { nDrawColor(mNativeCanvasWrapper, color, PorterDuff.Mode.SRC_OVER.nativeInt); } + /** + * @deprecated use {@link Canvas#drawColor(int, BlendMode)} + */ + @Deprecated public void drawColor(@ColorInt int color, @NonNull PorterDuff.Mode mode) { nDrawColor(mNativeCanvasWrapper, color, mode.nativeInt); } + /** + * Make lint happy. + * See {@link Canvas#drawColor(int, BlendMode)} + */ + public void drawColor(@ColorInt int color, @NonNull BlendMode mode) { + nDrawColor(mNativeCanvasWrapper, color, mode.getXfermode().porterDuffMode); + } + public void drawLine(float startX, float startY, float stopX, float stopY, @NonNull Paint paint) { throwIfHasHwBitmapInSwMode(paint); diff --git a/graphics/java/android/graphics/BaseRecordingCanvas.java b/graphics/java/android/graphics/BaseRecordingCanvas.java index 4de7ca708eb6..901c2116884b 100644 --- a/graphics/java/android/graphics/BaseRecordingCanvas.java +++ b/graphics/java/android/graphics/BaseRecordingCanvas.java @@ -201,12 +201,21 @@ public class BaseRecordingCanvas extends Canvas { nDrawColor(mNativeCanvasWrapper, color, PorterDuff.Mode.SRC_OVER.nativeInt); } + /** + * @deprecated use {@link #drawColor(int, BlendMode)} instead + */ + @Deprecated @Override public final void drawColor(@ColorInt int color, @NonNull PorterDuff.Mode mode) { nDrawColor(mNativeCanvasWrapper, color, mode.nativeInt); } @Override + public final void drawColor(@ColorInt int color, @NonNull BlendMode mode) { + nDrawColor(mNativeCanvasWrapper, color, mode.getXfermode().porterDuffMode); + } + + @Override public final void drawLine(float startX, float startY, float stopX, float stopY, @NonNull Paint paint) { nDrawLine(mNativeCanvasWrapper, startX, startY, stopX, stopY, paint.getNativeInstance()); diff --git a/graphics/java/android/graphics/BlendMode.java b/graphics/java/android/graphics/BlendMode.java new file mode 100644 index 000000000000..39392c89d170 --- /dev/null +++ b/graphics/java/android/graphics/BlendMode.java @@ -0,0 +1,472 @@ +/* + * 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.graphics; + +import android.annotation.NonNull; +import android.annotation.Nullable; + +public enum BlendMode { + + /** + * <p> + * <img src="{@docRoot}reference/android/images/graphics/blendmode_CLEAR.png" /> + * <figcaption>Destination pixels covered by the source are cleared to 0.</figcaption> + * </p> + * <p>\(\alpha_{out} = 0\)</p> + * <p>\(C_{out} = 0\)</p> + */ + CLEAR(0), + + /** + * <p> + * <img src="{@docRoot}reference/android/images/graphics/blendmode_SRC.png" /> + * <figcaption>The source pixels replace the destination pixels.</figcaption> + * </p> + * <p>\(\alpha_{out} = \alpha_{src}\)</p> + * <p>\(C_{out} = C_{src}\)</p> + */ + SRC(1), + + /** + * <p> + * <img src="{@docRoot}reference/android/images/graphics/blendmode_DST.png" /> + * <figcaption>The source pixels are discarded, leaving the destination intact.</figcaption> + * </p> + * <p>\(\alpha_{out} = \alpha_{dst}\)</p> + * <p>\(C_{out} = C_{dst}\)</p> + */ + DST(2), + + /** + * <p> + * <img src="{@docRoot}reference/android/images/graphics/blendmode_SRC_OVER.png" /> + * <figcaption>The source pixels are drawn over the destination pixels.</figcaption> + * </p> + * <p>\(\alpha_{out} = \alpha_{src} + (1 - \alpha_{src}) * \alpha_{dst}\)</p> + * <p>\(C_{out} = C_{src} + (1 - \alpha_{src}) * C_{dst}\)</p> + */ + SRC_OVER(3), + + /** + * <p> + * <img src="{@docRoot}reference/android/images/graphics/blendmode_DST_OVER.png" /> + * <figcaption>The source pixels are drawn behind the destination pixels.</figcaption> + * </p> + * <p>\(\alpha_{out} = \alpha_{dst} + (1 - \alpha_{dst}) * \alpha_{src}\)</p> + * <p>\(C_{out} = C_{dst} + (1 - \alpha_{dst}) * C_{src}\)</p> + */ + DST_OVER(4), + + /** + * <p> + * <img src="{@docRoot}reference/android/images/graphics/blendmode_SRC_IN.png" /> + * <figcaption>Keeps the source pixels that cover the destination pixels, + * discards the remaining source and destination pixels.</figcaption> + * </p> + * <p>\(\alpha_{out} = \alpha_{src} * \alpha_{dst}\)</p> + * <p>\(C_{out} = C_{src} * \alpha_{dst}\)</p> + */ + SRC_IN(5), + + /** + * <p> + * <img src="{@docRoot}reference/android/images/graphics/blendmode_DST_IN.png" /> + * <figcaption>Keeps the destination pixels that cover source pixels, + * discards the remaining source and destination pixels.</figcaption> + * </p> + * <p>\(\alpha_{out} = \alpha_{src} * \alpha_{dst}\)</p> + * <p>\(C_{out} = C_{dst} * \alpha_{src}\)</p> + */ + DST_IN(6), + + /** + * <p> + * <img src="{@docRoot}reference/android/images/graphics/blendmode_SRC_OUT.png" /> + * <figcaption>Keeps the source pixels that do not cover destination pixels. + * Discards source pixels that cover destination pixels. Discards all + * destination pixels.</figcaption> + * </p> + * <p>\(\alpha_{out} = (1 - \alpha_{dst}) * \alpha_{src}\)</p> + * <p>\(C_{out} = (1 - \alpha_{dst}) * C_{src}\)</p> + */ + SRC_OUT(7), + + /** + * <p> + * <img src="{@docRoot}reference/android/images/graphics/blendmode_DST_OUT.png" /> + * <figcaption>Keeps the destination pixels that are not covered by source pixels. + * Discards destination pixels that are covered by source pixels. Discards all + * source pixels.</figcaption> + * </p> + * <p>\(\alpha_{out} = (1 - \alpha_{src}) * \alpha_{dst}\)</p> + * <p>\(C_{out} = (1 - \alpha_{src}) * C_{dst}\)</p> + */ + DST_OUT(8), + + /** + * <p> + * <img src="{@docRoot}reference/android/images/graphics/blendmode_SRC_ATOP.png" /> + * <figcaption>Discards the source pixels that do not cover destination pixels. + * Draws remaining source pixels over destination pixels.</figcaption> + * </p> + * <p>\(\alpha_{out} = \alpha_{dst}\)</p> + * <p>\(C_{out} = \alpha_{dst} * C_{src} + (1 - \alpha_{src}) * C_{dst}\)</p> + */ + SRC_ATOP(9), + + /** + * <p> + * <img src="{@docRoot}reference/android/images/graphics/blendmode_DST_ATOP.png" /> + * <figcaption>Discards the destination pixels that are not covered by source pixels. + * Draws remaining destination pixels over source pixels.</figcaption> + * </p> + * <p>\(\alpha_{out} = \alpha_{src}\)</p> + * <p>\(C_{out} = \alpha_{src} * C_{dst} + (1 - \alpha_{dst}) * C_{src}\)</p> + */ + DST_ATOP(10), + + /** + * <p> + * <img src="{@docRoot}reference/android/images/graphics/blendmode_XOR.png" /> + * <figcaption>Discards the source and destination pixels where source pixels + * cover destination pixels. Draws remaining source pixels.</figcaption> + * </p> + * <p> + * \(\alpha_{out} = (1 - \alpha_{dst}) * \alpha_{src} + (1 - \alpha_{src}) * \alpha_{dst}\) + * </p> + * <p>\(C_{out} = (1 - \alpha_{dst}) * C_{src} + (1 - \alpha_{src}) * C_{dst}\)</p> + */ + XOR(11), + + /** + * <p> + * <img src="{@docRoot}reference/android/images/graphics/blendmode_PLUS.png" /> + * <figcaption>Adds the source pixels to the destination pixels and saturates + * the result.</figcaption> + * </p> + * <p>\(\alpha_{out} = max(0, min(\alpha_{src} + \alpha_{dst}, 1))\)</p> + * <p>\(C_{out} = max(0, min(C_{src} + C_{dst}, 1))\)</p> + */ + PLUS(12), + + /** + * <p> + * <img src="{@docRoot}reference/android/images/graphics/blendmode_MODULATE.png" /> + * <figcaption>Multiplies the source and destination pixels.</figcaption> + * </p> + * <p>\(\alpha_{out} = \alpha_{src} * \alpha_{dst}\)</p> + * <p>\(C_{out} = C_{src} * C_{dst}\)</p> + * + */ + MODULATE(13), + + /** + * <p> + * <img src="{@docRoot}reference/android/images/graphics/blendmode_SCREEN.png" /> + * <figcaption> + * Adds the source and destination pixels, then subtracts the + * source pixels multiplied by the destination. + * </figcaption> + * </p> + * <p>\(\alpha_{out} = \alpha_{src} + \alpha_{dst} - \alpha_{src} * \alpha_{dst}\)</p> + * <p>\(C_{out} = C_{src} + C_{dst} - C_{src} * C_{dst}\)</p> + */ + SCREEN(14), + + /** + * <p> + * <img src="{@docRoot}reference/android/images/graphics/blendmode_OVERLAY.png" /> + * <figcaption> + * Multiplies or screens the source and destination depending on the + * destination color. + * </figcaption> + * </p> + * <p>\(\alpha_{out} = \alpha_{src} + \alpha_{dst} - \alpha_{src} * \alpha_{dst}\)</p> + * <p>\(\begin{equation} + * C_{out} = \begin{cases} 2 * C_{src} * C_{dst} & 2 * C_{dst} \lt \alpha_{dst} \\ + * \alpha_{src} * \alpha_{dst} - 2 (\alpha_{dst} - C_{src}) (\alpha_{src} - C_{dst}) & + * otherwise \end{cases} + * \end{equation}\)</p> + */ + OVERLAY(15), + + /** + * <p> + * <img src="{@docRoot}reference/android/images/graphics/blendmode_DARKEN.png" /> + * <figcaption> + * Retains the smallest component of the source and + * destination pixels. + * </figcaption> + * </p> + * <p>\(\alpha_{out} = \alpha_{src} + \alpha_{dst} - \alpha_{src} * \alpha_{dst}\)</p> + * <p> + * \(C_{out} = + * (1 - \alpha_{dst}) * C_{src} + (1 - \alpha_{src}) * C_{dst} + min(C_{src}, C_{dst})\) + * </p> + */ + DARKEN(16), + + /** + * <p> + * <img src="{@docRoot}reference/android/images/graphics/blendmode_LIGHTEN.png" /> + * <figcaption>Retains the largest component of the source and + * destination pixel.</figcaption> + * </p> + * <p>\(\alpha_{out} = \alpha_{src} + \alpha_{dst} - \alpha_{src} * \alpha_{dst}\)</p> + * <p> + * \(C_{out} = + * (1 - \alpha_{dst}) * C_{src} + (1 - \alpha_{src}) * C_{dst} + max(C_{src}, C_{dst})\) + * </p> + */ + LIGHTEN(17), + + /** + * <p> + * <img src="{@docRoot}reference/android/images/graphics/blendmode_COLOR_DODGE.png" /> + * <figcaption>Makes destination brighter to reflect source.</figcaption> + * </p> + * <p> + * \(\alpha_{out} = \alpha_{src} + \alpha_{dst} - \alpha_{src} * \alpha_{dst}\) + * </p> + * <p> + * \begin{equation} + * C_{out} = + * \begin{cases} + * C_{src} * (1 - \alpha_{dst}) & C_{dst} = 0 \\ + * C_{src} + \alpha_{dst}*(1 - \alpha_{src}) & C_{src} = \alpha_{src} \\ + * \alpha_{src} * min(\alpha_{dst}, C_{dst} * \alpha_{src}/(\alpha_{src} - C_{src})) + * + C_{src} *(1 - \alpha_{dst} + \alpha_{dst}*(1 - \alpha_{src}) & otherwise + * \end{cases} + * \end{equation} + * </p> + */ + COLOR_DODGE(18), + + /** + * <p> + * <img src="{@docRoot}reference/android/images/graphics/blendmode_COLOR_BURN.png" /> + * <figcaption>Makes destination darker to reflect source.</figcaption> + * </p> + * <p> + * \(\alpha_{out} = \alpha_{src} + \alpha_{dst} - \alpha_{src} * \alpha_{dst}\) + * </p> + * <p> + * \begin{equation} + * C_{out} = + * \begin{cases} + * C_{dst} + C_{src}*(1 - \alpha_{dst}) & C_{dst} = \alpha_{dst} \\ + * \alpha_{dst}*(1 - \alpha_{src}) & C_{src} = 0 \\ + * \alpha_{src}*(\alpha_{dst} - min(\alpha_{dst}, (\alpha_{dst} + * - C_{dst})*\alpha_{src}/C_{src})) + * + C_{src} * (1 - \alpha_{dst}) + \alpha_{dst}*(1-\alpha_{src}) & otherwise + * \end{cases} + * \end{equation} + * </p> + */ + COLOR_BURN(19), + + /** + * <p> + * <img src="{@docRoot}reference/android/images/graphics/blendmode_HARD_LIGHT.png" /> + * <figcaption>Makes destination lighter or darker, depending on source.</figcaption> + * </p> + * <p> + * \(\alpha_{out} = \alpha_{src} + \alpha_{dst} - \alpha_{src} * \alpha_{dst}\) + * </p> + * <p> + * \begin{equation} + * C_{out} = + * \begin{cases} + * 2*C_{src}*C_{dst} & C_{src}*(1-\alpha_{dst}) + C_{dst}*(1-\alpha_{src}) + 2*C_{src} + * \leq \alpha_{src} \\ + * \alpha_{src}*\alpha_{dst}- 2*(\alpha_{dst} - C_{dst})*(\alpha_{src} - C_{src}) + * & otherwise + * \end{cases} + * \end{equation} + * </p> + */ + HARD_LIGHT(20), + + /** + * <p> + * <img src="{@docRoot}reference/android/images/graphics/blendmode_SOFT_LIGHT.png" /> + * <figcaption>Makes destination lighter or darker, depending on source.</figcaption> + * </p> + * <p> + * Where + * \begin{equation} + * m = + * \begin{cases} + * C_{dst} / \alpha_{dst} & \alpha_{dst} \gt 0 \\ + * 0 & otherwise + * \end{cases} + * \end{equation} + * </p> + * <p> + * \begin{equation} + * g = + * \begin{cases} + * (16 * m * m + 4 * m) * (m - 1) + 7 * m & 4 * C_{dst} \leq \alpha_{dst} \\ + * \sqrt m - m & otherwise + * \end{cases} + * \end{equation} + * </p> + * <p> + * \begin{equation} + * f = + * \begin{cases} + * C_{dst} * (\alpha_{src} + (2 * C_{src} - \alpha_{src}) * (1 - m)) + * & 2 * C_{src} \leq \alpha_{src} \\ + * C_{dst} * \alpha_{src} + \alpha_{dst} * (2 * C_{src} - \alpha_{src}) * g + * & otherwise + * \end{cases} + * \end{equation} + * </p> + * <p> + * \begin{equation} + * \alpha_{out} = \alpha_{src} + \alpha_{dst} - \alpha_{src} * \alpha_{dst} + * \end{equation} + * \begin{equation} + * C_{out} = C_{src} / \alpha_{dst} + C_{dst} / \alpha_{src} + f + * \end{equation} + * </p> + */ + SOFT_LIGHT(21), + + /** + * <p> + * <img src="{@docRoot}reference/android/images/graphics/blendmode_DIFFERENCE.png" /> + * <figcaption>Subtracts darker from lighter with higher contrast.</figcaption> + * </p> + * <p> + * \begin{equation} + * \alpha_{out} = \alpha_{src} + \alpha_{dst} - \alpha_{src} * \alpha_{dst} + * \end{equation} + * </p> + * <p> + * \begin{equation} + * C_{out} = C_{src} + C_{dst} - 2 * min(C_{src} + * * \alpha_{dst}, C_{dst} * \alpha_{src}) + * \end{equation} + * </p> + */ + DIFFERENCE(22), + + /** + * <p> + * <img src="{@docRoot}reference/android/images/graphics/blendmode_DIFFERENCE.png" /> + * <figcaption>Subtracts darker from lighter with lower contrast.</figcaption> + * </p> + * <p> + * \begin{equation} + * \alpha_{out} = \alpha_{src} + \alpha_{dst} - \alpha_{src} * \alpha_{dst} + * \end{equation} + * </p> + * <p> + * \begin{equation} + * C_{out} = C_{src} + C_{dst} - 2 * C_{src} * C_{dst} + * \end{equation} + * </p> + */ + EXCLUSION(23), + + /** + * <p> + * <img src="{@docRoot}reference/android/images/graphics/blendmode_MODULATE.png" /> + * <figcaption>Multiplies the source and destination pixels.</figcaption> + * </p> + * <p>\(\alpha_{out} = \alpha_{src} + \alpha_{dst} - \alpha_{src} * \alpha_{dst}\)</p> + * <p>\(C_{out} = + * C_{src} * (1 - \alpha_{dst}) + C_{dst} * (1 - \alpha_{src}) + (C_{src} * C_{dst})\) + * </p> + */ + MULTIPLY(24), + + /** + * <p> + * <img src="{@docRoot}reference/android/images/graphics/blendmode_HUE.png" /> + * <figcaption> + * Replaces hue of destination with hue of source, leaving saturation + * and luminosity unchanged. + * </figcaption> + * </p> + */ + HUE(25), + + /** + * <p> + * <img src="{@docRoot}reference/android/images/graphics/blendmode_SATURATION.png" /> + * <figcaption> + * Replaces saturation of destination saturation hue of source, leaving hue and + * luminosity unchanged. + * </figcaption> + * </p> + */ + SATURATION(26), + + /** + * <p> + * <img src="{@docRoot}reference/android/images/graphics/blendmode_COLOR.png" /> + * <figcaption> + * Replaces hue and saturation of destination with hue and saturation of source, + * leaving luminosity unchanged. + * </figcaption> + * </p> + */ + COLOR(27), + + /** + * <p> + * <img src="{@docRoot}reference/android/images/graphics/blendmode_LUMINOSITY.png" /> + * <figcaption> + * Replaces luminosity of destination with luminosity of source, leaving hue and + * saturation unchanged. + * </figcaption> + * </p> + */ + LUMINOSITY(28); + + private static final BlendMode[] BLEND_MODES = values(); + + /** + * @hide + */ + public static @Nullable BlendMode fromValue(int value) { + for (BlendMode mode : BLEND_MODES) { + if (mode.mXfermode.porterDuffMode == value) { + return mode; + } + } + return null; + } + + @NonNull + private final Xfermode mXfermode; + + BlendMode(int mode) { + mXfermode = new Xfermode(); + mXfermode.porterDuffMode = mode; + } + + /** + * @hide + */ + @NonNull + public Xfermode getXfermode() { + return mXfermode; + } +} diff --git a/graphics/java/android/graphics/BlendModeColorFilter.java b/graphics/java/android/graphics/BlendModeColorFilter.java new file mode 100644 index 000000000000..7caeb4267ad2 --- /dev/null +++ b/graphics/java/android/graphics/BlendModeColorFilter.java @@ -0,0 +1,84 @@ +/* + * 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.graphics; + +import android.annotation.ColorInt; +import android.annotation.NonNull; + +/** + * A color filter that can be used to tint the source pixels using a single + * color and a specific {@link BlendMode}. + */ +public final class BlendModeColorFilter extends ColorFilter { + + @ColorInt final int mColor; + private final BlendMode mMode; + + public BlendModeColorFilter(@ColorInt int color, @NonNull BlendMode mode) { + mColor = color; + mMode = mode; + } + + + /** + * Returns the ARGB color used to tint the source pixels when this filter + * is applied. + * + * @see Color + * + */ + @ColorInt + public int getColor() { + return mColor; + } + + /** + * Returns the Porter-Duff mode used to composite this color filter's + * color with the source pixel when this filter is applied. + * + * @see BlendMode + * + */ + public BlendMode getMode() { + return mMode; + } + + @Override + long createNativeInstance() { + return native_CreateBlendModeFilter(mColor, mMode.getXfermode().porterDuffMode); + } + + @Override + public boolean equals(Object object) { + if (this == object) { + return true; + } + if (object == null || getClass() != object.getClass()) { + return false; + } + final BlendModeColorFilter other = (BlendModeColorFilter) object; + return other.mMode == mMode; + } + + @Override + public int hashCode() { + return 31 * mMode.hashCode() + mColor; + } + + private static native long native_CreateBlendModeFilter(int srcColor, int blendmode); + +} diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java index 135c13703131..6798ab216734 100644 --- a/graphics/java/android/graphics/Canvas.java +++ b/graphics/java/android/graphics/Canvas.java @@ -1684,12 +1684,26 @@ public class Canvas extends BaseCanvas { * * @param color the color to draw with * @param mode the porter-duff mode to apply to the color + * + * @deprecated use {@link #drawColor(int, BlendMode)} instead */ + @Deprecated public void drawColor(@ColorInt int color, @NonNull PorterDuff.Mode mode) { super.drawColor(color, mode); } /** + * Fill the entire canvas' bitmap (restricted to the current clip) with the specified color and + * blendmode. + * + * @param color the color to draw with + * @param mode the blendmode to apply to the color + */ + public void drawColor(@ColorInt int color, @NonNull BlendMode mode) { + super.drawColor(color, mode); + } + + /** * Draw a line segment with the specified start and stop x,y coordinates, using the specified * paint. * <p> diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java index 69ff3bca6528..6821282bd0a7 100644 --- a/graphics/java/android/graphics/Paint.java +++ b/graphics/java/android/graphics/Paint.java @@ -1168,12 +1168,29 @@ public class Paint { * Get the paint's transfer mode object. * * @return the paint's transfer mode (or null) + * + * @deprecated use {@link #getBlendMode()} instead */ + @Deprecated public Xfermode getXfermode() { return mXfermode; } /** + * Get the paint's blend mode object. + * + * @return the paint's blend mode (or null) + */ + @Nullable + public BlendMode getBlendMode() { + if (mXfermode == null) { + return null; + } else { + return BlendMode.fromValue(mXfermode.porterDuffMode); + } + } + + /** * Set or clear the transfer mode object. A transfer mode defines how * source pixels (generate by a drawing command) are composited with * the destination pixels (content of the render target). @@ -1185,8 +1202,17 @@ public class Paint { * * @param xfermode May be null. The xfermode to be installed in the paint * @return xfermode + * + * @deprecated Use {@link #setBlendMode} to apply a Xfermode directly + * through usage of {@link BlendMode} */ + @Deprecated public Xfermode setXfermode(Xfermode xfermode) { + return installXfermode(xfermode); + } + + @Nullable + private Xfermode installXfermode(Xfermode xfermode) { int newMode = xfermode != null ? xfermode.porterDuffMode : Xfermode.DEFAULT; int curMode = mXfermode != null ? mXfermode.porterDuffMode : Xfermode.DEFAULT; if (newMode != curMode) { @@ -1197,6 +1223,23 @@ public class Paint { } /** + * Set or clear the blend mode. A blend mode defines how source pixels + * (generated by a drawing command) are composited with the destination pixels + * (content of the render target). + * <p /> + * Pass null to clear any previous blend mode. + * As a convenience, the parameter passed is also returned. + * <p /> + * + * @see BlendMode + * + * @param blendmode May be null. The blend mode to be installed in the paint + */ + public void setBlendMode(@Nullable BlendMode blendmode) { + installXfermode(blendmode != null ? blendmode.getXfermode() : null); + } + + /** * Get the paint's patheffect object. * * @return the paint's patheffect (or null) diff --git a/graphics/java/android/graphics/PorterDuffColorFilter.java b/graphics/java/android/graphics/PorterDuffColorFilter.java index 6665220c293c..c2a8eb7dbab1 100644 --- a/graphics/java/android/graphics/PorterDuffColorFilter.java +++ b/graphics/java/android/graphics/PorterDuffColorFilter.java @@ -23,7 +23,11 @@ import android.annotation.UnsupportedAppUsage; /** * A color filter that can be used to tint the source pixels using a single * color and a specific {@link PorterDuff Porter-Duff composite mode}. + * + * @deprecated Consider using {@link BlendModeColorFilter} instead as it supports a wider + * set of blend modes than those defined in {@link PorterDuff.Mode} */ +@Deprecated public class PorterDuffColorFilter extends ColorFilter { @ColorInt private int mColor; @@ -71,7 +75,7 @@ public class PorterDuffColorFilter extends ColorFilter { @Override long createNativeInstance() { - return native_CreatePorterDuffFilter(mColor, mMode.nativeInt); + return native_CreateBlendModeFilter(mColor, mMode.nativeInt); } @Override @@ -91,5 +95,5 @@ public class PorterDuffColorFilter extends ColorFilter { return 31 * mMode.hashCode() + mColor; } - private static native long native_CreatePorterDuffFilter(int srcColor, int porterDuffMode); + private static native long native_CreateBlendModeFilter(int srcColor, int blendmode); } diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java index 5bd59d479876..09d0a581c2fc 100644 --- a/graphics/java/android/graphics/drawable/Drawable.java +++ b/graphics/java/android/graphics/drawable/Drawable.java @@ -595,7 +595,12 @@ public abstract class Drawable { * <p class="note"><strong>Note:</strong> Setting a color filter disables * {@link #setTintList(ColorStateList) tint}. * </p> + * + * @see {@link #setColorFilter(ColorFilter)} } + * @deprecated use {@link #setColorFilter(ColorFilter)} with an instance + * of {@link android.graphics.BlendModeColorFilter} */ + @Deprecated public void setColorFilter(@ColorInt int color, @NonNull PorterDuff.Mode mode) { if (getColorFilter() instanceof PorterDuffColorFilter) { PorterDuffColorFilter existing = (PorterDuffColorFilter) getColorFilter(); diff --git a/media/java/android/media/audiofx/AudioEffect.java b/media/java/android/media/audiofx/AudioEffect.java index 7480fa0f2101..52e9ae191f0c 100644 --- a/media/java/android/media/audiofx/AudioEffect.java +++ b/media/java/android/media/audiofx/AudioEffect.java @@ -25,10 +25,14 @@ import android.os.Build; import android.os.Handler; import android.os.Looper; import android.os.Message; +import android.os.Parcel; +import android.os.Parcelable; import android.util.Log; + import java.lang.ref.WeakReference; -import java.nio.ByteOrder; import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.Objects; import java.util.UUID; /** @@ -225,35 +229,12 @@ public class AudioEffect { * The method {@link #queryEffects()} returns an array of Descriptors to facilitate effects * enumeration. */ - public static class Descriptor { + public static final class Descriptor implements Parcelable { public Descriptor() { } /** - * @param type UUID identifying the effect type. May be one of: - * {@link AudioEffect#EFFECT_TYPE_AEC}, {@link AudioEffect#EFFECT_TYPE_AGC}, - * {@link AudioEffect#EFFECT_TYPE_BASS_BOOST}, {@link AudioEffect#EFFECT_TYPE_ENV_REVERB}, - * {@link AudioEffect#EFFECT_TYPE_EQUALIZER}, {@link AudioEffect#EFFECT_TYPE_NS}, - * {@link AudioEffect#EFFECT_TYPE_PRESET_REVERB}, - * {@link AudioEffect#EFFECT_TYPE_VIRTUALIZER}, - * {@link AudioEffect#EFFECT_TYPE_DYNAMICS_PROCESSING}. - * @param uuid UUID for this particular implementation - * @param connectMode {@link #EFFECT_INSERT} or {@link #EFFECT_AUXILIARY} - * @param name human readable effect name - * @param implementor human readable effect implementor name - * - */ - public Descriptor(String type, String uuid, String connectMode, - String name, String implementor) { - this.type = UUID.fromString(type); - this.uuid = UUID.fromString(uuid); - this.connectMode = connectMode; - this.name = name; - this.implementor = implementor; - } - - /** * Indicates the generic type of the effect (Equalizer, Bass boost ...). * One of {@link AudioEffect#EFFECT_TYPE_AEC}, * {@link AudioEffect#EFFECT_TYPE_AGC}, {@link AudioEffect#EFFECT_TYPE_BASS_BOOST}, @@ -289,7 +270,86 @@ public class AudioEffect { * Human readable effect implementor name */ public String implementor; - }; + + /** + * @param type UUID identifying the effect type. May be one of: + * {@link AudioEffect#EFFECT_TYPE_AEC}, {@link AudioEffect#EFFECT_TYPE_AGC}, + * {@link AudioEffect#EFFECT_TYPE_BASS_BOOST}, {@link AudioEffect#EFFECT_TYPE_ENV_REVERB}, + * {@link AudioEffect#EFFECT_TYPE_EQUALIZER}, {@link AudioEffect#EFFECT_TYPE_NS}, + * {@link AudioEffect#EFFECT_TYPE_PRESET_REVERB}, + * {@link AudioEffect#EFFECT_TYPE_VIRTUALIZER}, + * {@link AudioEffect#EFFECT_TYPE_DYNAMICS_PROCESSING}. + * @param uuid UUID for this particular implementation + * @param connectMode {@link #EFFECT_INSERT} or {@link #EFFECT_AUXILIARY} + * @param name human readable effect name + * @param implementor human readable effect implementor name + * + */ + public Descriptor(String type, String uuid, String connectMode, + String name, String implementor) { + this.type = UUID.fromString(type); + this.uuid = UUID.fromString(uuid); + this.connectMode = connectMode; + this.name = name; + this.implementor = implementor; + } + + private Descriptor(Parcel in) { + type = UUID.fromString(in.readString()); + uuid = UUID.fromString(in.readString()); + connectMode = in.readString(); + name = in.readString(); + implementor = in.readString(); + } + + public static final Parcelable.Creator<Descriptor> CREATOR = + new Parcelable.Creator<Descriptor>() { + /** + * Rebuilds a Descriptor previously stored with writeToParcel(). + * @param p Parcel object to read the Descriptor from + * @return a new Descriptor created from the data in the parcel + */ + public Descriptor createFromParcel(Parcel p) { + return new Descriptor(p); + } + public Descriptor[] newArray(int size) { + return new Descriptor[size]; + } + }; + + @Override + public int hashCode() { + return Objects.hash(type, uuid, connectMode, name, implementor); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(type.toString()); + dest.writeString(uuid.toString()); + dest.writeString(connectMode); + dest.writeString(name); + dest.writeString(implementor); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || !(o instanceof Descriptor)) return false; + + Descriptor that = (Descriptor) o; + + return (type.equals(that.type) + && uuid.equals(that.uuid) + && connectMode.equals(that.connectMode) + && name.equals(that.name) + && implementor.equals(that.implementor)); + } + } /** * Effect connection mode is insert. Specifying an audio session ID when creating the effect diff --git a/packages/CarSystemUI/Android.bp b/packages/CarSystemUI/Android.bp index f244f9f88684..74d6605a1ffb 100644 --- a/packages/CarSystemUI/Android.bp +++ b/packages/CarSystemUI/Android.bp @@ -26,6 +26,7 @@ android_app { ], static_libs: [ + "CarNotificationLib", "SystemUI-core", "SystemUIPluginLib", "SystemUISharedLib", diff --git a/packages/CarSystemUI/res/values/config.xml b/packages/CarSystemUI/res/values/config.xml index 452d61df5322..572737f92370 100644 --- a/packages/CarSystemUI/res/values/config.xml +++ b/packages/CarSystemUI/res/values/config.xml @@ -28,4 +28,31 @@ <bool name="config_enableRightNavigationBar">false</bool> <bool name="config_enableBottomNavigationBar">true</bool> + <!-- SystemUI Services: The classes of the stuff to start. This is duplicated from core + SystemUi b/c it can't be overlayed at this level for now + --> + <string-array name="config_systemUIServiceComponents" translatable="false"> + <item>com.android.systemui.Dependency</item> + <item>com.android.systemui.util.NotificationChannels</item> + <item>com.android.systemui.statusbar.CommandQueue$CommandQueueStart</item> + <item>com.android.systemui.keyguard.KeyguardViewMediator</item> + <item>com.android.systemui.recents.Recents</item> + <item>com.android.systemui.volume.VolumeUI</item> + <item>com.android.systemui.stackdivider.Divider</item> + <item>com.android.systemui.SystemBars</item> + <item>com.android.systemui.usb.StorageNotification</item> + <item>com.android.systemui.power.PowerUI</item> + <item>com.android.systemui.media.RingtonePlayer</item> + <item>com.android.systemui.keyboard.KeyboardUI</item> + <item>com.android.systemui.pip.PipUI</item> + <item>com.android.systemui.shortcut.ShortcutKeyDispatcher</item> + <item>@string/config_systemUIVendorServiceComponent</item> + <item>com.android.systemui.util.leak.GarbageMonitor$Service</item> + <item>com.android.systemui.LatencyTester</item> + <item>com.android.systemui.globalactions.GlobalActionsComponent</item> + <item>com.android.systemui.ScreenDecorations</item> + <item>com.android.systemui.fingerprint.FingerprintDialogImpl</item> + <item>com.android.systemui.SliceBroadcastRelayHandler</item> + <item>com.android.systemui.notifications.NotificationsUI</item> + </string-array> </resources> diff --git a/packages/CarSystemUI/src/com/android/systemui/notifications/NotificationsUI.java b/packages/CarSystemUI/src/com/android/systemui/notifications/NotificationsUI.java new file mode 100644 index 000000000000..cb92c4259504 --- /dev/null +++ b/packages/CarSystemUI/src/com/android/systemui/notifications/NotificationsUI.java @@ -0,0 +1,161 @@ +/* + * 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.systemui.notifications; + +import android.car.Car; +import android.car.CarNotConnectedException; +import android.car.drivingstate.CarUxRestrictionsManager; +import android.content.ComponentName; +import android.content.Context; +import android.content.ServiceConnection; +import android.graphics.PixelFormat; +import android.os.IBinder; +import android.util.Log; +import android.view.View; +import android.view.ViewGroup; +import android.view.WindowManager; + +import com.android.car.notification.CarNotificationListener; +import com.android.car.notification.CarUxRestrictionManagerWrapper; +import com.android.car.notification.NotificationViewController; +import com.android.car.notification.PreprocessingManager; +import com.android.systemui.R; +import com.android.systemui.SystemUI; + +/** + * Standalone SystemUI for displaying Notifications that have been designed to be used in the car + */ +public class NotificationsUI extends SystemUI { + + private static final String TAG = "NotificationsUI"; + private CarNotificationListener mCarNotificationListener; + private CarUxRestrictionsManager mCarUxRestrictionsManager; + private Car mCar; + private ViewGroup mCarNotificationWindow; + private NotificationViewController mNotificationViewController; + private boolean mIsShowing; + private CarUxRestrictionManagerWrapper mCarUxRestrictionManagerWrapper = + new CarUxRestrictionManagerWrapper(); + + /** + * Inits the window that hosts the notifications and establishes the connections + * to the car related services. + */ + @Override + public void start() { + WindowManager windowManager = + (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); + mCarNotificationListener = new CarNotificationListener(); + mCarNotificationListener.registerAsSystemService(mContext, mCarUxRestrictionManagerWrapper); + mCar = Car.createCar(mContext, mCarConnectionListener); + mCar.connect(); + + + mCarNotificationWindow = (ViewGroup) View.inflate(mContext, + R.layout.navigation_bar_window, null); + View.inflate(mContext, + com.android.car.notification.R.layout.notification_center_activity, + mCarNotificationWindow); + mCarNotificationWindow.findViewById( + com.android.car.notification.R.id.exit_button_container) + .setOnClickListener(v -> toggleShowingCarNotifications()); + + WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, + WindowManager.LayoutParams.TYPE_DISPLAY_OVERLAY, + WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE + | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL + | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH + | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH, + PixelFormat.TRANSLUCENT); + layoutParams.setTitle("Car Notification Window"); + // start in the hidden state + mCarNotificationWindow.setVisibility(View.GONE); + windowManager.addView(mCarNotificationWindow, layoutParams); + mNotificationViewController = new NotificationViewController( + mCarNotificationWindow + .findViewById(com.android.car.notification.R.id.notification_view), + PreprocessingManager.getInstance(mContext), + mCarNotificationListener, + mCarUxRestrictionManagerWrapper + ); + // Add to the SystemUI component registry + putComponent(NotificationsUI.class, this); + } + + /** + * Connection callback to establish UX Restrictions + */ + private ServiceConnection mCarConnectionListener = new ServiceConnection() { + @Override + public void onServiceConnected(ComponentName name, IBinder service) { + try { + mCarUxRestrictionsManager = (CarUxRestrictionsManager) mCar.getCarManager( + Car.CAR_UX_RESTRICTION_SERVICE); + mCarUxRestrictionManagerWrapper + .setCarUxRestrictionsManager(mCarUxRestrictionsManager); + PreprocessingManager preprocessingManager = PreprocessingManager.getInstance( + mContext); + preprocessingManager + .setCarUxRestrictionManagerWrapper(mCarUxRestrictionManagerWrapper); + } catch (CarNotConnectedException e) { + Log.e(TAG, "Car not connected in CarConnectionListener", e); + } + } + + @Override + public void onServiceDisconnected(ComponentName name) { + Log.e(TAG, "Car service disconnected unexpectedly"); + } + }; + + /** + * Toggles the visiblity of the notifications + */ + public void toggleShowingCarNotifications() { + if (mCarNotificationWindow.getVisibility() == View.VISIBLE) { + closeCarNotifications(); + return; + } + openCarNotifications(); + } + + /** + * Hides the notifications + */ + public void closeCarNotifications() { + mCarNotificationWindow.setVisibility(View.GONE); + mNotificationViewController.disable(); + mIsShowing = false; + } + + /** + * Sets the notifications to visible + */ + public void openCarNotifications() { + mCarNotificationWindow.setVisibility(View.VISIBLE); + mNotificationViewController.enable(); + mIsShowing = true; + } + + /** + * Returns {@code true} if notifications are currently on the screen + */ + public boolean isShowing() { + return mIsShowing; + } +} diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarView.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarView.java index 81f7846b357d..0cba351a8a9c 100644 --- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarView.java +++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarView.java @@ -21,7 +21,6 @@ import android.util.AttributeSet; import android.view.View; import android.widget.LinearLayout; -import com.android.keyguard.AlphaOptimizedImageButton; import com.android.systemui.Dependency; import com.android.systemui.R; import com.android.systemui.statusbar.phone.StatusBarIconController; @@ -34,7 +33,7 @@ import com.android.systemui.statusbar.phone.StatusBarIconController; */ class CarNavigationBarView extends LinearLayout { private View mNavButtons; - private AlphaOptimizedImageButton mNotificationsButton; + private CarFacetButton mNotificationsButton; private CarStatusBar mCarStatusBar; private Context mContext; private View mLockScreenButtons; @@ -71,7 +70,7 @@ class CarNavigationBarView extends LinearLayout { } protected void onNotificationsClick(View v) { - mCarStatusBar.togglePanel(); + mCarStatusBar.toggleCarNotifications(); } /** diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java index 2d90f8f0afd9..5da236ceb211 100644 --- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java +++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java @@ -35,6 +35,7 @@ import com.android.systemui.R; import com.android.systemui.classifier.FalsingLog; import com.android.systemui.classifier.FalsingManager; import com.android.systemui.fragments.FragmentHostManager; +import com.android.systemui.notifications.NotificationsUI; import com.android.systemui.plugins.qs.QS; import com.android.systemui.qs.car.CarQSFragment; import com.android.systemui.shared.system.ActivityManagerWrapper; @@ -587,4 +588,9 @@ public class CarStatusBar extends StatusBar implements private Drawable getDefaultWallpaper() { return mContext.getDrawable(com.android.internal.R.drawable.default_wallpaper); } + + public void toggleCarNotifications() { + getComponent(NotificationsUI.class).toggleShowingCarNotifications(); + } + } diff --git a/packages/ExtServices/AndroidManifest.xml b/packages/ExtServices/AndroidManifest.xml index ff70e9712bcc..010a810cd791 100644 --- a/packages/ExtServices/AndroidManifest.xml +++ b/packages/ExtServices/AndroidManifest.xml @@ -63,6 +63,13 @@ android:resource="@array/autofill_field_classification_available_algorithms" /> </service> + <service android:name=".sms.FinancialSmsServiceImpl" + android:permission="android.permission.BIND_FINANCIAL_SMS_SERVICE"> + <intent-filter> + <action android:name="android.service.sms.action.FINANCIAL_SERVICE_INTENT" /> + </intent-filter> + </service> + <library android:name="android.ext.services"/> </application> diff --git a/packages/ExtServices/src/android/ext/services/sms/FinancialSmsServiceImpl.java b/packages/ExtServices/src/android/ext/services/sms/FinancialSmsServiceImpl.java new file mode 100644 index 000000000000..ab71802102ae --- /dev/null +++ b/packages/ExtServices/src/android/ext/services/sms/FinancialSmsServiceImpl.java @@ -0,0 +1,80 @@ +/* + * 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.ext.services.sms; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.database.Cursor; +import android.database.CursorWindow; +import android.net.Uri; +import android.os.Bundle; +import android.service.sms.FinancialSmsService; +import android.util.Log; + +import java.util.ArrayList; +/** + * Service to provide financial apps access to sms messages. + */ +public class FinancialSmsServiceImpl extends FinancialSmsService { + + private static final String TAG = "FinancialSmsServiceImpl"; + private static final String KEY_COLUMN_NAMES = "column_names"; + + @Nullable + @Override + public CursorWindow onGetSmsMessages(@NonNull Bundle params) { + ArrayList<String> columnNames = params.getStringArrayList(KEY_COLUMN_NAMES); + if (columnNames == null || columnNames.size() <= 0) { + return null; + } + + Uri inbox = Uri.parse("content://sms/inbox"); + + try (Cursor cursor = getContentResolver().query(inbox, null, null, null, null); + CursorWindow window = new CursorWindow("FinancialSmsMessages")) { + int messageCount = cursor.getCount(); + if (messageCount > 0 && cursor.moveToFirst()) { + window.setNumColumns(columnNames.size()); + for (int row = 0; row < messageCount; row++) { + if (!window.allocRow()) { + Log.e(TAG, "CursorWindow ran out of memory."); + return null; + } + for (int col = 0; col < columnNames.size(); col++) { + String columnName = columnNames.get(col); + int inboxColumnIndex = cursor.getColumnIndexOrThrow(columnName); + String inboxColumnValue = cursor.getString(inboxColumnIndex); + boolean addedToCursorWindow = window.putString(inboxColumnValue, row, col); + if (!addedToCursorWindow) { + Log.e(TAG, "Failed to add:" + + inboxColumnValue + + ";column:" + + columnName); + return null; + } + } + cursor.moveToNext(); + } + } else { + Log.w(TAG, "No sms messages."); + } + return window; + } catch (Exception e) { + Log.e(TAG, "Failed to get sms messages."); + return null; + } + } +} diff --git a/packages/ExtServices/tests/src/android/ext/services/sms/FinancialSmsServiceImplTest.java b/packages/ExtServices/tests/src/android/ext/services/sms/FinancialSmsServiceImplTest.java new file mode 100644 index 000000000000..12575a63d0ad --- /dev/null +++ b/packages/ExtServices/tests/src/android/ext/services/sms/FinancialSmsServiceImplTest.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.ext.services.sms; + +import static com.google.common.truth.Truth.assertThat; + +import android.os.Bundle; + +import org.junit.Test; + +/** + * Contains the base tests for FinancialSmsServiceImpl. + */ +public class FinancialSmsServiceImplTest { + + private final FinancialSmsServiceImpl mService = new FinancialSmsServiceImpl(); + + @Test + public void testOnGetSmsMessages_nullWithNoParamData() { + assertThat(mService.onGetSmsMessages(new Bundle())).isNull(); + } +} diff --git a/packages/SystemUI/res/layout/qs_detail.xml b/packages/SystemUI/res/layout/qs_detail.xml index 0b9a7b226105..294bd50fcf8b 100644 --- a/packages/SystemUI/res/layout/qs_detail.xml +++ b/packages/SystemUI/res/layout/qs_detail.xml @@ -24,7 +24,8 @@ android:orientation="vertical" android:paddingBottom="8dp" android:visibility="invisible" - android:elevation="4dp" > + android:elevation="4dp" + android:importantForAccessibility="no" > <include android:id="@+id/qs_detail_header" diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 3851190fdeec..6037dfc5154d 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -24,7 +24,7 @@ <!-- Minimum swipe distance to catch the swipe gestures to invoke assist or switch tasks. --> <dimen name="navigation_bar_min_swipe_distance">48dp</dimen> <!-- The distance from a side of device of the navigation bar to start an edge swipe --> - <dimen name="navigation_bar_edge_swipe_threshold">60dp</dimen> + <dimen name="navigation_bar_edge_swipe_threshold">48dp</dimen> <!-- thickness (height) of the dead zone at the top of the navigation bar, reducing false presses on navbar buttons; approx 2mm --> diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index fede934d7369..87155c4d41a2 100644 --- a/packages/SystemUI/res/values/styles.xml +++ b/packages/SystemUI/res/values/styles.xml @@ -144,7 +144,7 @@ <item name="android:textSize">@dimen/qs_time_expanded_size</item> <item name="android:textStyle">normal</item> <item name="android:textColor">?android:attr/textColorPrimary</item> - <item name="android:fontFamily">sans-serif</item> + <item name="android:fontFamily">@*android:string/config_bodyFontFamily</item> </style> <style name="TextAppearance.StatusBar.Expanded.AboveDateTime"> @@ -171,12 +171,12 @@ <style name="TextAppearance.QS"> <item name="android:textStyle">normal</item> <item name="android:textColor">?android:attr/textColorPrimary</item> - <item name="android:fontFamily">sans-serif</item> + <item name="android:fontFamily">@*android:string/config_bodyFontFamily</item> </style> <style name="TextAppearance.QS.DetailHeader"> <item name="android:textSize">@dimen/qs_detail_header_text_size</item> - <item name="android:fontFamily">sans-serif-medium</item> + <item name="android:fontFamily">@*android:string/config_bodyFontFamilyMedium</item> </style> <style name="TextAppearance.QS.DetailItemPrimary"> @@ -202,7 +202,7 @@ <item name="android:textSize">@dimen/qs_detail_button_text_size</item> <item name="android:textColor">?android:attr/textColorSecondary</item> <item name="android:textAllCaps">true</item> - <item name="android:fontFamily">sans-serif-medium</item> + <item name="android:fontFamily">@*android:string/config_bodyFontFamilyMedium</item> <item name="android:gravity">center</item> </style> @@ -222,7 +222,7 @@ <style name="TextAppearance.QS.SegmentedButton"> <item name="android:textSize">16sp</item> - <item name="android:fontFamily">sans-serif-medium</item> + <item name="android:fontFamily">@*android:string/config_bodyFontFamilyMedium</item> </style> <style name="TextAppearance.QS.DataUsage"> @@ -245,7 +245,7 @@ <style name="TextAppearance.QS.TileLabel.Secondary"> <item name="android:textSize">@dimen/qs_tile_text_size</item> - <item name="android:fontFamily">sans-serif</item> + <item name="android:fontFamily">@*android:string/config_bodyFontFamily</item> </style> <style name="TextAppearance.QS.CarrierInfo"> @@ -262,7 +262,7 @@ <style name="TextAppearance.AppOpsDialog.Item"> <item name="android:textSize">@dimen/ongoing_appops_dialog_item_size</item> - <item name="android:fontFamily">sans-serif</item> + <item name="android:fontFamily">@*android:string/config_bodyFontFamily</item> </style> <style name="BaseBrightnessDialogContainer" parent="@style/Theme.SystemUI"> @@ -391,7 +391,7 @@ <style name="TextAppearance.Volume"> <item name="android:textStyle">normal</item> <item name="android:textColor">?android:attr/textColorPrimary</item> - <item name="android:fontFamily">sans-serif</item> + <item name="android:fontFamily">@*android:string/config_bodyFontFamily</item> </style> <style name="TextAppearance.Volume.Header"> @@ -435,7 +435,7 @@ </style> <style name="TextAppearance.NotificationInfo"> - <item name="android:fontFamily">sans-serif</item> + <item name="android:fontFamily">@*android:string/config_bodyFontFamily</item> <item name="android:textColor">@color/notification_primary_text_color</item> </style> @@ -463,7 +463,7 @@ </style> <style name="TextAppearance.NotificationInfo.Button"> - <item name="android:fontFamily">sans-serif-medium</item> + <item name="android:fontFamily">@*android:string/config_bodyFontFamilyMedium</item> <item name="android:textSize">14sp</item> <item name="android:textColor">?android:attr/colorAccent</item> <item name="android:background">@drawable/btn_borderless_rect</item> diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java index 32fd2dcedd0e..bfcf0214dd05 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java @@ -19,6 +19,7 @@ import android.animation.ValueAnimator; import android.content.Context; import android.content.res.ColorStateList; import android.content.res.TypedArray; +import android.graphics.Color; import android.graphics.Path; import android.graphics.drawable.AdaptiveIconDrawable; import android.graphics.drawable.Drawable; @@ -88,6 +89,7 @@ public class QSTileBaseView extends com.android.systemui.plugins.qs.QSTileView { float pathSize = AdaptiveIconDrawable.MASK_SIZE; PathShape p = new PathShape(path, pathSize, pathSize); ShapeDrawable d = new ShapeDrawable(p); + d.setTintList(ColorStateList.valueOf(Color.TRANSPARENT)); int bgSize = context.getResources().getDimensionPixelSize(R.dimen.qs_tile_background_size); d.setIntrinsicHeight(bgSize); d.setIntrinsicWidth(bgSize); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java index 6cec36a81e5a..91b34fc875bf 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java @@ -916,6 +916,10 @@ public class NotificationShelf extends ActivatableNotificationView implements updateRelativeOffset(); } + public void onUiModeChanged() { + updateBackgroundColors(); + } + private class ShelfState extends ExpandableViewState { private float openedAmount; private boolean hasItemsInStableShelf; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java index 7876b24112e0..1d79152bb1cc 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java @@ -225,7 +225,7 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView initDimens(); } - public void onUiModeChanged() { + protected void updateBackgroundColors() { updateColors(); initBackground(); updateBackgroundTint(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java index 8bed3663cf49..383446c00d37 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java @@ -121,6 +121,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView private static final int MENU_VIEW_INDEX = 0; private static final String TAG = "ExpandableNotifRow"; public static final float DEFAULT_HEADER_VISIBLE_AMOUNT = 1.0f; + private boolean mUpdateBackgroundOnUpdate; /** * Listener for when {@link ExpandableNotificationRow} is laid out. @@ -587,6 +588,10 @@ public class ExpandableNotificationRow extends ActivatableNotificationView updateIconVisibilities(); updateShelfIconColor(); updateRippleAllowed(); + if (mUpdateBackgroundOnUpdate) { + mUpdateBackgroundOnUpdate = false; + updateBackgroundColors(); + } } /** Called when the notification's ranking was changed (but nothing else changed). */ @@ -1212,9 +1217,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView } } - @Override public void onUiModeChanged() { - super.onUiModeChanged(); + mUpdateBackgroundOnUpdate = true; reInflateViews(); if (mChildrenContainer != null) { for (ExpandableNotificationRow child : mChildrenContainer.getNotificationChildren()) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java index eca1a1411212..dbe6e8ec764d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java @@ -641,15 +641,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd public void onUiModeChanged() { mBgColor = mContext.getColor(R.color.notification_shade_background_color); updateBackgroundDimming(); - - // Re-inflate all notification views - int childCount = getChildCount(); - for (int i = 0; i < childCount; i++) { - View child = getChildAt(i); - if (child instanceof ActivatableNotificationView) { - ((ActivatableNotificationView) child).onUiModeChanged(); - } - } + mShelf.onUiModeChanged(); } @ShadeViewRefactor(RefactorComponent.DECORATOR) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java index a2a11bbfd650..c7e4d340b7d8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java @@ -105,10 +105,22 @@ public class NotificationPanelView extends PanelView implements private static final boolean DEBUG = false; - private static final boolean EXPAND_ON_WAKE_UP = SystemProperties.getBoolean( + /** + * If passive interrupts expand the NSSL or not + */ + private static final boolean EXPAND_ON_PASSIVE_INTERRUPT = SystemProperties.getBoolean( "persist.sysui.expand_shade_on_wake_up", true); + /** + * If the notification panel should remain collapsed when the phone wakes up, even if the user + * presses power. + */ + private static final boolean NEVER_EXPAND_WHEN_WAKING_UP = SystemProperties.getBoolean( + "persist.sysui.defer_notifications_on_lock_screen", false); + /** + * If waking up the phone should take you to SHADE_LOCKED instead of KEYGUARD + */ private static final boolean WAKE_UP_TO_SHADE = SystemProperties.getBoolean( - "persist.sysui.go_to_shade_on_wake_up", true); + "persist.sysui.go_to_shade_on_wake_up", false); /** * Fling expanding QS. @@ -2774,10 +2786,12 @@ public class NotificationPanelView extends PanelView implements } public void setDozing(boolean dozing, boolean animate, PointF wakeUpTouchLocation, - boolean passiveInterrupted) { + boolean passivelyInterrupted) { if (dozing == mDozing) return; mDozing = dozing; - mSemiAwake = !EXPAND_ON_WAKE_UP && !mDozing && passiveInterrupted; + boolean doNotExpand = (!EXPAND_ON_PASSIVE_INTERRUPT && passivelyInterrupted) + || NEVER_EXPAND_WHEN_WAKING_UP; + mSemiAwake = doNotExpand && !mDozing; if (!mSemiAwake) { mNotificationStackScroller.setDark(mDozing, animate, wakeUpTouchLocation); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java index acdd5e995322..261f117b58b4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java @@ -67,6 +67,8 @@ import com.android.systemui.statusbar.notification.stack.NotificationListContain import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.KeyguardMonitor; +import java.util.ArrayList; + public class StatusBarNotificationPresenter implements NotificationPresenter, ConfigurationController.ConfigurationListener { @@ -105,6 +107,7 @@ public class StatusBarNotificationPresenter implements NotificationPresenter, private final int mMaxAllowedKeyguardNotifications; private final IStatusBarService mBarService; private boolean mReinflateNotificationsOnUserSwitched; + private boolean mDispatchUiModeChangeOnUserSwitched; private final UnlockMethodCache mUnlockMethodCache; private TextView mNotificationPanelDebugText; @@ -187,6 +190,27 @@ public class StatusBarNotificationPresenter implements NotificationPresenter, } @Override + public void onUiModeChanged() { + if (!KeyguardUpdateMonitor.getInstance(mContext).isSwitchingUser()) { + updateNotificationOnUiModeChanged(); + } else { + mDispatchUiModeChangeOnUserSwitched = true; + } + } + + private void updateNotificationOnUiModeChanged() { + ArrayList<Entry> userNotifications + = mEntryManager.getNotificationData().getNotificationsForCurrentUser(); + for (int i = 0; i < userNotifications.size(); i++) { + Entry entry = userNotifications.get(i); + ExpandableNotificationRow row = entry.getRow(); + if (row != null) { + row.onUiModeChanged(); + } + } + } + + @Override public boolean isCollapsing() { return mNotificationPanel.isCollapsing() || mActivityLaunchAnimator.isAnimationPending() @@ -301,6 +325,10 @@ public class StatusBarNotificationPresenter implements NotificationPresenter, mEntryManager.updateNotificationsOnDensityOrFontScaleChanged(); mReinflateNotificationsOnUserSwitched = false; } + if (mDispatchUiModeChangeOnUserSwitched) { + updateNotificationOnUiModeChanged(); + mDispatchUiModeChangeOnUserSwitched = false; + } updateNotificationViews(); mMediaManager.clearCurrentMediaNotification(); mShadeController.setLockscreenUser(newUserId); diff --git a/proto/src/metrics_constants/metrics_constants.proto b/proto/src/metrics_constants/metrics_constants.proto index 2d3064017719..eb0090be4747 100644 --- a/proto/src/metrics_constants/metrics_constants.proto +++ b/proto/src/metrics_constants/metrics_constants.proto @@ -6637,6 +6637,11 @@ message MetricsEvent { // OS: Q SETTINGS_WIFI_DPP_ENROLLEE = 1596; + // OPEN: Settings > Apps & Notifications -> Special app access -> Financial Apps Sms Access + // CATEGORY: SETTINGS + // OS: Q + SETTINGS_FINANCIAL_APPS_SMS_ACCESS = 1597; + // ---- End Q Constants, all Q constants go above this line ---- // Add new aosp constants above this line. diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index eda9fe15fe36..89194e43bf95 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -1968,6 +1968,7 @@ public class ConnectivityService extends IConnectivityManager.Stub void systemReady() { mProxyTracker.loadGlobalProxy(); registerNetdEventCallback(); + mTethering.systemReady(); synchronized (this) { mSystemReady = true; diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java index 5901ece7d89e..33a74d35cf85 100644 --- a/services/core/java/com/android/server/StorageManagerService.java +++ b/services/core/java/com/android/server/StorageManagerService.java @@ -19,7 +19,11 @@ package com.android.server; import static android.Manifest.permission.INSTALL_PACKAGES; import static android.Manifest.permission.WRITE_MEDIA_STORAGE; import static android.app.AppOpsManager.MODE_ALLOWED; +import static android.app.AppOpsManager.OP_LEGACY_STORAGE; import static android.app.AppOpsManager.OP_REQUEST_INSTALL_PACKAGES; +import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE; +import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE; +import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.os.ParcelFileDescriptor.MODE_READ_ONLY; import static android.os.ParcelFileDescriptor.MODE_READ_WRITE; @@ -32,9 +36,11 @@ import static android.os.storage.OnObbStateChangeListener.ERROR_PERMISSION_DENIE import static android.os.storage.OnObbStateChangeListener.MOUNTED; import static android.os.storage.OnObbStateChangeListener.UNMOUNTED; +import static com.android.internal.util.XmlUtils.readBooleanAttribute; import static com.android.internal.util.XmlUtils.readIntAttribute; import static com.android.internal.util.XmlUtils.readLongAttribute; import static com.android.internal.util.XmlUtils.readStringAttribute; +import static com.android.internal.util.XmlUtils.writeBooleanAttribute; import static com.android.internal.util.XmlUtils.writeIntAttribute; import static com.android.internal.util.XmlUtils.writeLongAttribute; import static com.android.internal.util.XmlUtils.writeStringAttribute; @@ -58,6 +64,7 @@ import android.content.IntentFilter; import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; import android.content.pm.IPackageMoveObserver; +import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; import android.content.pm.ProviderInfo; @@ -129,6 +136,7 @@ import com.android.internal.os.FuseUnavailableMountException; import com.android.internal.os.SomeArgs; import com.android.internal.os.Zygote; import com.android.internal.util.ArrayUtils; +import com.android.internal.util.CollectionUtils; import com.android.internal.util.DumpUtils; import com.android.internal.util.FastXmlSerializer; import com.android.internal.util.HexDump; @@ -211,7 +219,9 @@ class StorageManagerService extends IStorageManager.Stub @Override public void onBootPhase(int phase) { - if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) { + if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) { + mStorageManagerService.servicesReady(); + } else if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) { mStorageManagerService.systemReady(); } else if (phase == SystemService.PHASE_BOOT_COMPLETED) { mStorageManagerService.bootCompleted(); @@ -268,6 +278,7 @@ class StorageManagerService extends IStorageManager.Stub private static final String TAG_VOLUMES = "volumes"; private static final String ATTR_VERSION = "version"; private static final String ATTR_PRIMARY_STORAGE_UUID = "primaryStorageUuid"; + private static final String ATTR_ISOLATED_STORAGE = "isolatedStorage"; private static final String TAG_VOLUME = "volume"; private static final String ATTR_TYPE = "type"; private static final String ATTR_FS_UUID = "fsUuid"; @@ -318,6 +329,10 @@ class StorageManagerService extends IStorageManager.Stub @GuardedBy("mLock") private String mPrimaryStorageUuid; + /** Flag indicating isolated storage state of last boot */ + @GuardedBy("mLock") + private boolean mLastIsolatedStorage = false; + /** Map from disk ID to latches */ @GuardedBy("mLock") private ArrayMap<String, CountDownLatch> mDiskScanLatches = new ArrayMap<>(); @@ -1575,6 +1590,74 @@ class StorageManagerService extends IStorageManager.Stub } } + private void servicesReady() { + synchronized (mLock) { + final boolean thisIsolatedStorage = StorageManager.hasIsolatedStorage(); + if (mLastIsolatedStorage == thisIsolatedStorage) { + // Nothing changed since last boot; keep rolling forward + return; + } else if (thisIsolatedStorage) { + // This boot enables isolated storage; apply legacy behavior + applyLegacyStorage(); + } + + // Always remember the new state we just booted with + writeSettingsLocked(); + } + } + + /** + * If we're enabling isolated storage, we need to remember which existing + * apps have already been using shared storage, and grant them legacy access + * to keep them running smoothly. + */ + private void applyLegacyStorage() { + final AppOpsManager appOps = mContext.getSystemService(AppOpsManager.class); + final UserManagerInternal um = LocalServices.getService(UserManagerInternal.class); + for (int userId : um.getUserIds()) { + final PackageManager pm; + try { + pm = mContext.createPackageContextAsUser(mContext.getPackageName(), + 0, UserHandle.of(userId)).getPackageManager(); + } catch (PackageManager.NameNotFoundException e) { + throw new RuntimeException(e); + } + + final List<PackageInfo> pkgs = pm.getPackagesHoldingPermissions(new String[] { + android.Manifest.permission.READ_EXTERNAL_STORAGE, + android.Manifest.permission.WRITE_EXTERNAL_STORAGE + }, MATCH_UNINSTALLED_PACKAGES | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE); + for (PackageInfo pkg : pkgs) { + final int uid = pkg.applicationInfo.uid; + final String packageName = pkg.applicationInfo.packageName; + + final long lastAccess = getLastAccessTime(appOps, uid, packageName, new int[] { + AppOpsManager.OP_READ_EXTERNAL_STORAGE, + AppOpsManager.OP_WRITE_EXTERNAL_STORAGE, + }); + + Log.d(TAG, "Found " + uid + " " + packageName + + " with granted storage access, last accessed " + lastAccess); + if (lastAccess > 0) { + appOps.setMode(AppOpsManager.OP_LEGACY_STORAGE, + uid, packageName, AppOpsManager.MODE_ALLOWED); + } + } + } + } + + private static long getLastAccessTime(AppOpsManager manager, + int uid, String packageName, int[] ops) { + long maxTime = 0; + final List<AppOpsManager.PackageOps> pkgs = manager.getOpsForPackage(uid, packageName, ops); + for (AppOpsManager.PackageOps pkg : CollectionUtils.defeatNullable(pkgs)) { + for (AppOpsManager.OpEntry op : CollectionUtils.defeatNullable(pkg.getOps())) { + maxTime = Math.max(maxTime, op.getLastAccessTime()); + } + } + return maxTime; + } + private void systemReady() { LocalServices.getService(ActivityTaskManagerInternal.class) .registerScreenObserver(this); @@ -1603,6 +1686,7 @@ class StorageManagerService extends IStorageManager.Stub private void readSettingsLocked() { mRecords.clear(); mPrimaryStorageUuid = getDefaultPrimaryStorageUuid(); + mLastIsolatedStorage = false; FileInputStream fis = null; try { @@ -1624,6 +1708,8 @@ class StorageManagerService extends IStorageManager.Stub mPrimaryStorageUuid = readStringAttribute(in, ATTR_PRIMARY_STORAGE_UUID); } + mLastIsolatedStorage = readBooleanAttribute(in, + ATTR_ISOLATED_STORAGE, false); } else if (TAG_VOLUME.equals(tag)) { final VolumeRecord rec = readVolumeRecord(in); @@ -1654,6 +1740,7 @@ class StorageManagerService extends IStorageManager.Stub out.startTag(null, TAG_VOLUMES); writeIntAttribute(out, ATTR_VERSION, VERSION_FIX_PRIMARY); writeStringAttribute(out, ATTR_PRIMARY_STORAGE_UUID, mPrimaryStorageUuid); + writeBooleanAttribute(out, ATTR_ISOLATED_STORAGE, StorageManager.hasIsolatedStorage()); final int size = mRecords.size(); for (int i = 0; i < size; i++) { final VolumeRecord rec = mRecords.valueAt(i); @@ -2920,7 +3007,7 @@ class StorageManagerService extends IStorageManager.Stub } if (!foundPrimary) { - Log.w(TAG, "No primary storage defined yet; hacking together a stub"); + Slog.w(TAG, "No primary storage defined yet; hacking together a stub"); final boolean primaryPhysical = SystemProperties.getBoolean( StorageManager.PROP_PRIMARY_PHYSICAL, false); @@ -3505,6 +3592,10 @@ class StorageManagerService extends IStorageManager.Stub if (mIPackageManager.checkUidPermission(WRITE_MEDIA_STORAGE, uid) == PERMISSION_GRANTED) { return Zygote.MOUNT_EXTERNAL_FULL; + } else if (mIAppOpsService.checkOperation(OP_LEGACY_STORAGE, uid, + packageName) == MODE_ALLOWED) { + // TODO: define a specific "legacy" mount mode + return Zygote.MOUNT_EXTERNAL_FULL; } else if (mIPackageManager.checkUidPermission(INSTALL_PACKAGES, uid) == PERMISSION_GRANTED || mIAppOpsService.checkOperation( OP_REQUEST_INSTALL_PACKAGES, uid, packageName) == MODE_ALLOWED) { diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index f7acf7e83200..8751d24bcf67 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -2019,6 +2019,13 @@ public final class ActiveServices { ComponentName className = new ComponentName( sInfo.applicationInfo.packageName, sInfo.name); ComponentName name = comp != null ? comp : className; + if (!mAm.validateAssociationAllowedLocked(callingPackage, callingUid, + name.getPackageName(), sInfo.applicationInfo.uid)) { + String msg = "association not allowed between packages " + + callingPackage + " and " + r.packageName; + Slog.w(TAG, "Service lookup failed: " + msg); + return new ServiceLookupResult(null, msg); + } if ((sInfo.flags & ServiceInfo.FLAG_EXTERNAL_SERVICE) != 0) { if (isBindExternal) { if (!sInfo.exported) { @@ -2099,6 +2106,17 @@ public final class ActiveServices { } } if (r != null) { + if (!mAm.validateAssociationAllowedLocked(callingPackage, callingUid, r.packageName, + r.appInfo.uid)) { + String msg = "association not allowed between packages " + + callingPackage + " and " + r.packageName; + Slog.w(TAG, "Service lookup failed: " + msg); + return new ServiceLookupResult(null, msg); + } + if (!mAm.mIntentFirewall.checkService(r.name, service, callingUid, callingPid, + resolvedType, r.appInfo)) { + return new ServiceLookupResult(null, "blocked by firewall"); + } if (mAm.checkComponentPermission(r.permission, callingPid, callingUid, r.appInfo.uid, r.exported) != PERMISSION_GRANTED) { if (!r.exported) { @@ -2125,11 +2143,6 @@ public final class ActiveServices { return null; } } - - if (!mAm.mIntentFirewall.checkService(r.name, service, callingUid, callingPid, - resolvedType, r.appInfo)) { - return null; - } return new ServiceLookupResult(r, null); } return null; diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 8ce37a50557b..6700a530edc0 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -658,6 +658,12 @@ public class ActivityManagerService extends IActivityManager.Stub ArraySet<String> mBackgroundLaunchBroadcasts; /** + * When an app has restrictions on the other apps that can have associations with it, + * it appears here with a set of the allowed apps. + */ + ArrayMap<String, ArraySet<String>> mAllowedAssociations; + + /** * All of the processes we currently have running organized by pid. * The keys are the pid running the application. * @@ -2396,6 +2402,34 @@ public class ActivityManagerService extends IActivityManager.Stub return mBackgroundLaunchBroadcasts; } + boolean validateAssociationAllowedLocked(String pkg1, int uid1, String pkg2, int uid2) { + if (mAllowedAssociations == null) { + mAllowedAssociations = SystemConfig.getInstance().getAllowedAssociations(); + } + // Interactions with the system uid are always allowed, since that is the core system + // that everyone needs to be able to interact with. + if (UserHandle.getAppId(uid1) == SYSTEM_UID) { + return true; + } + if (UserHandle.getAppId(uid2) == SYSTEM_UID) { + return true; + } + // We won't allow this association if either pkg1 or pkg2 has a limit on the + // associations that are allowed with it, and the other package is not explicitly + // specified as one of those associations. + ArraySet<String> pkgs = mAllowedAssociations.get(pkg1); + if (pkgs != null) { + if (!pkgs.contains(pkg2)) { + return false; + } + } + pkgs = mAllowedAssociations.get(pkg2); + if (pkgs != null) { + return pkgs.contains(pkg1); + } + return true; + } + @Override public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { @@ -6264,6 +6298,21 @@ public class ActivityManagerService extends IActivityManager.Stub return state != 'Z' && state != 'X' && state != 'x' && state != 'K'; } + private String checkContentProviderAssociation(ProcessRecord callingApp, int callingUid, + ProviderInfo cpi) { + if (callingApp == null) { + return validateAssociationAllowedLocked(cpi.packageName, cpi.applicationInfo.uid, + null, callingUid) ? null : "<null>"; + } + for (int i = callingApp.pkgList.size() - 1; i >= 0; i--) { + if (!validateAssociationAllowedLocked(callingApp.pkgList.keyAt(i), callingApp.uid, + cpi.packageName, cpi.applicationInfo.uid)) { + return cpi.packageName; + } + } + return null; + } + private ContentProviderHolder getContentProviderImpl(IApplicationThread caller, String name, IBinder token, int callingUid, String callingTag, boolean stable, int userId) { @@ -6335,6 +6384,11 @@ public class ActivityManagerService extends IActivityManager.Stub String msg; if (r != null && cpr.canRunHere(r)) { + if ((msg = checkContentProviderAssociation(r, callingUid, cpi)) != null) { + throw new SecurityException("Content provider lookup " + + cpr.name.flattenToShortString() + + " failed: association not allowed with package " + msg); + } checkTime(startTime, "getContentProviderImpl: before checkContentProviderPermission"); if ((msg = checkContentProviderPermissionLocked(cpi, r, userId, checkCrossUser)) @@ -6364,6 +6418,11 @@ public class ActivityManagerService extends IActivityManager.Stub } catch (RemoteException e) { } + if ((msg = checkContentProviderAssociation(r, callingUid, cpi)) != null) { + throw new SecurityException("Content provider lookup " + + cpr.name.flattenToShortString() + + " failed: association not allowed with package " + msg); + } checkTime(startTime, "getContentProviderImpl: before checkContentProviderPermission"); if ((msg = checkContentProviderPermissionLocked(cpi, r, userId, checkCrossUser)) @@ -6461,6 +6520,11 @@ public class ActivityManagerService extends IActivityManager.Stub checkTime(startTime, "getContentProviderImpl: got app info for user"); String msg; + if ((msg = checkContentProviderAssociation(r, callingUid, cpi)) != null) { + throw new SecurityException("Content provider lookup " + + cpr.name.flattenToShortString() + + " failed: association not allowed with package " + msg); + } checkTime(startTime, "getContentProviderImpl: before checkContentProviderPermission"); if ((msg = checkContentProviderPermissionLocked(cpi, r, userId, !singleton)) != null) { @@ -9207,6 +9271,12 @@ public class ActivityManagerService extends IActivityManager.Stub pw.println("-------------------------------------------------------------------------------"); } + dumpAllowedAssociationsLocked(fd, pw, args, opti, dumpAll, dumpPackage); + pw.println(); + if (dumpAll) { + pw.println("-------------------------------------------------------------------------------"); + + } mPendingIntentController.dumpPendingIntents(pw, dumpAll, dumpPackage); pw.println(); if (dumpAll) { @@ -9474,6 +9544,14 @@ public class ActivityManagerService extends IActivityManager.Stub System.gc(); pw.println(BinderInternal.nGetBinderProxyCount(Integer.parseInt(uid))); } + } else if ("allowed-associations".equals(cmd)) { + if (opti < args.length) { + dumpPackage = args[opti]; + opti++; + } + synchronized (this) { + dumpAllowedAssociationsLocked(fd, pw, args, opti, true, dumpPackage); + } } else if ("broadcasts".equals(cmd) || "b".equals(cmd)) { if (opti < args.length) { dumpPackage = args[opti]; @@ -10824,6 +10902,44 @@ public class ActivityManagerService extends IActivityManager.Stub proto.end(handlerToken); } + void dumpAllowedAssociationsLocked(FileDescriptor fd, PrintWriter pw, String[] args, + int opti, boolean dumpAll, String dumpPackage) { + boolean needSep = false; + boolean printedAnything = false; + + pw.println("ACTIVITY MANAGER ALLOWED ASSOCIATION STATE (dumpsys activity allowed-associations)"); + boolean printed = false; + if (mAllowedAssociations != null) { + for (int i = 0; i < mAllowedAssociations.size(); i++) { + final String pkg = mAllowedAssociations.keyAt(i); + final ArraySet<String> asc = mAllowedAssociations.valueAt(i); + boolean printedHeader = false; + for (int j = 0; j < asc.size(); j++) { + if (dumpPackage == null || pkg.equals(dumpPackage) + || asc.valueAt(j).equals(dumpPackage)) { + if (!printed) { + pw.println(" Allowed associations (by restricted package):"); + printed = true; + needSep = true; + printedAnything = true; + } + if (!printedHeader) { + pw.print(" * "); + pw.print(pkg); + pw.println(":"); + printedHeader = true; + } + pw.print(" Allow: "); + pw.println(asc.valueAt(j)); + } + } + } + } + if (!printed) { + pw.println(" (No association restrictions)"); + } + } + void dumpBroadcastsLocked(FileDescriptor fd, PrintWriter pw, String[] args, int opti, boolean dumpAll, String dumpPackage) { boolean needSep = false; diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java index 67a4d14a6edb..740c0da72fc8 100644 --- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java +++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java @@ -20,6 +20,7 @@ import static android.app.ActivityManagerInternal.ALLOW_FULL_ONLY; import static android.app.ActivityTaskManager.INVALID_TASK_ID; import static android.app.ActivityTaskManager.RESIZE_MODE_SYSTEM; import static android.app.ActivityTaskManager.RESIZE_MODE_USER; +import static android.app.WaitResult.launchStateToString; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; import static android.view.Display.INVALID_DISPLAY; @@ -491,6 +492,7 @@ final class ActivityManagerShellCommand extends ShellCommand { final long endTime = SystemClock.uptimeMillis(); PrintWriter out = mWaitOption ? pw : getErrPrintWriter(); boolean launched = false; + boolean hotLaunch = false; switch (res) { case ActivityManager.START_SUCCESS: launched = true; @@ -516,6 +518,8 @@ final class ActivityManagerShellCommand extends ShellCommand { break; case ActivityManager.START_TASK_TO_FRONT: launched = true; + //TODO(b/120981435) remove special case + hotLaunch = true; out.println( "Warning: Activity not started, its current " + "task has been brought to the front"); @@ -563,6 +567,9 @@ final class ActivityManagerShellCommand extends ShellCommand { result.who = intent.getComponent(); } pw.println("Status: " + (result.timeout ? "timeout" : "ok")); + final @WaitResult.LaunchState int launchState = + hotLaunch ? WaitResult.LAUNCH_STATE_HOT : result.launchState; + pw.println("LaunchState: " + launchStateToString(launchState)); if (result.who != null) { pw.println("Activity: " + result.who.flattenToShortString()); } @@ -2852,6 +2859,7 @@ final class ActivityManagerShellCommand extends ShellCommand { pw.println(" prov[iders] [COMP_SPEC ...]: content provider state"); pw.println(" provider [COMP_SPEC]: provider client-side state"); pw.println(" s[ervices] [COMP_SPEC ...]: service state"); + pw.println(" allowed-associations: current package association restrictions"); pw.println(" as[sociations]: tracked app associations"); pw.println(" lmk: stats on low memory killer"); pw.println(" lru: raw LRU process list"); diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java index dd3f3b51d2fd..1c1daffceafe 100644 --- a/services/core/java/com/android/server/am/AppErrors.java +++ b/services/core/java/com/android/server/am/AppErrors.java @@ -18,6 +18,7 @@ package com.android.server.am; import static android.app.ActivityTaskManager.INVALID_TASK_ID; import static android.content.pm.ApplicationInfo.FLAG_SYSTEM; + import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.am.ActivityManagerService.MY_PID; @@ -27,7 +28,6 @@ import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_N import android.app.ActivityManager; import android.app.ActivityOptions; -import android.app.AppOpsManager; import android.app.ApplicationErrorReport; import android.app.Dialog; import android.content.ActivityNotFoundException; @@ -835,15 +835,6 @@ class AppErrors { return; } - Intent intent = new Intent("android.intent.action.ANR"); - if (!mService.mProcessesReady) { - intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY - | Intent.FLAG_RECEIVER_FOREGROUND); - } - mService.broadcastIntentLocked(null, null, intent, - null, null, 0, null, null, null, AppOpsManager.OP_NONE, - null, false, false, MY_PID, Process.SYSTEM_UID, 0 /* TODO: Verify */); - boolean showBackground = Settings.Secure.getInt(mContext.getContentResolver(), Settings.Secure.ANR_SHOW_BACKGROUND, 0) != 0; if (mService.mAtmInternal.canShowErrorDialogs() || showBackground) { diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java index 3a0899de75c3..c290fbe09864 100644 --- a/services/core/java/com/android/server/am/BroadcastQueue.java +++ b/services/core/java/com/android/server/am/BroadcastQueue.java @@ -527,6 +527,24 @@ public final class BroadcastQueue { private void deliverToRegisteredReceiverLocked(BroadcastRecord r, BroadcastFilter filter, boolean ordered, int index) { boolean skip = false; + if (!mService.validateAssociationAllowedLocked(r.callerPackage, r.callingUid, + filter.packageName, filter.owningUid)) { + Slog.w(TAG, "Association not allowed: broadcasting " + + r.intent.toString() + + " from " + r.callerPackage + " (pid=" + r.callingPid + + ", uid=" + r.callingUid + ") to " + filter.packageName + " through " + + filter); + skip = true; + } + if (!skip && !mService.mIntentFirewall.checkBroadcast(r.intent, r.callingUid, + r.callingPid, r.resolvedType, filter.receiverList.uid)) { + Slog.w(TAG, "Firewall blocked: broadcasting " + + r.intent.toString() + + " from " + r.callerPackage + " (pid=" + r.callingPid + + ", uid=" + r.callingUid + ") to " + filter.packageName + " through " + + filter); + skip = true; + } if (filter.requiredPermission != null) { int perm = mService.checkComponentPermission(filter.requiredPermission, r.callingPid, r.callingUid, -1, true); @@ -619,11 +637,6 @@ public final class BroadcastQueue { skip = true; } - if (!mService.mIntentFirewall.checkBroadcast(r.intent, r.callingUid, - r.callingPid, r.resolvedType, filter.receiverList.uid)) { - skip = true; - } - if (!skip && (filter.receiverList.app == null || filter.receiverList.app.killed || filter.receiverList.app.isCrashing())) { Slog.w(TAG, "Skipping deliver [" + mQueueName + "] " + r @@ -1082,6 +1095,24 @@ public final class BroadcastQueue { > brOptions.getMaxManifestReceiverApiLevel())) { skip = true; } + if (!skip && !mService.validateAssociationAllowedLocked(r.callerPackage, r.callingUid, + component.getPackageName(), info.activityInfo.applicationInfo.uid)) { + Slog.w(TAG, "Association not allowed: broadcasting " + + r.intent.toString() + + " from " + r.callerPackage + " (pid=" + r.callingPid + + ", uid=" + r.callingUid + ") to " + component.flattenToShortString()); + skip = true; + } + if (!skip) { + skip = !mService.mIntentFirewall.checkBroadcast(r.intent, r.callingUid, + r.callingPid, r.resolvedType, info.activityInfo.applicationInfo.uid); + if (skip) { + Slog.w(TAG, "Firewall blocked: broadcasting " + + r.intent.toString() + + " from " + r.callerPackage + " (pid=" + r.callingPid + + ", uid=" + r.callingUid + ") to " + component.flattenToShortString()); + } + } int perm = mService.checkComponentPermission(info.activityInfo.permission, r.callingPid, r.callingUid, info.activityInfo.applicationInfo.uid, info.activityInfo.exported); @@ -1170,10 +1201,6 @@ public final class BroadcastQueue { + " (uid " + r.callingUid + ")"); skip = true; } - if (!skip) { - skip = !mService.mIntentFirewall.checkBroadcast(r.intent, r.callingUid, - r.callingPid, r.resolvedType, info.activityInfo.applicationInfo.uid); - } boolean isSingleton = false; try { isSingleton = mService.isSingleton(info.activityInfo.processName, diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java index d75601be23e3..9dfdddbea18a 100644 --- a/services/core/java/com/android/server/connectivity/Tethering.java +++ b/services/core/java/com/android/server/connectivity/Tethering.java @@ -1382,7 +1382,7 @@ public class Tethering extends BaseNetworkObserver { return; } - mUpstreamNetworkMonitor.start(mDeps.getDefaultNetworkRequest()); + mUpstreamNetworkMonitor.startObserveAllNetworks(); // TODO: De-duplicate with updateUpstreamWanted() below. if (upstreamWanted()) { @@ -1658,6 +1658,10 @@ public class Tethering extends BaseNetworkObserver { } } + public void systemReady() { + mUpstreamNetworkMonitor.startTrackDefaultNetwork(mDeps.getDefaultNetworkRequest()); + } + @Override public void dump(FileDescriptor fd, PrintWriter writer, String[] args) { // Binder.java closes the resource for us. diff --git a/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java b/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java index 3e5d5aa6ca54..3ac311b3e13a 100644 --- a/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java +++ b/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java @@ -55,10 +55,13 @@ import java.util.Set; * A class to centralize all the network and link properties information * pertaining to the current and any potential upstream network. * - * Calling #start() registers two callbacks: one to track the system default - * network and a second to observe all networks. The latter is necessary - * while the expression of preferred upstreams remains a list of legacy - * connectivity types. In future, this can be revisited. + * The owner of UNM gets it to register network callbacks by calling the + * following methods : + * Calling #startTrackDefaultNetwork() to track the system default network. + * Calling #startObserveAllNetworks() to observe all networks. Listening all + * networks is necessary while the expression of preferred upstreams remains + * a list of legacy connectivity types. In future, this can be revisited. + * Calling #registerMobileNetworkRequest() to bring up mobile DUN/HIPRI network. * * The methods and data members of this class are only to be accessed and * modified from the tethering master state machine thread. Any other @@ -119,33 +122,31 @@ public class UpstreamNetworkMonitor { mCM = cm; } - public void start(NetworkRequest defaultNetworkRequest) { + public void startTrackDefaultNetwork(NetworkRequest defaultNetworkRequest) { + // This is not really a "request", just a way of tracking the system default network. + // It's guaranteed not to actually bring up any networks because it's the same request + // as the ConnectivityService default request, and thus shares fate with it. We can't + // use registerDefaultNetworkCallback because it will not track the system default + // network if there is a VPN that applies to our UID. + if (mDefaultNetworkCallback == null) { + final NetworkRequest trackDefaultRequest = new NetworkRequest(defaultNetworkRequest); + mDefaultNetworkCallback = new UpstreamNetworkCallback(CALLBACK_DEFAULT_INTERNET); + cm().requestNetwork(trackDefaultRequest, mDefaultNetworkCallback, mHandler); + } + } + + public void startObserveAllNetworks() { stop(); final NetworkRequest listenAllRequest = new NetworkRequest.Builder() .clearCapabilities().build(); mListenAllCallback = new UpstreamNetworkCallback(CALLBACK_LISTEN_ALL); cm().registerNetworkCallback(listenAllRequest, mListenAllCallback, mHandler); - - if (defaultNetworkRequest != null) { - // This is not really a "request", just a way of tracking the system default network. - // It's guaranteed not to actually bring up any networks because it's the same request - // as the ConnectivityService default request, and thus shares fate with it. We can't - // use registerDefaultNetworkCallback because it will not track the system default - // network if there is a VPN that applies to our UID. - final NetworkRequest trackDefaultRequest = new NetworkRequest(defaultNetworkRequest); - mDefaultNetworkCallback = new UpstreamNetworkCallback(CALLBACK_DEFAULT_INTERNET); - cm().requestNetwork(trackDefaultRequest, mDefaultNetworkCallback, mHandler); - } } public void stop() { releaseMobileNetworkRequest(); - releaseCallback(mDefaultNetworkCallback); - mDefaultNetworkCallback = null; - mDefaultInternetNetwork = null; - releaseCallback(mListenAllCallback); mListenAllCallback = null; @@ -264,9 +265,7 @@ public class UpstreamNetworkMonitor { mNetworkMap.put(network, new NetworkState(null, null, null, network, null, null)); } - private void handleNetCap(int callbackType, Network network, NetworkCapabilities newNc) { - if (callbackType == CALLBACK_DEFAULT_INTERNET) mDefaultInternetNetwork = network; - + private void handleNetCap(Network network, NetworkCapabilities newNc) { final NetworkState prev = mNetworkMap.get(network); if (prev == null || newNc.equals(prev.networkCapabilities)) { // Ignore notifications about networks for which we have not yet @@ -315,31 +314,25 @@ public class UpstreamNetworkMonitor { notifyTarget(EVENT_ON_LINKPROPERTIES, network); } - private void handleSuspended(int callbackType, Network network) { - if (callbackType != CALLBACK_LISTEN_ALL) return; + private void handleSuspended(Network network) { if (!network.equals(mTetheringUpstreamNetwork)) return; mLog.log("SUSPENDED current upstream: " + network); } - private void handleResumed(int callbackType, Network network) { - if (callbackType != CALLBACK_LISTEN_ALL) return; + private void handleResumed(Network network) { if (!network.equals(mTetheringUpstreamNetwork)) return; mLog.log("RESUMED current upstream: " + network); } - private void handleLost(int callbackType, Network network) { - if (network.equals(mDefaultInternetNetwork)) { - mDefaultInternetNetwork = null; - // There are few TODOs within ConnectivityService's rematching code - // pertaining to spurious onLost() notifications. - // - // TODO: simplify this, probably if favor of code that: - // - selects a new upstream if mTetheringUpstreamNetwork has - // been lost (by any callback) - // - deletes the entry from the map only when the LISTEN_ALL - // callback gets notified. - if (callbackType == CALLBACK_DEFAULT_INTERNET) return; - } + private void handleLost(Network network) { + // There are few TODOs within ConnectivityService's rematching code + // pertaining to spurious onLost() notifications. + // + // TODO: simplify this, probably if favor of code that: + // - selects a new upstream if mTetheringUpstreamNetwork has + // been lost (by any callback) + // - deletes the entry from the map only when the LISTEN_ALL + // callback gets notified. if (!mNetworkMap.containsKey(network)) { // Ignore loss of networks about which we had not previously @@ -393,11 +386,17 @@ public class UpstreamNetworkMonitor { @Override public void onCapabilitiesChanged(Network network, NetworkCapabilities newNc) { - handleNetCap(mCallbackType, network, newNc); + if (mCallbackType == CALLBACK_DEFAULT_INTERNET) { + mDefaultInternetNetwork = network; + return; + } + handleNetCap(network, newNc); } @Override public void onLinkPropertiesChanged(Network network, LinkProperties newLp) { + if (mCallbackType == CALLBACK_DEFAULT_INTERNET) return; + handleLinkProp(network, newLp); // Any non-LISTEN_ALL callback will necessarily concern a network that will // also match the LISTEN_ALL callback by construction of the LISTEN_ALL callback. @@ -409,17 +408,25 @@ public class UpstreamNetworkMonitor { @Override public void onNetworkSuspended(Network network) { - handleSuspended(mCallbackType, network); + if (mCallbackType == CALLBACK_LISTEN_ALL) { + handleSuspended(network); + } } @Override public void onNetworkResumed(Network network) { - handleResumed(mCallbackType, network); + if (mCallbackType == CALLBACK_LISTEN_ALL) { + handleResumed(network); + } } @Override public void onLost(Network network) { - handleLost(mCallbackType, network); + if (mCallbackType == CALLBACK_DEFAULT_INTERNET) { + mDefaultInternetNetwork = null; + return; + } + handleLost(network); // Any non-LISTEN_ALL callback will necessarily concern a network that will // also match the LISTEN_ALL callback by construction of the LISTEN_ALL callback. // So it's not useful to do this work for non-LISTEN_ALL callbacks. diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java index 78e18e91ae73..1325f049e737 100644 --- a/services/core/java/com/android/server/job/JobSchedulerService.java +++ b/services/core/java/com/android/server/job/JobSchedulerService.java @@ -861,6 +861,11 @@ public class JobSchedulerService extends com.android.server.SystemService Slog.d(TAG, "Removing jobs for uid: " + uidRemoved); } cancelJobsForPackageAndUid(pkgName, uidRemoved, "app uninstalled"); + synchronized (mLock) { + for (int c = 0; c < mControllers.size(); ++c) { + mControllers.get(c).onAppRemovedLocked(pkgName, pkgUid); + } + } } } else if (Intent.ACTION_USER_REMOVED.equals(action)) { final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0); @@ -868,6 +873,11 @@ public class JobSchedulerService extends com.android.server.SystemService Slog.d(TAG, "Removing jobs for user: " + userId); } cancelJobsForUser(userId); + synchronized (mLock) { + for (int c = 0; c < mControllers.size(); ++c) { + mControllers.get(c).onUserRemovedLocked(userId); + } + } } else if (Intent.ACTION_QUERY_PACKAGE_RESTART.equals(action)) { // Has this package scheduled any jobs, such that we will take action // if it were to be force-stopped? diff --git a/services/core/java/com/android/server/job/controllers/ConnectivityController.java b/services/core/java/com/android/server/job/controllers/ConnectivityController.java index 8f104e4a1525..aca02bf1fb7c 100644 --- a/services/core/java/com/android/server/job/controllers/ConnectivityController.java +++ b/services/core/java/com/android/server/job/controllers/ConnectivityController.java @@ -296,6 +296,12 @@ public final class ConnectivityController extends StateController implements mRequestedWhitelistJobs.remove(uid); } + @GuardedBy("mLock") + @Override + public void onAppRemovedLocked(String pkgName, int uid) { + mTrackedJobs.delete(uid); + } + /** * Test to see if running the given job on the given network is insane. * <p> diff --git a/services/core/java/com/android/server/job/controllers/QuotaController.java b/services/core/java/com/android/server/job/controllers/QuotaController.java index 660c2383ea2f..58ee21795d99 100644 --- a/services/core/java/com/android/server/job/controllers/QuotaController.java +++ b/services/core/java/com/android/server/job/controllers/QuotaController.java @@ -98,6 +98,19 @@ public final class QuotaController extends StateController { data.put(packageName, obj); } + /** Removes all the data for the user, if there was any. */ + public void delete(int userId) { + mData.delete(userId); + } + + /** Removes the data for the user and package, if there was any. */ + public void delete(int userId, @NonNull String packageName) { + ArrayMap<String, T> data = mData.get(userId); + if (data != null) { + data.remove(packageName); + } + } + @Nullable public T get(int userId, @NonNull String packageName) { ArrayMap<String, T> data = mData.get(userId); @@ -371,6 +384,38 @@ public final class QuotaController extends StateController { } } + @Override + public void onAppRemovedLocked(String packageName, int uid) { + if (packageName == null) { + Slog.wtf(TAG, "Told app removed but given null package name."); + return; + } + final int userId = UserHandle.getUserId(uid); + mTrackedJobs.delete(userId, packageName); + Timer timer = mPkgTimers.get(userId, packageName); + if (timer != null) { + if (timer.isActive()) { + Slog.wtf(TAG, "onAppRemovedLocked called before Timer turned off."); + timer.dropEverything(); + } + mPkgTimers.delete(userId, packageName); + } + mTimingSessions.delete(userId, packageName); + QcAlarmListener alarmListener = mInQuotaAlarmListeners.get(userId, packageName); + if (alarmListener != null) { + mAlarmManager.cancel(alarmListener); + mInQuotaAlarmListeners.delete(userId, packageName); + } + } + + @Override + public void onUserRemovedLocked(int userId) { + mTrackedJobs.delete(userId); + mPkgTimers.delete(userId); + mTimingSessions.delete(userId); + mInQuotaAlarmListeners.delete(userId); + } + /** * Returns an appropriate standby bucket for the job, taking into account any standby * exemptions. @@ -882,6 +927,15 @@ public final class QuotaController extends StateController { } } + /** + * Stops tracking all jobs and cancels any pending alarms. This should only be called if + * the Timer is not going to be used anymore. + */ + void dropEverything() { + mRunningBgJobs.clear(); + cancelCutoff(); + } + private void emitSessionLocked(long nowElapsed) { if (mBgJobCount <= 0) { // Nothing to emit. diff --git a/services/core/java/com/android/server/job/controllers/StateController.java b/services/core/java/com/android/server/job/controllers/StateController.java index 61dc4799f221..97c3bac4ddbb 100644 --- a/services/core/java/com/android/server/job/controllers/StateController.java +++ b/services/core/java/com/android/server/job/controllers/StateController.java @@ -83,21 +83,12 @@ public abstract class StateController { public void onConstantsUpdatedLocked() { } - protected boolean wouldBeReadyWithConstraintLocked(JobStatus jobStatus, int constraint) { - // This is very cheap to check (just a few conditions on data in JobStatus). - final boolean jobWouldBeReady = jobStatus.wouldBeReadyWithConstraint(constraint); - if (DEBUG) { - Slog.v(TAG, "wouldBeReadyWithConstraintLocked: " + jobStatus.toShortString() - + " readyWithConstraint=" + jobWouldBeReady); - } - if (!jobWouldBeReady) { - // If the job wouldn't be ready, nothing to do here. - return false; - } + /** Called when a package is uninstalled from the device (not for an update). */ + public void onAppRemovedLocked(String packageName, int uid) { + } - // This is potentially more expensive since JSS may have to query component - // presence. - return mService.areComponentsInPlaceLocked(jobStatus); + /** Called when a user is removed from the device. */ + public void onUserRemovedLocked(int userId) { } /** @@ -114,6 +105,23 @@ public abstract class StateController { public void reevaluateStateLocked(int uid) { } + protected boolean wouldBeReadyWithConstraintLocked(JobStatus jobStatus, int constraint) { + // This is very cheap to check (just a few conditions on data in JobStatus). + final boolean jobWouldBeReady = jobStatus.wouldBeReadyWithConstraint(constraint); + if (DEBUG) { + Slog.v(TAG, "wouldBeReadyWithConstraintLocked: " + jobStatus.toShortString() + + " readyWithConstraint=" + jobWouldBeReady); + } + if (!jobWouldBeReady) { + // If the job wouldn't be ready, nothing to do here. + return false; + } + + // This is potentially more expensive since JSS may have to query component + // presence. + return mService.areComponentsInPlaceLocked(jobStatus); + } + public abstract void dumpControllerStateLocked(IndentingPrintWriter pw, Predicate<JobStatus> predicate); public abstract void dumpControllerStateLocked(ProtoOutputStream proto, long fieldId, diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java index 31f5ce47abd9..b58c811645f7 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java @@ -799,10 +799,6 @@ public class PermissionManagerService { continue; } - if (bp.isRemoved()) { - continue; - } - // Limit ephemeral apps to ephemeral allowed permissions. if (pkg.applicationInfo.isInstantApp() && !bp.isInstant()) { if (DEBUG_PERMISSIONS) { @@ -951,7 +947,8 @@ public class PermissionManagerService { // how to disable the API to simulate revocation as legacy // apps don't expect to run with revoked permissions. if (PLATFORM_PACKAGE_NAME.equals(bp.getSourcePackageName())) { - if ((flags & FLAG_PERMISSION_REVIEW_REQUIRED) == 0) { + if ((flags & FLAG_PERMISSION_REVIEW_REQUIRED) == 0 + && !bp.isRemoved()) { flags |= FLAG_PERMISSION_REVIEW_REQUIRED; // We changed the flags, hence have to write. updatedUserIds = ArrayUtils.appendInt( diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java index 12690a99062e..102318262798 100644 --- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java +++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java @@ -3,6 +3,9 @@ package com.android.server.wm; import static android.app.ActivityManager.START_SUCCESS; import static android.app.ActivityManager.START_TASK_TO_FRONT; import static android.app.ActivityManager.processStateAmToProto; +import static android.app.WaitResult.LAUNCH_STATE_COLD; +import static android.app.WaitResult.LAUNCH_STATE_HOT; +import static android.app.WaitResult.LAUNCH_STATE_WARM; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; @@ -80,6 +83,7 @@ import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_TIMEOUT; +import android.app.WaitResult; import android.app.WindowConfiguration.WindowingMode; import android.content.Context; import android.content.Intent; @@ -101,10 +105,10 @@ import android.util.StatsLog; import android.util.TimeUtils; import android.util.proto.ProtoOutputStream; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.MetricsLogger; import com.android.internal.os.BackgroundThread; import com.android.internal.os.SomeArgs; -import com.android.internal.annotations.VisibleForTesting; import com.android.server.LocalServices; /** @@ -259,6 +263,19 @@ class ActivityMetricsLogger { activityRecordIdHashCode = System.identityHashCode(launchedActivity); this.windowsFullyDrawnDelayMs = windowsFullyDrawnDelayMs; } + + @WaitResult.LaunchState int getLaunchState() { + switch (type) { + case TYPE_TRANSITION_WARM_LAUNCH: + return LAUNCH_STATE_WARM; + case TYPE_TRANSITION_HOT_LAUNCH: + return LAUNCH_STATE_HOT; + case TYPE_TRANSITION_COLD_LAUNCH: + return LAUNCH_STATE_COLD; + default: + return -1; + } + } } ActivityMetricsLogger(ActivityStackSupervisor supervisor, Context context, Looper looper) { diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index de8024fb9ae8..43736755cf88 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -145,6 +145,7 @@ import android.app.ActivityOptions; import android.app.PendingIntent; import android.app.PictureInPictureParams; import android.app.ResultInfo; +import android.app.WaitResult.LaunchState; import android.app.servertransaction.ActivityConfigurationChangeItem; import android.app.servertransaction.ActivityLifecycleItem; import android.app.servertransaction.ActivityRelaunchItem; @@ -2180,7 +2181,7 @@ final class ActivityRecord extends ConfigurationContainer { .getActivityMetricsLogger().logAppTransitionReportedDrawn(this, restoredFromBundle); if (info != null) { mStackSupervisor.reportActivityLaunchedLocked(false /* timeout */, this, - info.windowsFullyDrawnDelayMs); + info.windowsFullyDrawnDelayMs, info.getLaunchState()); } } @@ -2204,8 +2205,9 @@ final class ActivityRecord extends ConfigurationContainer { final WindowingModeTransitionInfoSnapshot info = mStackSupervisor .getActivityMetricsLogger().notifyWindowsDrawn(getWindowingMode(), timestamp); final int windowsDrawnDelayMs = info != null ? info.windowsDrawnDelayMs : INVALID_DELAY; + final @LaunchState int launchState = info != null ? info.getLaunchState() : -1; mStackSupervisor.reportActivityLaunchedLocked(false /* timeout */, this, - windowsDrawnDelayMs); + windowsDrawnDelayMs, launchState); mStackSupervisor.sendWaitingVisibleReportLocked(this); finishLaunchTickingLocked(); if (task != null) { diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java index c43fd2487470..f58b83d682f6 100644 --- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java @@ -599,7 +599,8 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { } } - void reportActivityLaunchedLocked(boolean timeout, ActivityRecord r, long totalTime) { + void reportActivityLaunchedLocked(boolean timeout, ActivityRecord r, long totalTime, + @WaitResult.LaunchState int launchState) { boolean changed = false; for (int i = mWaitingActivityLaunched.size() - 1; i >= 0; i--) { WaitResult w = mWaitingActivityLaunched.remove(i); @@ -610,6 +611,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { w.who = new ComponentName(r.info.packageName, r.info.name); } w.totalTime = totalTime; + w.launchState = launchState; // Do not modify w.result. } } @@ -1252,7 +1254,8 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { mHandler.removeMessages(IDLE_TIMEOUT_MSG, r); r.finishLaunchTickingLocked(); if (fromTimeout) { - reportActivityLaunchedLocked(fromTimeout, r, INVALID_DELAY); + reportActivityLaunchedLocked(fromTimeout, r, INVALID_DELAY, + -1 /* launchState */); } // This is a hack to semi-deal with a race condition diff --git a/services/core/jni/com_android_server_net_NetworkStatsService.cpp b/services/core/jni/com_android_server_net_NetworkStatsService.cpp index 649f1a56f011..4d4a7b41643c 100644 --- a/services/core/jni/com_android_server_net_NetworkStatsService.cpp +++ b/services/core/jni/com_android_server_net_NetworkStatsService.cpp @@ -34,7 +34,6 @@ #include "netdbpf/BpfNetworkStats.h" using android::bpf::Stats; -using android::bpf::hasBpfSupport; using android::bpf::bpfGetUidStats; using android::bpf::bpfGetIfaceStats; diff --git a/services/net/java/android/net/apf/ApfFilter.java b/services/net/java/android/net/apf/ApfFilter.java index a7209a076461..b9cc372c5138 100644 --- a/services/net/java/android/net/apf/ApfFilter.java +++ b/services/net/java/android/net/apf/ApfFilter.java @@ -111,7 +111,7 @@ public class ApfFilter { * the last writable 32bit word. */ @VisibleForTesting - private static enum Counter { + public static enum Counter { RESERVED_OOB, // Points to offset 0 from the end of the buffer (out-of-bounds) TOTAL_PACKETS, PASSED_ARP, diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java index 71aec235640b..effb5a72bd66 100644 --- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java @@ -270,6 +270,60 @@ public class QuotaControllerTest { } @Test + public void testOnAppRemovedLocked() { + final long now = JobSchedulerService.sElapsedRealtimeClock.millis(); + mQuotaController.saveTimingSession(0, "com.android.test.remove", + createTimingSession(now - (6 * HOUR_IN_MILLIS), 10 * MINUTE_IN_MILLIS, 5)); + mQuotaController.saveTimingSession(0, "com.android.test.remove", + createTimingSession( + now - (2 * HOUR_IN_MILLIS + MINUTE_IN_MILLIS), 6 * MINUTE_IN_MILLIS, 5)); + mQuotaController.saveTimingSession(0, "com.android.test.remove", + createTimingSession(now - (HOUR_IN_MILLIS), MINUTE_IN_MILLIS, 1)); + // Test that another app isn't affected. + TimingSession one = createTimingSession( + now - 10 * MINUTE_IN_MILLIS, 9 * MINUTE_IN_MILLIS, 3); + TimingSession two = createTimingSession( + now - (70 * MINUTE_IN_MILLIS), 9 * MINUTE_IN_MILLIS, 1); + List<TimingSession> expected = new ArrayList<>(); + // Added in correct (chronological) order. + expected.add(two); + expected.add(one); + mQuotaController.saveTimingSession(0, "com.android.test.stay", two); + mQuotaController.saveTimingSession(0, "com.android.test.stay", one); + + mQuotaController.onAppRemovedLocked("com.android.test.remove", 10001); + assertNull(mQuotaController.getTimingSessions(0, "com.android.test.remove")); + assertEquals(expected, mQuotaController.getTimingSessions(0, "com.android.test.stay")); + } + + @Test + public void testOnUserRemovedLocked() { + final long now = JobSchedulerService.sElapsedRealtimeClock.millis(); + mQuotaController.saveTimingSession(0, "com.android.test", + createTimingSession(now - (6 * HOUR_IN_MILLIS), 10 * MINUTE_IN_MILLIS, 5)); + mQuotaController.saveTimingSession(0, "com.android.test", + createTimingSession( + now - (2 * HOUR_IN_MILLIS + MINUTE_IN_MILLIS), 6 * MINUTE_IN_MILLIS, 5)); + mQuotaController.saveTimingSession(0, "com.android.test", + createTimingSession(now - (HOUR_IN_MILLIS), MINUTE_IN_MILLIS, 1)); + // Test that another user isn't affected. + TimingSession one = createTimingSession( + now - 10 * MINUTE_IN_MILLIS, 9 * MINUTE_IN_MILLIS, 3); + TimingSession two = createTimingSession( + now - (70 * MINUTE_IN_MILLIS), 9 * MINUTE_IN_MILLIS, 1); + List<TimingSession> expected = new ArrayList<>(); + // Added in correct (chronological) order. + expected.add(two); + expected.add(one); + mQuotaController.saveTimingSession(10, "com.android.test", two); + mQuotaController.saveTimingSession(10, "com.android.test", one); + + mQuotaController.onUserRemovedLocked(0); + assertNull(mQuotaController.getTimingSessions(0, "com.android.test")); + assertEquals(expected, mQuotaController.getTimingSessions(10, "com.android.test")); + } + + @Test public void testGetTrailingExecutionTimeLocked_NoTimer() { final long now = JobSchedulerService.sElapsedRealtimeClock.millis(); // Added in chronological order. diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp index d7b1cb475bb4..4ee9551542b5 100644 --- a/services/tests/servicestests/Android.bp +++ b/services/tests/servicestests/Android.bp @@ -70,7 +70,7 @@ android_test { "liblzma", "libnativehelper", "libui", - "libunwind", + "libunwindstack", "libutils", "netd_aidl_interface-cpp", ], diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java index 49030f59064a..fb371c176352 100644 --- a/telecomm/java/android/telecom/TelecomManager.java +++ b/telecomm/java/android/telecom/TelecomManager.java @@ -476,7 +476,7 @@ public class TelecomManager { /** * A boolean meta-data value indicating whether an {@link InCallService} implements an * in-call user interface to be used while the device is in car-mode (see - * {@link android.content.res.Configuration.UI_MODE_TYPE_CAR}). + * {@link android.content.res.Configuration#UI_MODE_TYPE_CAR}). */ public static final String METADATA_IN_CALL_SERVICE_CAR_MODE_UI = "android.telecom.IN_CALL_SERVICE_CAR_MODE_UI"; diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index cfe134fd0ee2..388b5fb43096 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -1398,9 +1398,9 @@ public class CarrierConfigManager { * Example: "default" * * {@code ERROR_CODE_1} is an integer defined in - * {@link com.android.internal.telephony.dataconnection.DcFailCause DcFailure} + * {@link DataFailCause DcFailure} * Example: - * {@link com.android.internal.telephony.dataconnection.DcFailCause#MISSING_UNKNOWN_APN} + * {@link DataFailCause#MISSING_UNKNOWN_APN} * * {@code CARRIER_ACTION_IDX_1} is an integer defined in * {@link com.android.carrierdefaultapp.CarrierActionUtils CarrierActionUtils} diff --git a/telephony/java/android/telephony/DataFailCause.java b/telephony/java/android/telephony/DataFailCause.java new file mode 100644 index 000000000000..c6f7d0e458db --- /dev/null +++ b/telephony/java/android/telephony/DataFailCause.java @@ -0,0 +1,259 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.telephony; + +import android.content.Context; +import android.os.PersistableBundle; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; + +/** + * Returned as the reason for a connection failure as defined + * by RIL_DataCallFailCause in ril.h and some local errors. + * @hide + */ +public enum DataFailCause { + NONE(0), + + // This series of errors as specified by the standards + // specified in ril.h + OPERATOR_BARRED(0x08), /* no retry */ + NAS_SIGNALLING(0x0E), + LLC_SNDCP(0x19), + INSUFFICIENT_RESOURCES(0x1A), + MISSING_UNKNOWN_APN(0x1B), /* no retry */ + UNKNOWN_PDP_ADDRESS_TYPE(0x1C), /* no retry */ + USER_AUTHENTICATION(0x1D), /* no retry */ + ACTIVATION_REJECT_GGSN(0x1E), /* no retry */ + ACTIVATION_REJECT_UNSPECIFIED(0x1F), + SERVICE_OPTION_NOT_SUPPORTED(0x20), /* no retry */ + SERVICE_OPTION_NOT_SUBSCRIBED(0x21), /* no retry */ + SERVICE_OPTION_OUT_OF_ORDER(0x22), + NSAPI_IN_USE(0x23), /* no retry */ + REGULAR_DEACTIVATION(0x24), /* possibly restart radio, based on config */ + QOS_NOT_ACCEPTED(0x25), + NETWORK_FAILURE(0x26), + UMTS_REACTIVATION_REQ(0x27), + FEATURE_NOT_SUPP(0x28), + TFT_SEMANTIC_ERROR(0x29), + TFT_SYTAX_ERROR(0x2A), + UNKNOWN_PDP_CONTEXT(0x2B), + FILTER_SEMANTIC_ERROR(0x2C), + FILTER_SYTAX_ERROR(0x2D), + PDP_WITHOUT_ACTIVE_TFT(0x2E), + ONLY_IPV4_ALLOWED(0x32), /* no retry */ + ONLY_IPV6_ALLOWED(0x33), /* no retry */ + ONLY_SINGLE_BEARER_ALLOWED(0x34), + ESM_INFO_NOT_RECEIVED(0x35), + PDN_CONN_DOES_NOT_EXIST(0x36), + MULTI_CONN_TO_SAME_PDN_NOT_ALLOWED(0x37), + MAX_ACTIVE_PDP_CONTEXT_REACHED(0x41), + UNSUPPORTED_APN_IN_CURRENT_PLMN(0x42), + INVALID_TRANSACTION_ID(0x51), + MESSAGE_INCORRECT_SEMANTIC(0x5F), + INVALID_MANDATORY_INFO(0x60), + MESSAGE_TYPE_UNSUPPORTED(0x61), + MSG_TYPE_NONCOMPATIBLE_STATE(0x62), + UNKNOWN_INFO_ELEMENT(0x63), + CONDITIONAL_IE_ERROR(0x64), + MSG_AND_PROTOCOL_STATE_UNCOMPATIBLE(0x65), + PROTOCOL_ERRORS(0x6F), /* no retry */ + APN_TYPE_CONFLICT(0x70), + INVALID_PCSCF_ADDR(0x71), + INTERNAL_CALL_PREEMPT_BY_HIGH_PRIO_APN(0x72), + EMM_ACCESS_BARRED(0x73), + EMERGENCY_IFACE_ONLY(0x74), + IFACE_MISMATCH(0x75), + COMPANION_IFACE_IN_USE(0x76), + IP_ADDRESS_MISMATCH(0x77), + IFACE_AND_POL_FAMILY_MISMATCH(0x78), + EMM_ACCESS_BARRED_INFINITE_RETRY(0x79), + AUTH_FAILURE_ON_EMERGENCY_CALL(0x7A), + + // OEM sepecific error codes. To be used by OEMs when they don't + // want to reveal error code which would be replaced by ERROR_UNSPECIFIED + OEM_DCFAILCAUSE_1(0x1001), + OEM_DCFAILCAUSE_2(0x1002), + OEM_DCFAILCAUSE_3(0x1003), + OEM_DCFAILCAUSE_4(0x1004), + OEM_DCFAILCAUSE_5(0x1005), + OEM_DCFAILCAUSE_6(0x1006), + OEM_DCFAILCAUSE_7(0x1007), + OEM_DCFAILCAUSE_8(0x1008), + OEM_DCFAILCAUSE_9(0x1009), + OEM_DCFAILCAUSE_10(0x100A), + OEM_DCFAILCAUSE_11(0x100B), + OEM_DCFAILCAUSE_12(0x100C), + OEM_DCFAILCAUSE_13(0x100D), + OEM_DCFAILCAUSE_14(0x100E), + OEM_DCFAILCAUSE_15(0x100F), + + // Local errors generated by Vendor RIL + // specified in ril.h + REGISTRATION_FAIL(-1), + GPRS_REGISTRATION_FAIL(-2), + SIGNAL_LOST(-3), /* no retry */ + PREF_RADIO_TECH_CHANGED(-4), + RADIO_POWER_OFF(-5), /* no retry */ + TETHERED_CALL_ACTIVE(-6), /* no retry */ + ERROR_UNSPECIFIED(0xFFFF), + + // Errors generated by the Framework + // specified here + UNKNOWN(0x10000), + RADIO_NOT_AVAILABLE(0x10001), /* no retry */ + UNACCEPTABLE_NETWORK_PARAMETER(0x10002), /* no retry */ + CONNECTION_TO_DATACONNECTIONAC_BROKEN(0x10003), + LOST_CONNECTION(0x10004), + RESET_BY_FRAMEWORK(0x10005); + + private final int mErrorCode; + private static final HashMap<Integer, DataFailCause> sErrorCodeToFailCauseMap; + static { + sErrorCodeToFailCauseMap = new HashMap<Integer, DataFailCause>(); + for (DataFailCause fc : values()) { + sErrorCodeToFailCauseMap.put(fc.getErrorCode(), fc); + } + } + + /** + * Map of subId -> set of data call setup permanent failure for the carrier. + */ + private static final HashMap<Integer, HashSet<DataFailCause>> sPermanentFailureCache = + new HashMap<>(); + + DataFailCause(int errorCode) { + mErrorCode = errorCode; + } + + public int getErrorCode() { + return mErrorCode; + } + + /** + * Returns whether or not the fail cause is a failure that requires a modem restart + * + * @param context device context + * @param subId subscription index + * @return true if the fail cause code needs platform to trigger a modem restart. + */ + public boolean isRadioRestartFailure(Context context, int subId) { + CarrierConfigManager configManager = (CarrierConfigManager) + context.getSystemService(Context.CARRIER_CONFIG_SERVICE); + if (configManager != null) { + PersistableBundle b = configManager.getConfigForSubId(subId); + + if (b != null) { + if (this == REGULAR_DEACTIVATION + && b.getBoolean(CarrierConfigManager + .KEY_RESTART_RADIO_ON_PDP_FAIL_REGULAR_DEACTIVATION_BOOL)) { + // This is for backward compatibility support. We need to continue support this + // old configuration until it gets removed in the future. + return true; + } + // Check the current configurations. + int[] causeCodes = b.getIntArray(CarrierConfigManager + .KEY_RADIO_RESTART_FAILURE_CAUSES_INT_ARRAY); + if (causeCodes != null) { + return Arrays.stream(causeCodes).anyMatch(i -> i == getErrorCode()); + } + } + } + + return false; + } + + public boolean isPermanentFailure(Context context, int subId) { + + synchronized (sPermanentFailureCache) { + + HashSet<DataFailCause> permanentFailureSet = sPermanentFailureCache.get(subId); + + // In case of cache miss, we need to look up the settings from carrier config. + if (permanentFailureSet == null) { + // Retrieve the permanent failure from carrier config + CarrierConfigManager configManager = (CarrierConfigManager) + context.getSystemService(Context.CARRIER_CONFIG_SERVICE); + if (configManager != null) { + PersistableBundle b = configManager.getConfigForSubId(subId); + if (b != null) { + String[] permanentFailureStrings = b.getStringArray(CarrierConfigManager. + KEY_CARRIER_DATA_CALL_PERMANENT_FAILURE_STRINGS); + + if (permanentFailureStrings != null) { + permanentFailureSet = new HashSet<>(); + for (String failure : permanentFailureStrings) { + permanentFailureSet.add(DataFailCause.valueOf(failure)); + } + } + } + } + + // If we are not able to find the configuration from carrier config, use the default + // ones. + if (permanentFailureSet == null) { + permanentFailureSet = new HashSet<DataFailCause>() { + { + add(OPERATOR_BARRED); + add(MISSING_UNKNOWN_APN); + add(UNKNOWN_PDP_ADDRESS_TYPE); + add(USER_AUTHENTICATION); + add(ACTIVATION_REJECT_GGSN); + add(SERVICE_OPTION_NOT_SUPPORTED); + add(SERVICE_OPTION_NOT_SUBSCRIBED); + add(NSAPI_IN_USE); + add(ONLY_IPV4_ALLOWED); + add(ONLY_IPV6_ALLOWED); + add(PROTOCOL_ERRORS); + add(RADIO_POWER_OFF); + add(TETHERED_CALL_ACTIVE); + add(RADIO_NOT_AVAILABLE); + add(UNACCEPTABLE_NETWORK_PARAMETER); + add(SIGNAL_LOST); + } + }; + } + + sPermanentFailureCache.put(subId, permanentFailureSet); + } + + return permanentFailureSet.contains(this); + } + } + + public boolean isEventLoggable() { + return (this == OPERATOR_BARRED) || (this == INSUFFICIENT_RESOURCES) || + (this == UNKNOWN_PDP_ADDRESS_TYPE) || (this == USER_AUTHENTICATION) || + (this == ACTIVATION_REJECT_GGSN) || (this == ACTIVATION_REJECT_UNSPECIFIED) || + (this == SERVICE_OPTION_NOT_SUBSCRIBED) || + (this == SERVICE_OPTION_NOT_SUPPORTED) || + (this == SERVICE_OPTION_OUT_OF_ORDER) || (this == NSAPI_IN_USE) || + (this == ONLY_IPV4_ALLOWED) || (this == ONLY_IPV6_ALLOWED) || + (this == PROTOCOL_ERRORS) || (this == SIGNAL_LOST) || + (this == RADIO_POWER_OFF) || (this == TETHERED_CALL_ACTIVE) || + (this == UNACCEPTABLE_NETWORK_PARAMETER); + } + + public static DataFailCause fromInt(int errorCode) { + DataFailCause fc = sErrorCodeToFailCauseMap.get(errorCode); + if (fc == null) { + fc = UNKNOWN; + } + return fc; + } +} diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java index c95837e1e1de..4dcb410e277a 100644 --- a/telephony/java/android/telephony/PhoneNumberUtils.java +++ b/telephony/java/android/telephony/PhoneNumberUtils.java @@ -20,7 +20,6 @@ import com.android.i18n.phonenumbers.NumberParseException; import com.android.i18n.phonenumbers.PhoneNumberUtil; import com.android.i18n.phonenumbers.PhoneNumberUtil.PhoneNumberFormat; import com.android.i18n.phonenumbers.Phonenumber.PhoneNumber; -import com.android.i18n.phonenumbers.ShortNumberInfo; import android.annotation.IntDef; import android.annotation.UnsupportedAppUsage; @@ -2185,101 +2184,6 @@ public class PhoneNumberUtils { } /** - * Back-up old logics for {@link #isEmergencyNumberInternal} for legacy and deprecate purpose. - * - * @hide - */ - public static boolean isEmergencyNumberInternal(String number, boolean useExactMatch, - String defaultCountryIso) { - // If the number passed in is null, just return false: - if (number == null) return false; - - // If the number passed in is a SIP address, return false, since the - // concept of "emergency numbers" is only meaningful for calls placed - // over the cell network. - // (Be sure to do this check *before* calling extractNetworkPortionAlt(), - // since the whole point of extractNetworkPortionAlt() is to filter out - // any non-dialable characters (which would turn 'abc911def@example.com' - // into '911', for example.)) - if (PhoneNumberUtils.isUriNumber(number)) { - return false; - } - - // Strip the separators from the number before comparing it - // to the list. - number = PhoneNumberUtils.extractNetworkPortionAlt(number); - - String emergencyNumbers = ""; - int slotId = SubscriptionManager.getSlotIndex(getDefaultVoiceSubId()); - - // retrieve the list of emergency numbers - // check read-write ecclist property first - String ecclist = (slotId <= 0) ? "ril.ecclist" : ("ril.ecclist" + slotId); - - emergencyNumbers = SystemProperties.get(ecclist, ""); - - Rlog.d(LOG_TAG, "slotId:" + slotId + " country:" - + defaultCountryIso + " emergencyNumbers: " + emergencyNumbers); - - if (TextUtils.isEmpty(emergencyNumbers)) { - // then read-only ecclist property since old RIL only uses this - emergencyNumbers = SystemProperties.get("ro.ril.ecclist"); - } - - if (!TextUtils.isEmpty(emergencyNumbers)) { - // searches through the comma-separated list for a match, - // return true if one is found. - for (String emergencyNum : emergencyNumbers.split(",")) { - // It is not possible to append additional digits to an emergency number to dial - // the number in Brazil - it won't connect. - if (useExactMatch || "BR".equalsIgnoreCase(defaultCountryIso)) { - if (number.equals(emergencyNum)) { - return true; - } - } else { - if (number.startsWith(emergencyNum)) { - return true; - } - } - } - // no matches found against the list! - return false; - } - - Rlog.d(LOG_TAG, "System property doesn't provide any emergency numbers." - + " Use embedded logic for determining ones."); - - // If slot id is invalid, means that there is no sim card. - // According spec 3GPP TS22.101, the following numbers should be - // ECC numbers when SIM/USIM is not present. - emergencyNumbers = ((slotId < 0) ? "112,911,000,08,110,118,119,999" : "112,911"); - - for (String emergencyNum : emergencyNumbers.split(",")) { - if (useExactMatch) { - if (number.equals(emergencyNum)) { - return true; - } - } else { - if (number.startsWith(emergencyNum)) { - return true; - } - } - } - - // No ecclist system property, so use our own list. - if (defaultCountryIso != null) { - ShortNumberInfo info = ShortNumberInfo.getInstance(); - if (useExactMatch) { - return info.isEmergencyNumber(number, defaultCountryIso); - } else { - return info.connectsToEmergencyNumber(number, defaultCountryIso); - } - } - - return false; - } - - /** * isVoiceMailNumber: checks a given number against the voicemail * number provided by the RIL and SIM card. The caller must have * the READ_PHONE_STATE credential. diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 348ab2a38716..11b667427aaf 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -5629,7 +5629,7 @@ public class TelephonyManager { if (value == null) { value = ""; } - + value.replace(',', ' '); if (prop != null) { p = prop.split(","); } @@ -5655,7 +5655,13 @@ public class TelephonyManager { } } - if (propVal.length() > SystemProperties.PROP_VALUE_MAX) { + int propValLen = propVal.length(); + try { + propValLen = propVal.getBytes("utf-8").length; + } catch (java.io.UnsupportedEncodingException e) { + Rlog.d(TAG, "setTelephonyProperty: utf-8 not supported"); + } + if (propValLen > SystemProperties.PROP_VALUE_MAX) { Rlog.d(TAG, "setTelephonyProperty: property too long phoneId=" + phoneId + " property=" + property + " value: " + value + " propVal=" + propVal); return; diff --git a/telephony/java/android/telephony/ims/RcsManager.java b/telephony/java/android/telephony/ims/RcsManager.java new file mode 100644 index 000000000000..d50b516b8754 --- /dev/null +++ b/telephony/java/android/telephony/ims/RcsManager.java @@ -0,0 +1,36 @@ +/* + * 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.telephony.ims; + +import android.annotation.SystemService; +import android.content.Context; + +/** + * The manager class for RCS related utilities. + * @hide + */ +@SystemService(Context.TELEPHONY_RCS_SERVICE) +public class RcsManager { + + private static final RcsMessageStore sRcsMessageStoreInstance = new RcsMessageStore(); + + /** + * Returns an instance of RcsMessageStore. + */ + public RcsMessageStore getRcsMessageStore() { + return sRcsMessageStoreInstance; + } +} diff --git a/telephony/java/android/telephony/rcs/RcsManager.java b/telephony/java/android/telephony/ims/RcsMessageStore.java index 0ef4e1552085..c89c0bebb1a1 100644 --- a/telephony/java/android/telephony/rcs/RcsManager.java +++ b/telephony/java/android/telephony/ims/RcsMessageStore.java @@ -14,24 +14,20 @@ * limitations under the License. */ -package android.telephony.rcs; +package android.telephony.ims; -import android.annotation.SystemService; -import android.content.Context; import android.os.RemoteException; import android.os.ServiceManager; import android.telephony.Rlog; - -import com.android.internal.telephony.rcs.IRcs; +import android.telephony.ims.aidl.IRcs; /** - * RcsManager is the application interface to RcsProvider and provides access methods to + * RcsMessageStore is the application interface to RcsProvider and provides access methods to * RCS related database tables. * @hide - TODO make this public */ -@SystemService(Context.TELEPHONY_RCS_SERVICE) -public class RcsManager { - private static final String TAG = "RcsManager"; +public class RcsMessageStore { + private static final String TAG = "RcsMessageStore"; private static final boolean VDBG = false; /** diff --git a/telephony/java/android/telephony/ims/RcsThread.aidl b/telephony/java/android/telephony/ims/RcsThread.aidl new file mode 100644 index 000000000000..79d473266272 --- /dev/null +++ b/telephony/java/android/telephony/ims/RcsThread.aidl @@ -0,0 +1,20 @@ +/* + * + * 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.telephony; + +parcelable RcsThread;
\ No newline at end of file diff --git a/telephony/java/android/telephony/rcs/RcsThread.java b/telephony/java/android/telephony/ims/RcsThread.java index 83eb973ec12b..b7f440d94583 100644 --- a/telephony/java/android/telephony/rcs/RcsThread.java +++ b/telephony/java/android/telephony/ims/RcsThread.java @@ -14,14 +14,13 @@ * limitations under the License. */ -package android.telephony.rcs; +package android.telephony.ims; import android.os.Parcel; import android.os.Parcelable; import android.os.RemoteException; import android.os.ServiceManager; - -import com.android.internal.telephony.rcs.IRcs; +import android.telephony.ims.aidl.IRcs; /** * RcsThread represents a single RCS conversation thread. It holds messages that were sent and diff --git a/telephony/java/com/android/internal/telephony/rcs/IRcs.aidl b/telephony/java/android/telephony/ims/aidl/IRcs.aidl index 4c289acd15ef..b2e2fadca138 100644 --- a/telephony/java/com/android/internal/telephony/rcs/IRcs.aidl +++ b/telephony/java/android/telephony/ims/aidl/IRcs.aidl @@ -14,10 +14,14 @@ * limitations under the License. */ -package com.android.internal.telephony.rcs; +package android.telephony.ims.aidl; +/** + * RPC definition between RCS storage APIs and phone process. + * {@hide} + */ interface IRcs { - // RcsManager APIs + // RcsMessageStore APIs void deleteThread(int threadId); // RcsThread APIs diff --git a/telephony/java/android/telephony/rcs/RcsThread.aidl b/telephony/java/android/telephony/rcs/RcsThread.aidl deleted file mode 100644 index e2e0da5da347..000000000000 --- a/telephony/java/android/telephony/rcs/RcsThread.aidl +++ /dev/null @@ -1,20 +0,0 @@ -/* -** -** 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.telephony; - -parcelable RcsThread;
\ No newline at end of file diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java index c9343171e03e..2ebe87067be3 100644 --- a/telephony/java/com/android/internal/telephony/RILConstants.java +++ b/telephony/java/com/android/internal/telephony/RILConstants.java @@ -421,6 +421,7 @@ public interface RILConstants { int RIL_REQUEST_SET_SIGNAL_STRENGTH_REPORTING_CRITERIA = 202; int RIL_REQUEST_SET_LINK_CAPACITY_REPORTING_CRITERIA = 203; int RIL_REQUEST_SET_PREFERRED_DATA_MODEM = 204; + int RIL_REQUEST_EMERGENCY_DIAL = 205; /* Responses begin */ int RIL_RESPONSE_ACKNOWLEDGEMENT = 800; diff --git a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java index eed8ae7c1f70..5ea8ff1c4861 100644 --- a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java +++ b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java @@ -39,7 +39,6 @@ import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileInputStream; -import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; @@ -840,6 +839,7 @@ public class AppLaunch extends InstrumentationTestCase { /* SAMPLE OUTPUT : Cold launch Starting: Intent { cmp=com.google.android.calculator/com.android.calculator2.Calculator } Status: ok + LaunchState: COLD Activity: com.google.android.calculator/com.android.calculator2.Calculator TotalTime: 357 WaitTime: 377 @@ -848,6 +848,7 @@ public class AppLaunch extends InstrumentationTestCase { Starting: Intent { cmp=com.google.android.calculator/com.android.calculator2.Calculator } Warning: Activity not started, its current task has been brought to the front Status: ok + LaunchState: HOT Activity: com.google.android.calculator/com.android.calculator2.CalculatorGoogle TotalTime: 60 WaitTime: 67 diff --git a/tests/RcsTests/src/com/android/tests/rcs/RcsManagerTest.java b/tests/RcsTests/src/com/android/tests/rcs/RcsMessageStoreTest.java index 7f5f03e0d5a4..290e04ce8abb 100644 --- a/tests/RcsTests/src/com/android/tests/rcs/RcsManagerTest.java +++ b/tests/RcsTests/src/com/android/tests/rcs/RcsMessageStoreTest.java @@ -16,17 +16,17 @@ package com.android.tests.rcs; import android.support.test.runner.AndroidJUnit4; -import android.telephony.rcs.RcsManager; +import android.telephony.ims.RcsMessageStore; import org.junit.Test; import org.junit.runner.RunWith; @RunWith(AndroidJUnit4.class) -public class RcsManagerTest { +public class RcsMessageStoreTest { //TODO(sahinc): Add meaningful tests once we have more of the implementation in place @Test public void testDeleteThreadDoesntCrash() { - RcsManager mRcsManager = new RcsManager(); - mRcsManager.deleteThread(0); + RcsMessageStore mRcsMessageStore = new RcsMessageStore(); + mRcsMessageStore.deleteThread(0); } } diff --git a/tests/net/java/android/net/apf/ApfTest.java b/tests/net/java/android/net/apf/ApfTest.java index 983802035bfb..436dd859beca 100644 --- a/tests/net/java/android/net/apf/ApfTest.java +++ b/tests/net/java/android/net/apf/ApfTest.java @@ -46,6 +46,7 @@ import android.support.test.runner.AndroidJUnit4; import android.system.ErrnoException; import android.system.Os; import android.text.format.DateUtils; +import android.util.Log; import com.android.frameworks.tests.net.R; import com.android.internal.util.HexDump; import java.io.File; @@ -89,6 +90,7 @@ public class ApfTest { System.loadLibrary("frameworksnettestsjni"); } + private static final String TAG = "ApfTest"; // Expected return codes from APF interpreter. private static final int PASS = 1; private static final int DROP = 0; @@ -869,6 +871,37 @@ public class ApfTest { } } + /** + * Generate APF program, run pcap file though APF filter, then check all the packets in the file + * should be dropped. + */ + @Test + public void testApfFilterPcapFile() throws Exception { + final byte[] MOCK_PCAP_IPV4_ADDR = {(byte) 172, 16, 7, (byte) 151}; + String pcapFilename = stageFile(R.raw.apfPcap); + MockIpClientCallback ipClientCallback = new MockIpClientCallback(); + LinkAddress link = new LinkAddress(InetAddress.getByAddress(MOCK_PCAP_IPV4_ADDR), 16); + LinkProperties lp = new LinkProperties(); + lp.addLinkAddress(link); + + ApfConfiguration config = getDefaultConfig(); + ApfCapabilities MOCK_APF_PCAP_CAPABILITIES = new ApfCapabilities(4, 1700, ARPHRD_ETHER); + config.apfCapabilities = MOCK_APF_PCAP_CAPABILITIES; + config.multicastFilter = DROP_MULTICAST; + config.ieee802_3Filter = DROP_802_3_FRAMES; + TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipClientCallback, mLog); + apfFilter.setLinkProperties(lp); + byte[] program = ipClientCallback.getApfProgram(); + byte[] data = new byte[ApfFilter.Counter.totalSize()]; + final boolean result; + + result = dropsAllPackets(program, data, pcapFilename); + Log.i(TAG, "testApfFilterPcapFile(): Data counters: " + HexDump.toHexString(data, false)); + + assertTrue("Failed to drop all packets by filter. \nAPF counters:" + + HexDump.toHexString(data, false), result); + } + private class MockIpClientCallback extends IpClient.Callback { private final ConditionVariable mGotApfProgram = new ConditionVariable(); private byte[] mLastApfProgram; @@ -1706,6 +1739,14 @@ public class ApfTest { private native static boolean compareBpfApf(String filter, String pcap_filename, byte[] apf_program); + + /** + * Open packet capture file {@code pcapFilename} and run it through APF filter. Then + * checks whether all the packets are dropped and populates data[] {@code data} with + * the APF counters. + */ + private native static boolean dropsAllPackets(byte[] program, byte[] data, String pcapFilename); + @Test public void testBroadcastAddress() throws Exception { assertEqualsIp("255.255.255.255", ApfFilter.ipv4BroadcastAddress(IPV4_ANY_HOST_ADDR, 0)); diff --git a/tests/net/java/com/android/server/connectivity/TetheringTest.java b/tests/net/java/com/android/server/connectivity/TetheringTest.java index 80818120fa3c..bca9be772704 100644 --- a/tests/net/java/com/android/server/connectivity/TetheringTest.java +++ b/tests/net/java/com/android/server/connectivity/TetheringTest.java @@ -71,7 +71,6 @@ import android.net.MacAddress; import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkInfo; -import android.net.NetworkRequest; import android.net.NetworkState; import android.net.NetworkUtils; import android.net.RouteInfo; @@ -130,10 +129,6 @@ public class TetheringTest { private static final String TEST_USB_IFNAME = "test_rndis0"; private static final String TEST_WLAN_IFNAME = "test_wlan0"; - // Actual contents of the request don't matter for this test. The lack of - // any specific TRANSPORT_* is sufficient to identify this request. - private static final NetworkRequest mDefaultRequest = new NetworkRequest.Builder().build(); - @Mock private ApplicationInfo mApplicationInfo; @Mock private Context mContext; @Mock private INetworkManagementService mNMService; @@ -257,11 +252,6 @@ public class TetheringTest { isTetheringSupportedCalls++; return true; } - - @Override - public NetworkRequest getDefaultNetworkRequest() { - return mDefaultRequest; - } } private static NetworkState buildMobileUpstreamState(boolean withIPv4, boolean withIPv6, @@ -496,7 +486,7 @@ public class TetheringTest { TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_LOCAL_ONLY); verifyNoMoreInteractions(mWifiManager); verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_ACTIVE_LOCAL_ONLY); - verify(mUpstreamNetworkMonitor, times(1)).start(any(NetworkRequest.class)); + verify(mUpstreamNetworkMonitor, times(1)).startObserveAllNetworks(); // TODO: Figure out why this isn't exactly once, for sendTetherStateChangedBroadcast(). assertTrue(1 <= mTetheringDependencies.isTetheringSupportedCalls); @@ -730,7 +720,7 @@ public class TetheringTest { TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_TETHERED); verifyNoMoreInteractions(mWifiManager); verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_ACTIVE_TETHER); - verify(mUpstreamNetworkMonitor, times(1)).start(any(NetworkRequest.class)); + verify(mUpstreamNetworkMonitor, times(1)).startObserveAllNetworks(); // In tethering mode, in the default configuration, an explicit request // for a mobile network is also made. verify(mUpstreamNetworkMonitor, times(1)).registerMobileNetworkRequest(); diff --git a/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java b/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java index a22cbd4c95d8..0afd607d1457 100644 --- a/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java +++ b/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java @@ -24,6 +24,7 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN; import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -53,7 +54,6 @@ import android.net.NetworkCapabilities; import android.net.NetworkRequest; import android.net.NetworkState; import android.net.util.SharedLog; - import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; @@ -65,7 +65,6 @@ import org.junit.Before; import org.junit.runner.RunWith; import org.junit.Test; import org.mockito.Mock; -import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import java.util.ArrayList; @@ -126,7 +125,7 @@ public class UpstreamNetworkMonitorTest { } @Test - public void testDoesNothingBeforeStarted() { + public void testDoesNothingBeforeTrackDefaultAndStarted() throws Exception { assertTrue(mCM.hasNoCallbacks()); assertFalse(mUNM.mobileNetworkRequested()); @@ -138,37 +137,40 @@ public class UpstreamNetworkMonitorTest { @Test public void testDefaultNetworkIsTracked() throws Exception { - assertEquals(0, mCM.trackingDefault.size()); + assertTrue(mCM.hasNoCallbacks()); + mUNM.startTrackDefaultNetwork(mDefaultRequest); - mUNM.start(mDefaultRequest); + mUNM.startObserveAllNetworks(); assertEquals(1, mCM.trackingDefault.size()); mUNM.stop(); - assertTrue(mCM.hasNoCallbacks()); + assertTrue(mCM.onlyHasDefaultCallbacks()); } @Test public void testListensForAllNetworks() throws Exception { assertTrue(mCM.listening.isEmpty()); - mUNM.start(mDefaultRequest); + mUNM.startTrackDefaultNetwork(mDefaultRequest); + mUNM.startObserveAllNetworks(); assertFalse(mCM.listening.isEmpty()); assertTrue(mCM.isListeningForAll()); mUNM.stop(); - assertTrue(mCM.hasNoCallbacks()); + assertTrue(mCM.onlyHasDefaultCallbacks()); } @Test public void testCallbacksRegistered() { - mUNM.start(mDefaultRequest); - verify(mCM, times(1)).registerNetworkCallback( - any(NetworkRequest.class), any(NetworkCallback.class), any(Handler.class)); + mUNM.startTrackDefaultNetwork(mDefaultRequest); verify(mCM, times(1)).requestNetwork( eq(mDefaultRequest), any(NetworkCallback.class), any(Handler.class)); + mUNM.startObserveAllNetworks(); + verify(mCM, times(1)).registerNetworkCallback( + any(NetworkRequest.class), any(NetworkCallback.class), any(Handler.class)); mUNM.stop(); - verify(mCM, times(2)).unregisterNetworkCallback(any(NetworkCallback.class)); + verify(mCM, times(1)).unregisterNetworkCallback(any(NetworkCallback.class)); } @Test @@ -176,7 +178,7 @@ public class UpstreamNetworkMonitorTest { assertFalse(mUNM.mobileNetworkRequested()); assertEquals(0, mCM.requested.size()); - mUNM.start(mDefaultRequest); + mUNM.startObserveAllNetworks(); assertFalse(mUNM.mobileNetworkRequested()); assertEquals(0, mCM.requested.size()); @@ -199,11 +201,9 @@ public class UpstreamNetworkMonitorTest { assertFalse(mUNM.mobileNetworkRequested()); assertEquals(0, mCM.requested.size()); - mUNM.start(mDefaultRequest); + mUNM.startObserveAllNetworks(); verify(mCM, times(1)).registerNetworkCallback( any(NetworkRequest.class), any(NetworkCallback.class), any(Handler.class)); - verify(mCM, times(1)).requestNetwork( - eq(mDefaultRequest), any(NetworkCallback.class), any(Handler.class)); assertFalse(mUNM.mobileNetworkRequested()); assertEquals(0, mCM.requested.size()); @@ -227,7 +227,7 @@ public class UpstreamNetworkMonitorTest { assertTrue(mCM.isDunRequested()); mUNM.stop(); - verify(mCM, times(3)).unregisterNetworkCallback(any(NetworkCallback.class)); + verify(mCM, times(2)).unregisterNetworkCallback(any(NetworkCallback.class)); verifyNoMoreInteractions(mCM); } @@ -237,7 +237,7 @@ public class UpstreamNetworkMonitorTest { assertFalse(mUNM.mobileNetworkRequested()); assertEquals(0, mCM.requested.size()); - mUNM.start(mDefaultRequest); + mUNM.startObserveAllNetworks(); assertFalse(mUNM.mobileNetworkRequested()); assertEquals(0, mCM.requested.size()); @@ -257,7 +257,7 @@ public class UpstreamNetworkMonitorTest { @Test public void testUpdateMobileRequiresDun() throws Exception { - mUNM.start(mDefaultRequest); + mUNM.startObserveAllNetworks(); // Test going from no-DUN to DUN correctly re-registers callbacks. mUNM.updateMobileRequiresDun(false); @@ -285,7 +285,8 @@ public class UpstreamNetworkMonitorTest { final Collection<Integer> preferredTypes = new ArrayList<>(); preferredTypes.add(TYPE_WIFI); - mUNM.start(mDefaultRequest); + mUNM.startTrackDefaultNetwork(mDefaultRequest); + mUNM.startObserveAllNetworks(); // There are no networks, so there is nothing to select. assertSatisfiesLegacyType(TYPE_NONE, mUNM.selectPreferredUpstreamType(preferredTypes)); @@ -350,7 +351,8 @@ public class UpstreamNetworkMonitorTest { @Test public void testGetCurrentPreferredUpstream() throws Exception { - mUNM.start(mDefaultRequest); + mUNM.startTrackDefaultNetwork(mDefaultRequest); + mUNM.startObserveAllNetworks(); mUNM.updateMobileRequiresDun(false); // [0] Mobile connects, DUN not required -> mobile selected. @@ -389,7 +391,8 @@ public class UpstreamNetworkMonitorTest { @Test public void testLocalPrefixes() throws Exception { - mUNM.start(mDefaultRequest); + mUNM.startTrackDefaultNetwork(mDefaultRequest); + mUNM.startObserveAllNetworks(); // [0] Test minimum set of local prefixes. Set<IpPrefix> local = mUNM.getLocalPrefixes(); @@ -521,11 +524,19 @@ public class UpstreamNetworkMonitorTest { } boolean hasNoCallbacks() { - return allCallbacks.isEmpty() && - trackingDefault.isEmpty() && - listening.isEmpty() && - requested.isEmpty() && - legacyTypeMap.isEmpty(); + return allCallbacks.isEmpty() + && trackingDefault.isEmpty() + && listening.isEmpty() + && requested.isEmpty() + && legacyTypeMap.isEmpty(); + } + + boolean onlyHasDefaultCallbacks() { + return (allCallbacks.size() == 1) + && (trackingDefault.size() == 1) + && listening.isEmpty() + && requested.isEmpty() + && legacyTypeMap.isEmpty(); } boolean isListeningForAll() { diff --git a/tests/net/jni/apf_jni.cpp b/tests/net/jni/apf_jni.cpp index 1ea9e274ab9e..4222adf9e06b 100644 --- a/tests/net/jni/apf_jni.cpp +++ b/tests/net/jni/apf_jni.cpp @@ -21,37 +21,40 @@ #include <stdlib.h> #include <string> #include <utils/Log.h> +#include <vector> #include "apf_interpreter.h" +#include "nativehelper/scoped_primitive_array.h" #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) // JNI function acting as simply call-through to native APF interpreter. static jint com_android_server_ApfTest_apfSimulate( - JNIEnv* env, jclass, jbyteArray program, jbyteArray packet, - jbyteArray data, jint filter_age) { - uint8_t* program_raw = (uint8_t*)env->GetByteArrayElements(program, nullptr); - uint8_t* packet_raw = (uint8_t*)env->GetByteArrayElements(packet, nullptr); - uint8_t* data_raw = (uint8_t*)(data ? env->GetByteArrayElements(data, nullptr) : nullptr); - uint32_t program_len = env->GetArrayLength(program); - uint32_t packet_len = env->GetArrayLength(packet); - uint32_t data_len = data ? env->GetArrayLength(data) : 0; - - // Merge program and data into a single buffer. - uint8_t* program_and_data = (uint8_t*)malloc(program_len + data_len); - memcpy(program_and_data, program_raw, program_len); - memcpy(program_and_data + program_len, data_raw, data_len); + JNIEnv* env, jclass, jbyteArray jprogram, jbyteArray jpacket, + jbyteArray jdata, jint filter_age) { + + ScopedByteArrayRO packet(env, jpacket); + uint32_t packet_len = (uint32_t)packet.size(); + uint32_t program_len = env->GetArrayLength(jprogram); + uint32_t data_len = jdata ? env->GetArrayLength(jdata) : 0; + std::vector<uint8_t> buf(program_len + data_len, 0); + + env->GetByteArrayRegion(jprogram, 0, program_len, reinterpret_cast<jbyte*>(buf.data())); + if (jdata) { + // Merge program and data into a single buffer. + env->GetByteArrayRegion(jdata, 0, data_len, + reinterpret_cast<jbyte*>(buf.data() + program_len)); + } jint result = - accept_packet(program_and_data, program_len, program_len + data_len, - packet_raw, packet_len, filter_age); - if (data) { - memcpy(data_raw, program_and_data + program_len, data_len); - env->ReleaseByteArrayElements(data, (jbyte*)data_raw, 0 /* copy back */); - } - free(program_and_data); - env->ReleaseByteArrayElements(packet, (jbyte*)packet_raw, JNI_ABORT); - env->ReleaseByteArrayElements(program, (jbyte*)program_raw, JNI_ABORT); + accept_packet(buf.data(), program_len, program_len + data_len, + reinterpret_cast<const uint8_t*>(packet.get()), packet_len, filter_age); + + if (jdata) { + env->SetByteArrayRegion(jdata, 0, data_len, + reinterpret_cast<jbyte*>(buf.data() + program_len)); + } + return result; } @@ -118,8 +121,7 @@ static jboolean com_android_server_ApfTest_compareBpfApf(JNIEnv* env, jclass, js jstring jpcap_filename, jbyteArray japf_program) { ScopedUtfChars filter(env, jfilter); ScopedUtfChars pcap_filename(env, jpcap_filename); - uint8_t* apf_program = (uint8_t*)env->GetByteArrayElements(japf_program, NULL); - uint32_t apf_program_len = env->GetArrayLength(japf_program); + ScopedByteArrayRO apf_program(env, japf_program); // Open pcap file for BPF filtering ScopedFILE bpf_fp(fopen(pcap_filename.c_str(), "rb")); @@ -161,14 +163,15 @@ static jboolean com_android_server_ApfTest_compareBpfApf(JNIEnv* env, jclass, js do { apf_packet = pcap_next(apf_pcap.get(), &apf_header); } while (apf_packet != NULL && !accept_packet( - apf_program, apf_program_len, 0 /* data_len */, + reinterpret_cast<uint8_t*>(const_cast<int8_t*>(apf_program.get())), + apf_program.size(), 0 /* data_len */, apf_packet, apf_header.len, 0 /* filter_age */)); // Make sure both filters matched the same packet. if (apf_packet == NULL && bpf_packet == NULL) - break; + break; if (apf_packet == NULL || bpf_packet == NULL) - return false; + return false; if (apf_header.len != bpf_header.len || apf_header.ts.tv_sec != bpf_header.ts.tv_sec || apf_header.ts.tv_usec != bpf_header.ts.tv_usec || @@ -178,6 +181,48 @@ static jboolean com_android_server_ApfTest_compareBpfApf(JNIEnv* env, jclass, js return true; } +static jboolean com_android_server_ApfTest_dropsAllPackets(JNIEnv* env, jclass, jbyteArray jprogram, + jbyteArray jdata, jstring jpcap_filename) { + ScopedUtfChars pcap_filename(env, jpcap_filename); + ScopedByteArrayRO apf_program(env, jprogram); + uint32_t apf_program_len = (uint32_t)apf_program.size(); + uint32_t data_len = env->GetArrayLength(jdata); + pcap_pkthdr apf_header; + const uint8_t* apf_packet; + char pcap_error[PCAP_ERRBUF_SIZE]; + std::vector<uint8_t> buf(apf_program_len + data_len, 0); + + // Merge program and data into a single buffer. + env->GetByteArrayRegion(jprogram, 0, apf_program_len, reinterpret_cast<jbyte*>(buf.data())); + env->GetByteArrayRegion(jdata, 0, data_len, + reinterpret_cast<jbyte*>(buf.data() + apf_program_len)); + + // Open pcap file + ScopedFILE apf_fp(fopen(pcap_filename.c_str(), "rb")); + ScopedPcap apf_pcap(pcap_fopen_offline(apf_fp.get(), pcap_error)); + + if (apf_pcap.get() == NULL) { + throwException(env, "pcap_fopen_offline failed: " + std::string(pcap_error)); + return false; + } + + while ((apf_packet = pcap_next(apf_pcap.get(), &apf_header)) != NULL) { + int result = accept_packet(buf.data(), apf_program_len, + apf_program_len + data_len, apf_packet, apf_header.len, 0); + + // Return false once packet passes the filter + if (result) { + env->SetByteArrayRegion(jdata, 0, data_len, + reinterpret_cast<jbyte*>(buf.data() + apf_program_len)); + return false; + } + } + + env->SetByteArrayRegion(jdata, 0, data_len, + reinterpret_cast<jbyte*>(buf.data() + apf_program_len)); + return true; +} + extern "C" jint JNI_OnLoad(JavaVM* vm, void*) { JNIEnv *env; if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) { @@ -192,6 +237,8 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void*) { (void*)com_android_server_ApfTest_compileToBpf }, { "compareBpfApf", "(Ljava/lang/String;Ljava/lang/String;[B)Z", (void*)com_android_server_ApfTest_compareBpfApf }, + { "dropsAllPackets", "([B[BLjava/lang/String;)Z", + (void*)com_android_server_ApfTest_dropsAllPackets }, }; jniRegisterNativeMethods(env, "android/net/apf/ApfTest", diff --git a/tests/net/res/raw/apfPcap.pcap b/tests/net/res/raw/apfPcap.pcap Binary files differnew file mode 100644 index 000000000000..6f69c4add0f8 --- /dev/null +++ b/tests/net/res/raw/apfPcap.pcap diff --git a/tools/apilint/apilint.py b/tools/apilint/apilint.py index cb8fef946baf..b5a990e6e3cf 100644 --- a/tools/apilint/apilint.py +++ b/tools/apilint/apilint.py @@ -183,6 +183,11 @@ class Class(): self.name = self.fullname[self.fullname.rindex(".")+1:] + def merge_from(self, other): + self.ctors.extend(other.ctors) + self.fields.extend(other.fields) + self.methods.extend(other.methods) + def __hash__(self): return hash((self.raw, tuple(self.ctors), tuple(self.fields), tuple(self.methods))) @@ -204,9 +209,28 @@ class Package(): return self.raw -def _parse_stream(f, clazz_cb=None): - line = 0 +def _parse_stream(f, clazz_cb=None, base_f=None): api = {} + + if base_f: + base_classes = _parse_stream_to_generator(base_f) + else: + base_classes = [] + + for clazz in _parse_stream_to_generator(f): + base_class = _parse_to_matching_class(base_classes, clazz) + if base_class: + clazz.merge_from(base_class) + + if clazz_cb: + clazz_cb(clazz) + else: # In callback mode, don't keep track of the full API + api[clazz.fullname] = clazz + + return api + +def _parse_stream_to_generator(f): + line = 0 pkg = None clazz = None blame = None @@ -225,26 +249,41 @@ def _parse_stream(f, clazz_cb=None): if raw.startswith("package"): pkg = Package(line, raw, blame) elif raw.startswith(" ") and raw.endswith("{"): - # When provided with class callback, we treat as incremental - # parse and don't build up entire API - if clazz and clazz_cb: - clazz_cb(clazz) clazz = Class(pkg, line, raw, blame) - if not clazz_cb: - api[clazz.fullname] = clazz elif raw.startswith(" ctor"): clazz.ctors.append(Method(clazz, line, raw, blame)) elif raw.startswith(" method"): clazz.methods.append(Method(clazz, line, raw, blame)) elif raw.startswith(" field"): clazz.fields.append(Field(clazz, line, raw, blame)) + elif raw.startswith(" }") and clazz: + while True: + retry = yield clazz + if not retry: + break + # send() was called, asking us to redeliver clazz on next(). Still need to yield + # a dummy value to the send() first though. + if (yield "Returning clazz on next()"): + raise TypeError("send() must be followed by next(), not send()") - # Handle last trailing class - if clazz and clazz_cb: - clazz_cb(clazz) - return api +def _parse_to_matching_class(classes, needle): + """Takes a classes generator and parses it until it returns the class we're looking for + + This relies on classes being sorted by package and class name.""" + for clazz in classes: + if clazz.pkg.name < needle.pkg.name: + # We haven't reached the right package yet + continue + if clazz.name < needle.name: + # We haven't reached the right class yet + continue + if clazz.fullname == needle.fullname: + return clazz + # We ran past the right class. Send it back into the generator, then report failure. + classes.send(clazz) + return None class Failure(): def __init__(self, sig, clazz, detail, error, rule, msg): @@ -1504,12 +1543,12 @@ def examine_clazz(clazz): verify_singleton(clazz) -def examine_stream(stream): +def examine_stream(stream, base_stream=None): """Find all style issues in the given API stream.""" global failures, noticed failures = {} noticed = {} - _parse_stream(stream, examine_clazz) + _parse_stream(stream, examine_clazz, base_f=base_stream) return (failures, noticed) @@ -1650,6 +1689,12 @@ if __name__ == "__main__": parser.add_argument("current.txt", type=argparse.FileType('r'), help="current.txt") parser.add_argument("previous.txt", nargs='?', type=argparse.FileType('r'), default=None, help="previous.txt") + parser.add_argument("--base-current", nargs='?', type=argparse.FileType('r'), default=None, + help="The base current.txt to use when examining system-current.txt or" + " test-current.txt") + parser.add_argument("--base-previous", nargs='?', type=argparse.FileType('r'), default=None, + help="The base previous.txt to use when examining system-previous.txt or" + " test-previous.txt") parser.add_argument("--no-color", action='store_const', const=True, help="Disable terminal colors") parser.add_argument("--allow-google", action='store_const', const=True, @@ -1669,7 +1714,9 @@ if __name__ == "__main__": ALLOW_GOOGLE = True current_file = args['current.txt'] + base_current_file = args['base_current'] previous_file = args['previous.txt'] + base_previous_file = args['base_previous'] if args['show_deprecations_at_birth']: with current_file as f: @@ -1688,10 +1735,18 @@ if __name__ == "__main__": sys.exit() with current_file as f: - cur_fail, cur_noticed = examine_stream(f) + if base_current_file: + with base_current_file as base_f: + cur_fail, cur_noticed = examine_stream(f, base_f) + else: + cur_fail, cur_noticed = examine_stream(f) if not previous_file is None: with previous_file as f: - prev_fail, prev_noticed = examine_stream(f) + if base_previous_file: + with base_previous_file as base_f: + prev_fail, prev_noticed = examine_stream(f, base_f) + else: + prev_fail, prev_noticed = examine_stream(f) # ignore errors from previous API level for p in prev_fail: |