diff options
127 files changed, 2362 insertions, 1651 deletions
diff --git a/Android.bp b/Android.bp index e19ca8465548..9b62b7af4558 100644 --- a/Android.bp +++ b/Android.bp @@ -49,8 +49,6 @@ java_defaults { "rs/java/**/*.java", ":framework-javastream-protos", - // TODO: Resolve circular library dependency and remove media1-srcs - ":media1-srcs", "core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl", "core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl", @@ -505,7 +503,11 @@ java_defaults { "media/java/android/media/session/ICallback.aidl", "media/java/android/media/session/IOnMediaKeyListener.aidl", "media/java/android/media/session/IOnVolumeKeyLongPressListener.aidl", + "media/java/android/media/session/ISession.aidl", "media/java/android/media/session/ISession2TokensListener.aidl", + "media/java/android/media/session/ISessionCallback.aidl", + "media/java/android/media/session/ISessionController.aidl", + "media/java/android/media/session/ISessionControllerCallback.aidl", "media/java/android/media/session/ISessionManager.aidl", "media/java/android/media/soundtrigger/ISoundTriggerDetectionService.aidl", "media/java/android/media/soundtrigger/ISoundTriggerDetectionServiceClient.aidl", @@ -520,6 +522,8 @@ java_defaults { "media/java/android/media/tv/ITvInputSessionCallback.aidl", "media/java/android/media/tv/ITvRemoteProvider.aidl", "media/java/android/media/tv/ITvRemoteServiceInput.aidl", + "media/java/android/service/media/IMediaBrowserService.aidl", + "media/java/android/service/media/IMediaBrowserServiceCallbacks.aidl", "telecomm/java/com/android/internal/telecom/ICallRedirectionAdapter.aidl", "telecomm/java/com/android/internal/telecom/ICallRedirectionService.aidl", "telecomm/java/com/android/internal/telecom/ICallScreeningAdapter.aidl", diff --git a/api/current.txt b/api/current.txt index 3b6cfe3a3cee..4a1fccf0b5ae 100644 --- a/api/current.txt +++ b/api/current.txt @@ -11233,6 +11233,7 @@ package android.content.pm { public class LauncherApps { method public java.util.List<android.content.pm.LauncherActivityInfo> getActivityList(String, android.os.UserHandle); + method @NonNull public java.util.List<android.content.pm.PackageInstaller.SessionInfo> getAllPackageInstallerSessions(); method @Nullable public android.content.pm.LauncherApps.AppUsageLimit getAppUsageLimit(String, android.os.UserHandle); method public android.content.pm.ApplicationInfo getApplicationInfo(@NonNull String, int, @NonNull android.os.UserHandle) throws android.content.pm.PackageManager.NameNotFoundException; method public android.content.pm.LauncherApps.PinItemRequest getPinItemRequest(android.content.Intent); @@ -11249,13 +11250,16 @@ package android.content.pm { method public void pinShortcuts(@NonNull String, @NonNull java.util.List<java.lang.String>, @NonNull android.os.UserHandle); method public void registerCallback(android.content.pm.LauncherApps.Callback); method public void registerCallback(android.content.pm.LauncherApps.Callback, android.os.Handler); + method public void registerPackageInstallerSessionCallback(@NonNull java.util.concurrent.Executor, @NonNull android.content.pm.PackageInstaller.SessionCallback); method public android.content.pm.LauncherActivityInfo resolveActivity(android.content.Intent, android.os.UserHandle); method public boolean shouldHideFromSuggestions(@NonNull String, @NonNull android.os.UserHandle); method public void startAppDetailsActivity(android.content.ComponentName, android.os.UserHandle, android.graphics.Rect, android.os.Bundle); method public void startMainActivity(android.content.ComponentName, android.os.UserHandle, android.graphics.Rect, android.os.Bundle); + method public void startPackageInstallerSessionDetailsActivity(android.content.pm.PackageInstaller.SessionInfo, android.graphics.Rect, android.os.Bundle); method public void startShortcut(@NonNull String, @NonNull String, @Nullable android.graphics.Rect, @Nullable android.os.Bundle, @NonNull android.os.UserHandle); method public void startShortcut(@NonNull android.content.pm.ShortcutInfo, @Nullable android.graphics.Rect, @Nullable android.os.Bundle); method public void unregisterCallback(android.content.pm.LauncherApps.Callback); + method public void unregisterPackageInstallerSessionCallback(android.content.pm.PackageInstaller.SessionCallback); field public static final String ACTION_CONFIRM_PIN_APPWIDGET = "android.content.pm.action.CONFIRM_PIN_APPWIDGET"; field public static final String ACTION_CONFIRM_PIN_SHORTCUT = "android.content.pm.action.CONFIRM_PIN_SHORTCUT"; field public static final String EXTRA_PIN_ITEM_REQUEST = "android.content.pm.extra.PIN_ITEM_REQUEST"; @@ -11445,6 +11449,7 @@ package android.content.pm { method public long getSize(); method public int getStagedSessionErrorCode(); method public String getStagedSessionErrorMessage(); + method public android.os.UserHandle getUser(); method public boolean isActive(); method public boolean isMultiPackage(); method public boolean isSealed(); @@ -13552,10 +13557,12 @@ package android.graphics { method public static android.graphics.Bitmap createScaledBitmap(@NonNull android.graphics.Bitmap, int, int, boolean); method public int describeContents(); method public void eraseColor(@ColorInt int); + method public void eraseColor(@ColorLong long); method @CheckResult public android.graphics.Bitmap extractAlpha(); method @CheckResult public android.graphics.Bitmap extractAlpha(android.graphics.Paint, int[]); method public int getAllocationByteCount(); method public int getByteCount(); + method public android.graphics.Color getColor(int, int); method @Nullable public android.graphics.ColorSpace getColorSpace(); method public android.graphics.Bitmap.Config getConfig(); method public int getDensity(); @@ -13581,6 +13588,7 @@ package android.graphics { method public void reconfigure(int, int, android.graphics.Bitmap.Config); method public void recycle(); method public boolean sameAs(android.graphics.Bitmap); + method public void setColorSpace(@NonNull android.graphics.ColorSpace); method public void setConfig(android.graphics.Bitmap.Config); method public void setDensity(int); method public void setHasAlpha(boolean); @@ -14382,6 +14390,7 @@ package android.graphics { method @Nullable public android.graphics.BlendMode getBlendMode(); method @ColorInt public int getColor(); method public android.graphics.ColorFilter getColorFilter(); + method @ColorLong public long getColorLong(); method public boolean getFillPath(android.graphics.Path, android.graphics.Path); method public int getFlags(); method public String getFontFeatureSettings(); @@ -14402,6 +14411,7 @@ package android.graphics { method public float getRunAdvance(CharSequence, int, int, int, int, boolean, int); method public android.graphics.Shader getShader(); method @ColorInt public int getShadowLayerColor(); + method @ColorLong public long getShadowLayerColorLong(); method public float getShadowLayerDx(); method public float getShadowLayerDy(); method public float getShadowLayerRadius(); @@ -14456,6 +14466,7 @@ package android.graphics { method public void setAntiAlias(boolean); method public void setBlendMode(@Nullable android.graphics.BlendMode); method public void setColor(@ColorInt int); + method public void setColor(@ColorLong long); method public android.graphics.ColorFilter setColorFilter(android.graphics.ColorFilter); method public void setDither(boolean); method public void setElegantTextHeight(boolean); @@ -14472,6 +14483,7 @@ package android.graphics { method public android.graphics.PathEffect setPathEffect(android.graphics.PathEffect); method public android.graphics.Shader setShader(android.graphics.Shader); method public void setShadowLayer(float, float, float, @ColorInt int); + method public void setShadowLayer(float, float, float, @ColorLong long); method public void setStrikeThruText(boolean); method public void setStrokeCap(android.graphics.Paint.Cap); method public void setStrokeJoin(android.graphics.Paint.Join); @@ -25575,6 +25587,14 @@ package android.media { field public static final int PLAYER_STATE_PAUSED = 1003; // 0x3eb field public static final int PLAYER_STATE_PLAYING = 1004; // 0x3ec field public static final int PLAYER_STATE_PREPARED = 1002; // 0x3ea + field public static final int PREPARE_DRM_STATUS_KEY_EXCHANGE_ERROR = 7; // 0x7 + field public static final int PREPARE_DRM_STATUS_PREPARATION_ERROR = 3; // 0x3 + field public static final int PREPARE_DRM_STATUS_PROVISIONING_NETWORK_ERROR = 1; // 0x1 + field public static final int PREPARE_DRM_STATUS_PROVISIONING_SERVER_ERROR = 2; // 0x2 + field public static final int PREPARE_DRM_STATUS_RESOURCE_BUSY = 5; // 0x5 + field public static final int PREPARE_DRM_STATUS_RESTORE_ERROR = 6; // 0x6 + field public static final int PREPARE_DRM_STATUS_SUCCESS = 0; // 0x0 + field public static final int PREPARE_DRM_STATUS_UNSUPPORTED_SCHEME = 4; // 0x4 field public static final int SEEK_CLOSEST = 3; // 0x3 field public static final int SEEK_CLOSEST_SYNC = 2; // 0x2 field public static final int SEEK_NEXT_SYNC = 1; // 0x1 @@ -38490,13 +38510,13 @@ package android.provider { field public static final String BUCKET_ID = "bucket_id"; field public static final String DATE_TAKEN = "datetaken"; field public static final String DESCRIPTION = "description"; + field public static final String GROUP_ID = "group_id"; field public static final String IS_PRIVATE = "isprivate"; field @Deprecated public static final String LATITUDE = "latitude"; field @Deprecated public static final String LONGITUDE = "longitude"; field @Deprecated public static final String MINI_THUMB_MAGIC = "mini_thumb_magic"; field public static final String ORIENTATION = "orientation"; field @Deprecated public static final String PICASA_ID = "picasa_id"; - field public static final String SECONDARY_BUCKET_ID = "secondary_bucket_id"; } public static final class MediaStore.Images.Media implements android.provider.MediaStore.Images.ImageColumns { @@ -38550,6 +38570,8 @@ package android.provider { field public static final String IS_TRASHED = "is_trashed"; field public static final String MIME_TYPE = "mime_type"; field public static final String OWNER_PACKAGE_NAME = "owner_package_name"; + field public static final String PRIMARY_DIRECTORY = "primary_directory"; + field public static final String SECONDARY_DIRECTORY = "secondary_directory"; field public static final String SIZE = "_size"; field public static final String TITLE = "title"; field public static final String WIDTH = "width"; @@ -38617,13 +38639,13 @@ package android.provider { field public static final String DATE_TAKEN = "datetaken"; field public static final String DESCRIPTION = "description"; field public static final String DURATION = "duration"; + field public static final String GROUP_ID = "group_id"; field public static final String IS_PRIVATE = "isprivate"; field public static final String LANGUAGE = "language"; field @Deprecated public static final String LATITUDE = "latitude"; field @Deprecated public static final String LONGITUDE = "longitude"; field @Deprecated public static final String MINI_THUMB_MAGIC = "mini_thumb_magic"; field public static final String RESOLUTION = "resolution"; - field public static final String SECONDARY_BUCKET_ID = "secondary_bucket_id"; field public static final String TAGS = "tags"; } @@ -38847,6 +38869,7 @@ package android.provider { field @Deprecated public static final int LOCATION_MODE_BATTERY_SAVING = 2; // 0x2 field @Deprecated public static final int LOCATION_MODE_HIGH_ACCURACY = 3; // 0x3 field @Deprecated public static final int LOCATION_MODE_OFF = 0; // 0x0 + field @Deprecated public static final int LOCATION_MODE_ON = 3; // 0x3 field @Deprecated public static final int LOCATION_MODE_SENSORS_ONLY = 1; // 0x1 field @Deprecated public static final String LOCATION_PROVIDERS_ALLOWED = "location_providers_allowed"; field @Deprecated public static final String LOCK_PATTERN_ENABLED = "lock_pattern_autolock"; @@ -41871,10 +41894,6 @@ package android.service.voice { method public void showSession(android.os.Bundle, int); field public static final String SERVICE_INTERFACE = "android.service.voice.VoiceInteractionService"; field public static final String SERVICE_META_DATA = "android.voice_interaction"; - field public static final int VOICE_STATE_CONDITIONAL_LISTENING = 1; // 0x1 - field public static final int VOICE_STATE_FULFILLING = 3; // 0x3 - field public static final int VOICE_STATE_LISTENING = 2; // 0x2 - field public static final int VOICE_STATE_NONE = 0; // 0x0 } public class VoiceInteractionSession implements android.content.ComponentCallbacks2 android.view.KeyEvent.Callback { diff --git a/api/system-current.txt b/api/system-current.txt index d061d01ac9b4..75f54f9b2301 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -3675,7 +3675,7 @@ package android.media.session { } public final class MediaSessionEngine implements java.lang.AutoCloseable { - ctor public MediaSessionEngine(@NonNull android.content.Context, @NonNull android.media.session.SessionLink, @NonNull android.media.session.SessionCallbackLink, @NonNull android.media.session.MediaSessionEngine.CallbackStub); + ctor public MediaSessionEngine(@NonNull android.content.Context, @NonNull android.media.session.SessionLink, @NonNull android.media.session.SessionCallbackLink); method public void close(); method public String getCallingPackage(); method @NonNull public android.media.session.MediaController getController(); @@ -3700,33 +3700,6 @@ package android.media.session { method public void setSessionActivity(@Nullable android.app.PendingIntent); } - public static final class MediaSessionEngine.CallbackStub { - ctor public MediaSessionEngine.CallbackStub(); - method public void onAdjustVolume(String, int, int, android.media.session.ControllerCallbackLink, int); - method public void onCommand(String, int, int, android.media.session.ControllerCallbackLink, String, android.os.Bundle, android.os.ResultReceiver); - method public void onCustomAction(String, int, int, android.media.session.ControllerCallbackLink, String, android.os.Bundle); - method public void onFastForward(String, int, int, android.media.session.ControllerCallbackLink); - method public void onMediaButton(String, int, int, android.content.Intent, int, android.os.ResultReceiver); - method public void onMediaButtonFromController(String, int, int, android.media.session.ControllerCallbackLink, android.content.Intent); - method public void onNext(String, int, int, android.media.session.ControllerCallbackLink); - method public void onPause(String, int, int, android.media.session.ControllerCallbackLink); - method public void onPlay(String, int, int, android.media.session.ControllerCallbackLink); - method public void onPlayFromMediaId(String, int, int, android.media.session.ControllerCallbackLink, String, android.os.Bundle); - method public void onPlayFromSearch(String, int, int, android.media.session.ControllerCallbackLink, String, android.os.Bundle); - method public void onPlayFromUri(String, int, int, android.media.session.ControllerCallbackLink, android.net.Uri, android.os.Bundle); - method public void onPrepare(String, int, int, android.media.session.ControllerCallbackLink); - method public void onPrepareFromMediaId(String, int, int, android.media.session.ControllerCallbackLink, String, android.os.Bundle); - method public void onPrepareFromSearch(String, int, int, android.media.session.ControllerCallbackLink, String, android.os.Bundle); - method public void onPrepareFromUri(String, int, int, android.media.session.ControllerCallbackLink, android.net.Uri, android.os.Bundle); - method public void onPrevious(String, int, int, android.media.session.ControllerCallbackLink); - method public void onRate(String, int, int, android.media.session.ControllerCallbackLink, android.media.Rating); - method public void onRewind(String, int, int, android.media.session.ControllerCallbackLink); - method public void onSeekTo(String, int, int, android.media.session.ControllerCallbackLink, long); - method public void onSetVolumeTo(String, int, int, android.media.session.ControllerCallbackLink, int); - method public void onSkipToTrack(String, int, int, android.media.session.ControllerCallbackLink, long); - method public void onStop(String, int, int, android.media.session.ControllerCallbackLink); - } - public static interface MediaSessionEngine.MediaButtonEventDelegate { method public boolean onMediaButtonIntent(android.content.Intent); } @@ -5844,6 +5817,7 @@ package android.provider { public static interface DeviceConfig.ActivityManager { field public static final String KEY_COMPACT_ACTION_1 = "compact_action_1"; field public static final String KEY_COMPACT_ACTION_2 = "compact_action_2"; + field public static final String KEY_COMPACT_STATSD_SAMPLE_RATE = "compact_statsd_sample_rate"; field public static final String KEY_COMPACT_THROTTLE_1 = "compact_throttle_1"; field public static final String KEY_COMPACT_THROTTLE_2 = "compact_throttle_2"; field public static final String KEY_COMPACT_THROTTLE_3 = "compact_throttle_3"; @@ -5859,9 +5833,9 @@ package android.provider { } public static interface DeviceConfig.AttentionManagerService { + field public static final String COMPONENT_NAME = "component_name"; field public static final String NAMESPACE = "attention_manager_service"; - field public static final String PROPERTY_COMPONENT_NAME = "component_name"; - field public static final String PROPERTY_SERVICE_ENABLED = "service_enabled"; + field public static final String SERVICE_ENABLED = "service_enabled"; } public static interface DeviceConfig.ContentCapture { @@ -5875,9 +5849,9 @@ package android.provider { } public static interface DeviceConfig.IntelligenceAttention { + field public static final String ATTENTION_ENABLED = "attention_enabled"; + field public static final String ATTENTION_SETTINGS = "attention_settings"; field public static final String NAMESPACE = "intelligence_attention"; - field public static final String PROPERTY_ATTENTION_ENABLED = "attention_enabled"; - field public static final String PROPERTY_ATTENTION_SETTINGS = "attention_settings"; } public static interface DeviceConfig.NotificationAssistant { @@ -5892,8 +5866,8 @@ package android.provider { public static interface DeviceConfig.Privacy { field public static final String NAMESPACE = "privacy"; - field public static final String PROPERTY_LOCATION_ACCESS_CHECK_ENABLED = "enable_location_access_check"; - field public static final String PROPERTY_PERMISSIONS_HUB_ENABLED = "enable_permissions_hub"; + field public static final String PROPERTY_LOCATION_ACCESS_CHECK_ENABLED = "location_access_check_enabled"; + field public static final String PROPERTY_PERMISSIONS_HUB_ENABLED = "permissions_hub_enabled"; } public static interface DeviceConfig.RuntimeNative { @@ -5907,8 +5881,9 @@ package android.provider { public static interface DeviceConfig.Telephony { field public static final String NAMESPACE = "telephony"; - field public static final String PROPERTY_ENABLE_RAMPING_RINGER = "enable_ramping_ringer"; - field public static final String PROPERTY_RAMPING_RINGER_DURATION = "ramping_duration"; + field public static final String RAMPING_RINGER_DURATION = "ramping_ringer_duration"; + field public static final String RAMPING_RINGER_ENABLED = "ramping_ringer_enabled"; + field public static final String RAMPING_RINGER_VIBRATION_DURATION = "ramping_ringer_vibration_duration"; } public final class DocumentsContract { @@ -7931,6 +7906,7 @@ package android.telephony { method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean getEmergencyCallbackMode(); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getIsimDomain(); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getIsimIst(); + method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.List<android.util.Pair<java.lang.Integer,java.lang.Integer>> getLogicalToPhysicalSlotMapping(); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public long getPreferredNetworkTypeBitmap(); method @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public int getRadioPowerState(); method public int getSimApplicationState(); diff --git a/api/test-current.txt b/api/test-current.txt index 76261ddfc191..2f4d45594d89 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -242,6 +242,7 @@ package android.app { public class NotificationManager { method public android.content.ComponentName getEffectsSuppressor(); + method public boolean matchesCallFilter(android.os.Bundle); } public final class PictureInPictureParams implements android.os.Parcelable { @@ -603,23 +604,10 @@ package android.database.sqlite { package android.graphics { - public final class Bitmap implements android.os.Parcelable { - method public void eraseColor(@ColorLong long); - method public android.graphics.Color getColor(int, int); - method public void setColorSpace(@NonNull android.graphics.ColorSpace); - } - public final class ImageDecoder implements java.lang.AutoCloseable { method @AnyThread @NonNull public static android.graphics.ImageDecoder.Source createSource(android.content.res.Resources, java.io.InputStream, int); } - public class Paint { - method @ColorLong public long getColorLong(); - method @ColorLong public long getShadowLayerColorLong(); - method public void setColor(@ColorLong long); - method public void setShadowLayer(float, float, float, @ColorLong long); - } - } package android.graphics.drawable { @@ -839,6 +827,17 @@ package android.media { method public android.media.BufferingParams.Builder setResumePlaybackMarkMs(int); } + public class MediaPlayer2 implements android.media.AudioRouting java.lang.AutoCloseable { + method public android.media.MediaPlayer2.DrmInfo getDrmInfo(@NonNull android.media.DataSourceDesc); + method public android.media.MediaDrm.KeyRequest getDrmKeyRequest(@NonNull android.media.DataSourceDesc, @Nullable byte[], @Nullable byte[], @Nullable String, int, @Nullable java.util.Map<java.lang.String,java.lang.String>) throws android.media.MediaPlayer2.NoDrmSchemeException; + method public String getDrmPropertyString(@NonNull android.media.DataSourceDesc, @NonNull String) throws android.media.MediaPlayer2.NoDrmSchemeException; + method public Object prepareDrm(@NonNull android.media.DataSourceDesc, @NonNull java.util.UUID); + method public byte[] provideDrmKeyResponse(@NonNull android.media.DataSourceDesc, @Nullable byte[], @NonNull byte[]) throws android.media.DeniedByServerException, android.media.MediaPlayer2.NoDrmSchemeException; + method public void releaseDrm(@NonNull android.media.DataSourceDesc) throws android.media.MediaPlayer2.NoDrmSchemeException; + method public void restoreDrmKeys(@NonNull android.media.DataSourceDesc, @NonNull byte[]) throws android.media.MediaPlayer2.NoDrmSchemeException; + method public void setDrmPropertyString(@NonNull android.media.DataSourceDesc, @NonNull String, @NonNull String) throws android.media.MediaPlayer2.NoDrmSchemeException; + } + public final class PlaybackParams implements android.os.Parcelable { method public int getAudioStretchMode(); method public android.media.PlaybackParams setAudioStretchMode(int); @@ -1745,7 +1744,7 @@ package android.provider { public static interface DeviceConfig.Privacy { field public static final String NAMESPACE = "privacy"; - field public static final String PROPERTY_LOCATION_ACCESS_CHECK_ENABLED = "enable_location_access_check"; + field public static final String PROPERTY_LOCATION_ACCESS_CHECK_ENABLED = "location_access_check_enabled"; } public final class MediaStore { diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index 30df850fd3b3..427662aa9eaa 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -234,6 +234,7 @@ message Atom { BluetoothBondStateChanged bluetooth_bond_state_changed = 165; BluetoothClassicPairingEventReported bluetooth_classic_pairing_event_reported = 166; BluetoothSmpPairingEventReported bluetooth_smp_pairing_event_reported = 167; + ScreenTimeoutExtensionReported screen_timeout_extension_reported = 168; } // Pulled events will start at field 10000. @@ -288,6 +289,7 @@ message Atom { DebugElapsedClock debug_elapsed_clock = 10046; DebugFailingElapsedClock debug_failing_elapsed_clock = 10047; NumBiometricsEnrolled num_faces_enrolled = 10048; + RoleHolder role_holder = 10049; } // DO NOT USE field numbers above 100,000 in AOSP. @@ -3973,6 +3975,20 @@ message NumBiometricsEnrolled { optional int32 num_enrolled = 2; } +/** + * A mapping of role holder -> role + */ +message RoleHolder { + // uid of the role holder + optional int32 uid = 1 [(is_uid) = true]; + + // package name of the role holder + optional string package_name = 2; + + // the role held + optional string role = 3; +} + message AggStats { optional int64 min = 1; @@ -4968,17 +4984,17 @@ message GnssConfigurationReported { * packages/apps/Nfc/src/com/android/nfc/cardemulation/AidRoutingManager.java */ message NfcErrorOccurred { - enum Type { - UNKNOWN = 0; - CMD_TIMEOUT = 1; - ERROR_NOTIFICATION = 2; - AID_OVERFLOW = 3; - } - optional Type type = 1; - // If it's nci cmd timeout, log the timeout command. - optional uint32 nci_cmd = 2; + enum Type { + UNKNOWN = 0; + CMD_TIMEOUT = 1; + ERROR_NOTIFICATION = 2; + AID_OVERFLOW = 3; + } + optional Type type = 1; + // If it's nci cmd timeout, log the timeout command. + optional uint32 nci_cmd = 2; - optional uint32 error_ntf_status_code = 3; + optional uint32 error_ntf_status_code = 3; } /** @@ -4987,14 +5003,14 @@ message NfcErrorOccurred { * packages/apps/Nfc/src/com/android/nfc/NfcService.java */ message NfcStateChanged { - enum State { - UNKNOWN = 0; - OFF = 1; - ON = 2; - ON_LOCKED = 3; // Secure Nfc enabled. - CRASH_RESTART = 4; // NfcService watchdog timeout restart. - } - optional State state = 1; + enum State { + UNKNOWN = 0; + OFF = 1; + ON = 2; + ON_LOCKED = 3; // Secure Nfc enabled. + CRASH_RESTART = 4; // NfcService watchdog timeout restart. + } + optional State state = 1; } /** @@ -5003,12 +5019,12 @@ message NfcStateChanged { * packages/apps/Nfc/src/com/android/nfc/P2pLinkManager.java */ message NfcBeamOccurred { - enum Operation { - UNKNOWN = 0; - SEND = 1; - RECEIVE = 2; - } - optional Operation operation = 1; + enum Operation { + UNKNOWN = 0; + SEND = 1; + RECEIVE = 2; + } + optional Operation operation = 1; } /** @@ -5018,16 +5034,16 @@ message NfcBeamOccurred { * packages/apps/Nfc/src/com/android/nfc/cardemulation/HostNfcFEmulationManager.java */ message NfcCardemulationOccurred { - enum Category { - UNKNOWN = 0; - HCE_PAYMENT = 1; - HCE_OTHER = 2; - OFFHOST = 3; - } - // Transaction belongs to HCE payment or HCE other category, or offhost. - optional Category category = 1; - // SeName from transaction: SIMx, eSEx, HCE, HCEF. - optional string se_name = 2; + enum Category { + UNKNOWN = 0; + HCE_PAYMENT = 1; + HCE_OTHER = 2; + OFFHOST = 3; + } + // Transaction belongs to HCE payment or HCE other category, or offhost. + optional Category category = 1; + // SeName from transaction: SIMx, eSEx, HCE, HCEF. + optional string se_name = 2; } /** @@ -5036,16 +5052,16 @@ message NfcCardemulationOccurred { * packages/apps/Nfc/src/com/android/nfc/NfcDispatcher.java */ message NfcTagOccurred { - enum Type { - UNKNOWN = 0; - URL = 1; - BT_PAIRING = 2; - PROVISION = 3; - WIFI_CONNECT = 4; - APP_LAUNCH = 5; - OTHERS = 6; - } - optional Type type = 1; + enum Type { + UNKNOWN = 0; + URL = 1; + BT_PAIRING = 2; + PROVISION = 3; + WIFI_CONNECT = 4; + APP_LAUNCH = 5; + OTHERS = 6; + } + optional Type type = 1; } /** @@ -5065,18 +5081,18 @@ message NfcHceTransactionOccurred { * packages/apps/SecureElement/src/com/android/se/Terminal.java */ message SeStateChanged { - enum State { - UNKNOWN = 0; - INITIALIZED = 1; - DISCONNECTED = 2; - CONNECTED = 3; - HALCRASH = 4; - } - optional State state = 1; + enum State { + UNKNOWN = 0; + INITIALIZED = 1; + DISCONNECTED = 2; + CONNECTED = 3; + HALCRASH = 4; + } + optional State state = 1; - optional string state_change_reason = 2; - // SIMx or eSEx. - optional string terminal = 3; + optional string state_change_reason = 2; + // SIMx or eSEx. + optional string terminal = 3; } /** @@ -5085,15 +5101,15 @@ message SeStateChanged { * packages/apps/SecureElement/src/com/android/se/Terminal.java */ message SeOmapiReported { - enum Operation { - UNKNOWN = 0; - OPEN_CHANNEL = 1; - } - optional Operation operation = 1; - // SIMx or eSEx. - optional string terminal = 2; + enum Operation { + UNKNOWN = 0; + OPEN_CHANNEL = 1; + } + optional Operation operation = 1; + // SIMx or eSEx. + optional string terminal = 2; - optional string package_name = 3; + optional string package_name = 3; } /** @@ -5275,3 +5291,15 @@ message ScheduledJobConstraintChanged { } optional State state = 4; } + +/** + * Logs PowerManagerService screen timeout resets (extensions) that happen when an attention check + * returns true. + * + * Logged from: + * frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java + */ +message ScreenTimeoutExtensionReported { + // Describes how many times in a row did the power manager reset the screen off timeout. + optional uint32 consecutive_timeout_extended_count = 1; +} diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp index a6ba2cae2889..6f3eeaa71703 100644 --- a/cmds/statsd/src/external/StatsPullerManager.cpp +++ b/cmds/statsd/src/external/StatsPullerManager.cpp @@ -220,6 +220,9 @@ const std::map<int, PullAtomInfo> StatsPullerManager::kAllPullAtomInfo = { // BuildInformation. {android::util::BUILD_INFORMATION, {.puller = new StatsCompanionServicePuller(android::util::BUILD_INFORMATION)}}, + // RoleHolder. + {android::util::ROLE_HOLDER, + {.puller = new StatsCompanionServicePuller(android::util::ROLE_HOLDER)}}, }; StatsPullerManager::StatsPullerManager() : mNextPullTimeNs(NO_ALARM_UPDATE) { diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 03a09ee04ea1..4a8566c0072c 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -6083,7 +6083,12 @@ public final class ActivityThread extends ClientTransactionHandler { instrApp.initForUser(UserHandle.myUserId()); final LoadedApk pi = getPackageInfo(instrApp, data.compatInfo, appContext.getClassLoader(), false, true, false); - final ContextImpl instrContext = ContextImpl.createAppContext(this, pi); + + // The test context's op package name == the target app's op package name, because + // the app ops manager checks the op package name against the real calling UID, + // which is what the target package name is associated with. + final ContextImpl instrContext = ContextImpl.createAppContext(this, pi, + appContext.getOpPackageName()); try { final ClassLoader cl = instrContext.getClassLoader(); diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index 92cdb20c7f4f..1a728c12e138 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -2128,7 +2128,7 @@ class ContextImpl extends Context { flags | CONTEXT_REGISTER_PACKAGE); if (pi != null) { ContextImpl c = new ContextImpl(this, mMainThread, pi, null, mActivityToken, - new UserHandle(UserHandle.getUserId(application.uid)), flags, null); + new UserHandle(UserHandle.getUserId(application.uid)), flags, null, null); final int displayId = getDisplayId(); @@ -2156,14 +2156,14 @@ class ContextImpl extends Context { // The system resources are loaded in every application, so we can safely copy // the context without reloading Resources. return new ContextImpl(this, mMainThread, mPackageInfo, null, mActivityToken, user, - flags, null); + flags, null, null); } LoadedApk pi = mMainThread.getPackageInfo(packageName, mResources.getCompatibilityInfo(), flags | CONTEXT_REGISTER_PACKAGE, user.getIdentifier()); if (pi != null) { ContextImpl c = new ContextImpl(this, mMainThread, pi, null, mActivityToken, user, - flags, null); + flags, null, null); final int displayId = getDisplayId(); @@ -2190,7 +2190,7 @@ class ContextImpl extends Context { final String[] paths = mPackageInfo.getSplitPaths(splitName); final ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, splitName, - mActivityToken, mUser, mFlags, classLoader); + mActivityToken, mUser, mFlags, classLoader, null); final int displayId = getDisplayId(); @@ -2214,7 +2214,7 @@ class ContextImpl extends Context { } ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, mSplitName, - mActivityToken, mUser, mFlags, mClassLoader); + mActivityToken, mUser, mFlags, mClassLoader, null); final int displayId = getDisplayId(); context.setResources(createResources(mActivityToken, mPackageInfo, mSplitName, displayId, @@ -2229,7 +2229,7 @@ class ContextImpl extends Context { } ContextImpl context = new ContextImpl(this, mMainThread, mPackageInfo, mSplitName, - mActivityToken, mUser, mFlags, mClassLoader); + mActivityToken, mUser, mFlags, mClassLoader, null); final int displayId = display.getDisplayId(); context.setResources(createResources(mActivityToken, mPackageInfo, mSplitName, displayId, @@ -2243,7 +2243,7 @@ class ContextImpl extends Context { final int flags = (mFlags & ~Context.CONTEXT_CREDENTIAL_PROTECTED_STORAGE) | Context.CONTEXT_DEVICE_PROTECTED_STORAGE; return new ContextImpl(this, mMainThread, mPackageInfo, mSplitName, mActivityToken, mUser, - flags, mClassLoader); + flags, mClassLoader, null); } @Override @@ -2251,7 +2251,7 @@ class ContextImpl extends Context { final int flags = (mFlags & ~Context.CONTEXT_DEVICE_PROTECTED_STORAGE) | Context.CONTEXT_CREDENTIAL_PROTECTED_STORAGE; return new ContextImpl(this, mMainThread, mPackageInfo, mSplitName, mActivityToken, mUser, - flags, mClassLoader); + flags, mClassLoader, null); } @Override @@ -2397,7 +2397,7 @@ class ContextImpl extends Context { static ContextImpl createSystemContext(ActivityThread mainThread) { LoadedApk packageInfo = new LoadedApk(mainThread); ContextImpl context = new ContextImpl(null, mainThread, packageInfo, null, null, null, 0, - null); + null, null); context.setResources(packageInfo.getResources()); context.mResources.updateConfiguration(context.mResourcesManager.getConfiguration(), context.mResourcesManager.getDisplayMetrics()); @@ -2414,7 +2414,7 @@ class ContextImpl extends Context { static ContextImpl createSystemUiContext(ContextImpl systemContext, int displayId) { final LoadedApk packageInfo = systemContext.mPackageInfo; ContextImpl context = new ContextImpl(null, systemContext.mMainThread, packageInfo, null, - null, null, 0, null); + null, null, 0, null, null); context.setResources(createResources(null, packageInfo, null, displayId, null, packageInfo.getCompatibilityInfo())); context.updateDisplay(displayId); @@ -2431,9 +2431,14 @@ class ContextImpl extends Context { @UnsupportedAppUsage static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInfo) { + return createAppContext(mainThread, packageInfo, null); + } + + static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInfo, + String opPackageName) { if (packageInfo == null) throw new IllegalArgumentException("packageInfo"); ContextImpl context = new ContextImpl(null, mainThread, packageInfo, null, null, null, 0, - null); + null, opPackageName); context.setResources(packageInfo.getResources()); return context; } @@ -2461,7 +2466,7 @@ class ContextImpl extends Context { } ContextImpl context = new ContextImpl(null, mainThread, packageInfo, activityInfo.splitName, - activityToken, null, 0, classLoader); + activityToken, null, 0, classLoader, null); // Clamp display ID to DEFAULT_DISPLAY if it is INVALID_DISPLAY. displayId = (displayId != Display.INVALID_DISPLAY) ? displayId : Display.DEFAULT_DISPLAY; @@ -2491,7 +2496,7 @@ class ContextImpl extends Context { private ContextImpl(@Nullable ContextImpl container, @NonNull ActivityThread mainThread, @NonNull LoadedApk packageInfo, @Nullable String splitName, @Nullable IBinder activityToken, @Nullable UserHandle user, int flags, - @Nullable ClassLoader classLoader) { + @Nullable ClassLoader classLoader, @Nullable String overrideOpPackageName) { mOuterContext = this; // If creator didn't specify which storage to use, use the default @@ -2520,9 +2525,11 @@ class ContextImpl extends Context { mClassLoader = classLoader; mResourcesManager = ResourcesManager.getInstance(); + String opPackageName; + if (container != null) { mBasePackageName = container.mBasePackageName; - mOpPackageName = container.mOpPackageName; + opPackageName = container.mOpPackageName; setResources(container.mResources); mDisplay = container.mDisplay; } else { @@ -2533,12 +2540,14 @@ class ContextImpl extends Context { // processes. For purposes of app ops, we must then consider the context as // belonging to the package of this process, not the system itself, otherwise // the package+uid verifications in app ops will fail. - mOpPackageName = ActivityThread.currentPackageName(); + opPackageName = ActivityThread.currentPackageName(); } else { - mOpPackageName = mBasePackageName; + opPackageName = mBasePackageName; } } + mOpPackageName = overrideOpPackageName != null ? overrideOpPackageName : opPackageName; + mContentResolver = new ApplicationContentResolver(this, mainThread); } diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java index 6a1ff298afdb..8207e0a112c5 100644 --- a/core/java/android/app/NotificationManager.java +++ b/core/java/android/app/NotificationManager.java @@ -828,6 +828,7 @@ public class NotificationManager { /** * @hide */ + @TestApi public boolean matchesCallFilter(Bundle extras) { INotificationManager service = getService(); try { diff --git a/core/java/android/content/pm/ILauncherApps.aidl b/core/java/android/content/pm/ILauncherApps.aidl index d1bc37791d40..50bb3c721763 100644 --- a/core/java/android/content/pm/ILauncherApps.aidl +++ b/core/java/android/content/pm/ILauncherApps.aidl @@ -24,6 +24,8 @@ import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.IOnAppsChangedListener; import android.content.pm.LauncherApps; +import android.content.pm.IPackageInstallerCallback; +import android.content.pm.PackageInstaller; import android.content.pm.ParceledListSlice; import android.content.pm.ResolveInfo; import android.content.pm.ShortcutInfo; @@ -44,6 +46,9 @@ interface ILauncherApps { String callingPackage, String packageName, in UserHandle user); ActivityInfo resolveActivity( String callingPackage, in ComponentName component, in UserHandle user); + void startSessionDetailsActivityAsUser(in IApplicationThread caller, String callingPackage, + in PackageInstaller.SessionInfo sessionInfo, in Rect sourceBounds, in Bundle opts, + in UserHandle user); void startActivityAsUser(in IApplicationThread caller, String callingPackage, in ComponentName component, in Rect sourceBounds, in Bundle opts, in UserHandle user); @@ -79,4 +84,9 @@ interface ILauncherApps { String callingPackage, String packageName, in UserHandle user); IntentSender getShortcutConfigActivityIntent(String callingPackage, in ComponentName component, in UserHandle user); + + // Unregister is performed using package installer + void registerPackageInstallerCallback(String callingPackage, + in IPackageInstallerCallback callback); + ParceledListSlice getAllSessions(String callingPackage); } diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java index 98dd9b3aa30b..b0d16cdace21 100644 --- a/core/java/android/content/pm/LauncherApps.java +++ b/core/java/android/content/pm/LauncherApps.java @@ -16,6 +16,7 @@ package android.content.pm; +import android.annotation.CallbackExecutor; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; @@ -32,6 +33,9 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentSender; +import android.content.pm.PackageInstaller.SessionCallback; +import android.content.pm.PackageInstaller.SessionCallbackDelegate; +import android.content.pm.PackageInstaller.SessionInfo; import android.content.pm.PackageManager.ApplicationInfoFlags; import android.content.pm.PackageManager.NameNotFoundException; import android.content.res.Resources; @@ -65,7 +69,9 @@ import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.Iterator; import java.util.List; +import java.util.concurrent.Executor; /** * Class for retrieving a list of launchable activities for the current user and any associated @@ -154,8 +160,8 @@ public class LauncherApps { private final PackageManager mPm; private final UserManager mUserManager; - private List<CallbackMessageHandler> mCallbacks - = new ArrayList<CallbackMessageHandler>(); + private final List<CallbackMessageHandler> mCallbacks = new ArrayList<>(); + private final List<SessionCallbackDelegate> mDelegates = new ArrayList<>(); /** * Callbacks for package changes to this and related managed profiles. @@ -572,6 +578,24 @@ public class LauncherApps { } /** + * Starts an activity to show the details of the specified session. + * + * @param sessionInfo The SessionInfo of the session + * @param sourceBounds The Rect containing the source bounds of the clicked icon + * @param opts Options to pass to startActivity + */ + public void startPackageInstallerSessionDetailsActivity(SessionInfo sessionInfo, + Rect sourceBounds, Bundle opts) { + try { + mService.startSessionDetailsActivityAsUser(mContext.getIApplicationThread(), + mContext.getPackageName(), sessionInfo, sourceBounds, opts, + sessionInfo.getUser()); + } catch (RemoteException re) { + throw re.rethrowFromSystemServer(); + } + } + + /** * Starts the settings activity to show the application details for a * package in the specified profile. * @@ -1131,7 +1155,7 @@ public class LauncherApps { } /** - * Registers a callback for changes to packages in current and managed profiles. + * Registers a callback for changes to packages in this user and managed profiles. * * @param callback The callback to register. */ @@ -1140,7 +1164,7 @@ public class LauncherApps { } /** - * Registers a callback for changes to packages in current and managed profiles. + * Registers a callback for changes to packages in this user and managed profiles. * * @param callback The callback to register. * @param handler that should be used to post callbacks on, may be null. @@ -1446,6 +1470,64 @@ public class LauncherApps { } /** + * Register a callback to watch for session lifecycle events in this user and managed profiles. + * @param callback The callback to register. + * @param executor {@link Executor} to handle the callbacks, cannot be null. + * + * @see PackageInstaller#registerSessionCallback(SessionCallback) + */ + public void registerPackageInstallerSessionCallback( + @NonNull @CallbackExecutor Executor executor, @NonNull SessionCallback callback) { + if (executor == null) { + throw new NullPointerException("Executor must not be null"); + } + + synchronized (mDelegates) { + final SessionCallbackDelegate delegate = new SessionCallbackDelegate(callback, + executor); + try { + mService.registerPackageInstallerCallback(mContext.getPackageName(), + delegate); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + mDelegates.add(delegate); + } + } + + /** + * Unregisters a callback that was previously registered. + * + * @param callback The callback to unregister. + * @see #registerPackageInstallerSessionCallback(Executor, SessionCallback) + */ + public void unregisterPackageInstallerSessionCallback(SessionCallback callback) { + synchronized (mDelegates) { + for (Iterator<SessionCallbackDelegate> i = mDelegates.iterator(); i.hasNext();) { + final SessionCallbackDelegate delegate = i.next(); + if (delegate.mCallback == callback) { + mPm.getPackageInstaller().unregisterSessionCallback(delegate.mCallback); + i.remove(); + } + } + } + } + + /** + * Return list of all known install sessions in this user and managed profiles, regardless + * of the installer. + * + * @see PackageInstaller#getAllSessions() + */ + public @NonNull List<SessionInfo> getAllPackageInstallerSessions() { + try { + return mService.getAllSessions(mContext.getPackageName()).getList(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** * A helper method to extract a {@link PinItemRequest} set to * the {@link #EXTRA_PIN_ITEM_REQUEST} extra. */ diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java index 2dc014c45fad..4f674bd378c0 100644 --- a/core/java/android/content/pm/PackageInstaller.java +++ b/core/java/android/content/pm/PackageInstaller.java @@ -36,20 +36,21 @@ import android.net.Uri; import android.os.Build; import android.os.FileBridge; import android.os.Handler; -import android.os.Looper; -import android.os.Message; +import android.os.HandlerExecutor; import android.os.Parcel; import android.os.ParcelFileDescriptor; import android.os.Parcelable; import android.os.ParcelableException; import android.os.RemoteException; import android.os.SystemProperties; +import android.os.UserHandle; import android.system.ErrnoException; import android.system.Os; import android.util.ExceptionUtils; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.Preconditions; +import com.android.internal.util.function.pooled.PooledLambda; import java.io.Closeable; import java.io.IOException; @@ -61,6 +62,7 @@ import java.security.MessageDigest; import java.util.ArrayList; import java.util.Iterator; import java.util.List; +import java.util.concurrent.Executor; /** * Offers the ability to install, upgrade, and remove applications on the @@ -659,8 +661,7 @@ public class PackageInstaller { } /** {@hide} */ - private static class SessionCallbackDelegate extends IPackageInstallerCallback.Stub implements - Handler.Callback { + static class SessionCallbackDelegate extends IPackageInstallerCallback.Stub { private static final int MSG_SESSION_CREATED = 1; private static final int MSG_SESSION_BADGING_CHANGED = 2; private static final int MSG_SESSION_ACTIVE_CHANGED = 3; @@ -668,63 +669,41 @@ public class PackageInstaller { private static final int MSG_SESSION_FINISHED = 5; final SessionCallback mCallback; - final Handler mHandler; + final Executor mExecutor; - public SessionCallbackDelegate(SessionCallback callback, Looper looper) { + SessionCallbackDelegate(SessionCallback callback, Executor executor) { mCallback = callback; - mHandler = new Handler(looper, this); - } - - @Override - public boolean handleMessage(Message msg) { - final int sessionId = msg.arg1; - switch (msg.what) { - case MSG_SESSION_CREATED: - mCallback.onCreated(sessionId); - return true; - case MSG_SESSION_BADGING_CHANGED: - mCallback.onBadgingChanged(sessionId); - return true; - case MSG_SESSION_ACTIVE_CHANGED: - final boolean active = msg.arg2 != 0; - mCallback.onActiveChanged(sessionId, active); - return true; - case MSG_SESSION_PROGRESS_CHANGED: - mCallback.onProgressChanged(sessionId, (float) msg.obj); - return true; - case MSG_SESSION_FINISHED: - mCallback.onFinished(sessionId, msg.arg2 != 0); - return true; - } - return false; + mExecutor = executor; } @Override public void onSessionCreated(int sessionId) { - mHandler.obtainMessage(MSG_SESSION_CREATED, sessionId, 0).sendToTarget(); + mExecutor.execute(PooledLambda.obtainRunnable(SessionCallback::onCreated, mCallback, + sessionId).recycleOnUse()); } @Override public void onSessionBadgingChanged(int sessionId) { - mHandler.obtainMessage(MSG_SESSION_BADGING_CHANGED, sessionId, 0).sendToTarget(); + mExecutor.execute(PooledLambda.obtainRunnable(SessionCallback::onBadgingChanged, + mCallback, sessionId).recycleOnUse()); } @Override public void onSessionActiveChanged(int sessionId, boolean active) { - mHandler.obtainMessage(MSG_SESSION_ACTIVE_CHANGED, sessionId, active ? 1 : 0) - .sendToTarget(); + mExecutor.execute(PooledLambda.obtainRunnable(SessionCallback::onActiveChanged, + mCallback, sessionId, active).recycleOnUse()); } @Override public void onSessionProgressChanged(int sessionId, float progress) { - mHandler.obtainMessage(MSG_SESSION_PROGRESS_CHANGED, sessionId, 0, progress) - .sendToTarget(); + mExecutor.execute(PooledLambda.obtainRunnable(SessionCallback::onProgressChanged, + mCallback, sessionId, progress).recycleOnUse()); } @Override public void onSessionFinished(int sessionId, boolean success) { - mHandler.obtainMessage(MSG_SESSION_FINISHED, sessionId, success ? 1 : 0) - .sendToTarget(); + mExecutor.execute(PooledLambda.obtainRunnable(SessionCallback::onFinished, + mCallback, sessionId, success).recycleOnUse()); } } @@ -758,7 +737,7 @@ public class PackageInstaller { public void registerSessionCallback(@NonNull SessionCallback callback, @NonNull Handler handler) { synchronized (mDelegates) { final SessionCallbackDelegate delegate = new SessionCallbackDelegate(callback, - handler.getLooper()); + new HandlerExecutor(handler)); try { mInstaller.registerCallback(delegate, mUserId); } catch (RemoteException e) { @@ -1649,6 +1628,8 @@ public class PackageInstaller { @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public int sessionId; /** {@hide} */ + public int userId; + /** {@hide} */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public String installerPackageName; /** {@hide} */ @@ -1720,6 +1701,7 @@ public class PackageInstaller { /** {@hide} */ public SessionInfo(Parcel source) { sessionId = source.readInt(); + userId = source.readInt(); installerPackageName = source.readString(); resolvedBaseCodePath = source.readString(); progress = source.readFloat(); @@ -1761,6 +1743,13 @@ public class PackageInstaller { } /** + * Return the user associated with this session. + */ + public UserHandle getUser() { + return new UserHandle(userId); + } + + /** * Return the package name of the app that owns this session. */ public @Nullable String getInstallerPackageName() { @@ -2091,6 +2080,7 @@ public class PackageInstaller { @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(sessionId); + dest.writeInt(userId); dest.writeString(installerPackageName); dest.writeString(resolvedBaseCodePath); dest.writeFloat(progress); diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index ef8ca9e3cb67..869cf6477df0 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -1033,34 +1033,6 @@ public class ConnectivityManager { } } - /** - * Configures an always-on VPN connection through a specific application. - * This connection is automatically granted and persisted after a reboot. - * - * <p>The designated package should declare a {@link VpnService} in its - * manifest guarded by {@link android.Manifest.permission.BIND_VPN_SERVICE}, - * otherwise the call will fail. - * - * @param userId The identifier of the user to set an always-on VPN for. - * @param vpnPackage The package name for an installed VPN app on the device, or {@code null} - * to remove an existing always-on VPN configuration. - * @param lockdownEnabled {@code true} to disallow networking when the VPN is not connected or - * {@code false} otherwise. - * @return {@code true} if the package is set as always-on VPN controller; - * {@code false} otherwise. - * @hide - */ - @RequiresPermission(android.Manifest.permission.CONTROL_ALWAYS_ON_VPN) - public boolean setAlwaysOnVpnPackageForUser(int userId, @Nullable String vpnPackage, - boolean lockdownEnabled) { - try { - return mService.setAlwaysOnVpnPackage( - userId, vpnPackage, lockdownEnabled, /* whitelist */ null); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - /** * Returns the package name of the currently set always-on VPN application. * If there is no always-on VPN set, or the VPN is provided by the system instead diff --git a/core/java/android/os/OWNERS b/core/java/android/os/OWNERS new file mode 100644 index 000000000000..b568f157c01d --- /dev/null +++ b/core/java/android/os/OWNERS @@ -0,0 +1,2 @@ +# Zygote +per-file ZygoteProcess.java = chriswailes@google.com, ngeoffray@google.com, sehr@google.com, narayan@google.com, maco@google.com diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java index 30c0731870ef..92650e114a66 100644 --- a/core/java/android/provider/DeviceConfig.java +++ b/core/java/android/provider/DeviceConfig.java @@ -181,10 +181,10 @@ public final class DeviceConfig { String NAMESPACE = "intelligence_attention"; /** If {@code true}, enables the attention features. */ - String PROPERTY_ATTENTION_ENABLED = "attention_enabled"; + String ATTENTION_ENABLED = "attention_enabled"; /** Settings for the attention features. */ - String PROPERTY_ATTENTION_SETTINGS = "attention_settings"; + String ATTENTION_SETTINGS = "attention_settings"; } /** @@ -203,12 +203,12 @@ public final class DeviceConfig { * @hide */ @SystemApi - String PROPERTY_PERMISSIONS_HUB_ENABLED = "enable_permissions_hub"; + String PROPERTY_PERMISSIONS_HUB_ENABLED = "permissions_hub_enabled"; /** * Whether to show location access check notifications. */ - String PROPERTY_LOCATION_ACCESS_CHECK_ENABLED = "enable_location_access_check"; + String PROPERTY_LOCATION_ACCESS_CHECK_ENABLED = "location_access_check_enabled"; } /** @@ -220,13 +220,17 @@ public final class DeviceConfig { public interface Telephony { String NAMESPACE = "telephony"; /** + * Ringer ramping time in milliseconds. + */ + String RAMPING_RINGER_DURATION = "ramping_ringer_duration"; + /** * Whether to apply ramping ringer on incoming phone calls. */ - String PROPERTY_ENABLE_RAMPING_RINGER = "enable_ramping_ringer"; + String RAMPING_RINGER_ENABLED = "ramping_ringer_enabled"; /** - * Ringer ramping time in milliseconds. + * Vibration time in milliseconds before ramping ringer starts. */ - String PROPERTY_RAMPING_RINGER_DURATION = "ramping_duration"; + String RAMPING_RINGER_VIBRATION_DURATION = "ramping_ringer_vibration_duration"; } /** @@ -261,6 +265,7 @@ public final class DeviceConfig { String KEY_COMPACT_THROTTLE_2 = "compact_throttle_2"; String KEY_COMPACT_THROTTLE_3 = "compact_throttle_3"; String KEY_COMPACT_THROTTLE_4 = "compact_throttle_4"; + String KEY_COMPACT_STATSD_SAMPLE_RATE = "compact_statsd_sample_rate"; /** * Maximum number of cached processes. See @@ -279,10 +284,10 @@ public final class DeviceConfig { String NAMESPACE = "attention_manager_service"; /** If {@code true}, enables {@link AttentionManagerService} features. */ - String PROPERTY_SERVICE_ENABLED = "service_enabled"; + String SERVICE_ENABLED = "service_enabled"; /** Allows a CTS to inject a fake implementation. */ - String PROPERTY_COMPONENT_NAME = "component_name"; + String COMPONENT_NAME = "component_name"; } /** diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java index 124c50a3393e..0743c23080fd 100644 --- a/core/java/android/provider/MediaStore.java +++ b/core/java/android/provider/MediaStore.java @@ -641,6 +641,8 @@ public final class MediaStore { * location. For example, when this value is left undefined, pending * {@link MediaStore.Audio.Media} items are stored under * {@link Environment#DIRECTORY_MUSIC}. + * + * @see MediaColumns#PRIMARY_DIRECTORY */ public void setPrimaryDirectory(@Nullable String primaryDirectory) { this.primaryDirectory = primaryDirectory; @@ -652,6 +654,8 @@ public final class MediaStore { * <p> * You may leave this value undefined to store the media as a direct * descendant of the {@link #setPrimaryDirectory(String)} location. + * + * @see MediaColumns#SECONDARY_DIRECTORY */ public void setSecondaryDirectory(@Nullable String secondaryDirectory) { this.secondaryDirectory = secondaryDirectory; @@ -980,6 +984,26 @@ public final class MediaStore { * Type: TEXT */ public static final String OWNER_PACKAGE_NAME = "owner_package_name"; + + /** + * The primary directory name this media exists under. The value may be + * {@code NULL} if the media doesn't have a primary directory name. + * <p> + * Type: TEXT + * + * @see PendingParams#setPrimaryDirectory(String) + */ + public static final String PRIMARY_DIRECTORY = "primary_directory"; + + /** + * The secondary directory name this media exists under. The value may + * be {@code NULL} if the media doesn't have a secondary directory name. + * <p> + * Type: TEXT + * + * @see PendingParams#setSecondaryDirectory(String) + */ + public static final String SECONDARY_DIRECTORY = "secondary_directory"; } /** @@ -1428,13 +1452,20 @@ public final class MediaStore { public static final String BUCKET_DISPLAY_NAME = "bucket_display_name"; /** - * The secondary bucket ID of this media item. This can be useful to - * present the user a second-level clustering of related media - * items. This is a read-only column that is automatically computed. + * The group ID of this media item. This can be useful to present + * the user a grouping of related media items, such a burst of + * images, or a {@code JPG} and {@code DNG} version of the same + * image. + * <p> + * This is a read-only column that is automatically computed based + * on the first portion of the filename. For example, + * {@code IMG1024.BURST001.JPG} and {@code IMG1024.BURST002.JPG} + * will have the same {@link #GROUP_ID} because the first portion of + * their filenames is identical. * <p> * Type: INTEGER */ - public static final String SECONDARY_BUCKET_ID = "secondary_bucket_id"; + public static final String GROUP_ID = "group_id"; } public static final class Media implements ImageColumns { @@ -2697,13 +2728,20 @@ public final class MediaStore { public static final String BUCKET_DISPLAY_NAME = "bucket_display_name"; /** - * The secondary bucket ID of this media item. This can be useful to - * present the user a second-level clustering of related media - * items. This is a read-only column that is automatically computed. + * The group ID of this media item. This can be useful to present + * the user a grouping of related media items, such a burst of + * images, or a {@code JPG} and {@code DNG} version of the same + * image. + * <p> + * This is a read-only column that is automatically computed based + * on the first portion of the filename. For example, + * {@code IMG1024.BURST001.JPG} and {@code IMG1024.BURST002.JPG} + * will have the same {@link #GROUP_ID} because the first portion of + * their filenames is identical. * <p> * Type: INTEGER */ - public static final String SECONDARY_BUCKET_ID = "secondary_bucket_id"; + public static final String GROUP_ID = "group_id"; /** * The bookmark for the video. Time in ms. Represents the location in the video that the diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index ea00698f2001..afa21100f022 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -5874,30 +5874,24 @@ public final class Settings { "unknown_sources_default_reversed"; /** - * Comma-separated list of location providers that activities may access. Do not rely on - * this value being present in settings.db or on ContentObserver notifications on the + * Comma-separated list of location providers that are accessible. Do not rely on + * this value being present or correct, or on ContentObserver notifications on the * corresponding Uri. * - * @deprecated Providers should not be controlled individually. See {@link #LOCATION_MODE} - * documentation for information on reading/writing location information. + * @deprecated The preferred methods for checking provider status and listening for changes + * are via {@link LocationManager#isProviderEnabled(String)} and + * {@link LocationManager#PROVIDERS_CHANGED_ACTION}. */ @Deprecated public static final String LOCATION_PROVIDERS_ALLOWED = "location_providers_allowed"; /** - * The degree of location access enabled by the user. - * <p> - * When used with {@link #putInt(ContentResolver, String, int)}, must be one of {@link - * #LOCATION_MODE_HIGH_ACCURACY}, {@link #LOCATION_MODE_SENSORS_ONLY}, {@link - * #LOCATION_MODE_BATTERY_SAVING}, or {@link #LOCATION_MODE_OFF}. When used with {@link - * #getInt(ContentResolver, String)}, the caller must gracefully handle additional location - * modes that might be added in the future. - * <p> - * Note: do not rely on this value being present in settings.db or on ContentObserver - * notifications for the corresponding Uri. Use {@link LocationManager#MODE_CHANGED_ACTION} - * to receive changes in this value. + * The current location mode of the device. Do not rely on this value being present or on + * ContentObserver notifications on the corresponding Uri. * - * @deprecated To check location mode, use {@link LocationManager#isLocationEnabled()}. + * @deprecated The preferred methods for checking location mode and listening for changes + * are via {@link LocationManager#isLocationEnabled()} and + * {@link LocationManager#MODE_CHANGED_ACTION}. */ @Deprecated public static final String LOCATION_MODE = "location_mode"; @@ -5924,7 +5918,7 @@ public final class Settings { public static final int LOCATION_CHANGER_QUICK_SETTINGS = 2; /** - * Location access disabled. + * Location mode is off. * * @deprecated See {@link #LOCATION_MODE}. */ @@ -5932,34 +5926,41 @@ public final class Settings { public static final int LOCATION_MODE_OFF = 0; /** - * Network Location Provider disabled, but GPS and other sensors enabled. + * This mode no longer has any distinct meaning, but is interpreted as the location mode is + * on. * - * @deprecated To check location status, use {@link LocationManager#isLocationEnabled()}. To - * get the status of a location provider, use - * {@link LocationManager#isProviderEnabled(String)}. + * @deprecated See {@link #LOCATION_MODE_ON}. */ @Deprecated public static final int LOCATION_MODE_SENSORS_ONLY = 1; /** - * Reduced power usage, such as limiting the number of GPS updates per hour. Requests - * with {@link android.location.Criteria#POWER_HIGH} may be downgraded to - * {@link android.location.Criteria#POWER_MEDIUM}. + * This mode no longer has any distinct meaning, but is interpreted as the location mode is + * on. * - * @deprecated See {@link #LOCATION_MODE}. + * @deprecated See {@link #LOCATION_MODE_ON}. */ @Deprecated public static final int LOCATION_MODE_BATTERY_SAVING = 2; /** - * Best-effort location computation allowed. + * This mode no longer has any distinct meaning, but is interpreted as the location mode is + * on. * - * @deprecated See {@link #LOCATION_MODE}. + * @deprecated See {@link #LOCATION_MODE_ON}. */ @Deprecated public static final int LOCATION_MODE_HIGH_ACCURACY = 3; /** + * Location mode is on. + * + * @deprecated See {@link #LOCATION_MODE}. + */ + @Deprecated + public static final int LOCATION_MODE_ON = LOCATION_MODE_HIGH_ACCURACY; + + /** * A flag containing settings used for biometric weak * @hide */ diff --git a/core/java/android/service/attention/AttentionService.java b/core/java/android/service/attention/AttentionService.java index f6e448dc4757..24d74ffd747d 100644 --- a/core/java/android/service/attention/AttentionService.java +++ b/core/java/android/service/attention/AttentionService.java @@ -64,10 +64,10 @@ public abstract class AttentionService extends Service { /** Attention is present. */ public static final int ATTENTION_SUCCESS_PRESENT = 1; - /** Preempted by other camera user. */ + /** Preempted by other client. */ public static final int ATTENTION_FAILURE_PREEMPTED = 2; - /** Preempted by other camera user. */ + /** Request timed out. */ public static final int ATTENTION_FAILURE_TIMED_OUT = 3; /** Unknown reasons for failing to determine the attention. */ diff --git a/core/java/android/service/dreams/OWNERS b/core/java/android/service/dreams/OWNERS index 3c9bbf8797ea..426f002ad236 100644 --- a/core/java/android/service/dreams/OWNERS +++ b/core/java/android/service/dreams/OWNERS @@ -1,3 +1,3 @@ -dsandler@google.com +dsandler@android.com michaelwr@google.com roosa@google.com diff --git a/core/java/android/service/voice/VoiceInteractionService.java b/core/java/android/service/voice/VoiceInteractionService.java index 2789651c4eaf..e76e0966b817 100644 --- a/core/java/android/service/voice/VoiceInteractionService.java +++ b/core/java/android/service/voice/VoiceInteractionService.java @@ -16,7 +16,6 @@ package android.service.voice; -import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SdkConstant; @@ -41,8 +40,6 @@ import com.android.internal.util.function.pooled.PooledLambda; import java.io.FileDescriptor; import java.io.PrintWriter; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.List; import java.util.Locale; @@ -80,33 +77,6 @@ public class VoiceInteractionService extends Service { */ public static final String SERVICE_META_DATA = "android.voice_interaction"; - /** @hide */ - @Retention(RetentionPolicy.SOURCE) - @IntDef(prefix = {"VOICE_STATE_"}, value = { - VOICE_STATE_NONE, - VOICE_STATE_CONDITIONAL_LISTENING, - VOICE_STATE_LISTENING, - VOICE_STATE_FULFILLING}) - public @interface VoiceState { - } - - /** - * Voice assistant inactive. - */ - public static final int VOICE_STATE_NONE = 0; - /** - * Voice assistant listening, but will only trigger if it hears a request it can fulfill. - */ - public static final int VOICE_STATE_CONDITIONAL_LISTENING = 1; - /** - * Voice assistant is listening to user speech. - */ - public static final int VOICE_STATE_LISTENING = 2; - /** - * Voice assistant is fulfilling an action requested by the user. - */ - public static final int VOICE_STATE_FULFILLING = 3; - IVoiceInteractionService mInterface = new IVoiceInteractionService.Stub() { @Override public void ready() { @@ -376,7 +346,7 @@ public class VoiceInteractionService extends Service { * * @param state value indicating whether the assistant is listening, fulfilling, etc. */ - public final void setVoiceState(@VoiceState int state) { + public final void setVoiceState(int state) { try { mSystemService.setVoiceState(state); } catch (RemoteException e) { diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java index db9351b030df..2e8b7f021ff6 100644 --- a/core/java/android/util/FeatureFlagUtils.java +++ b/core/java/android/util/FeatureFlagUtils.java @@ -57,6 +57,7 @@ public class FeatureFlagUtils { DEFAULT_FLAGS.put("settings_wifi_dpp", "true"); DEFAULT_FLAGS.put("settings_wifi_mac_randomization", "true"); DEFAULT_FLAGS.put("settings_wifi_sharing", "true"); + DEFAULT_FLAGS.put("settings_mainline_module", "false"); DEFAULT_FLAGS.put(HEARING_AID_SETTINGS, "false"); DEFAULT_FLAGS.put(SAFETY_HUB, "false"); DEFAULT_FLAGS.put(SCREENRECORD_LONG_PRESS, "false"); diff --git a/core/java/android/view/textclassifier/ExtrasUtils.java b/core/java/android/view/textclassifier/ExtrasUtils.java new file mode 100644 index 000000000000..602455c65beb --- /dev/null +++ b/core/java/android/view/textclassifier/ExtrasUtils.java @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.view.textclassifier; + +import android.annotation.Nullable; +import android.app.RemoteAction; +import android.content.Intent; +import android.os.Bundle; + +import java.util.ArrayList; + +/** + * Utility class for inserting and retrieving data in TextClassifier request/response extras. + * @hide + */ +public final class ExtrasUtils { + + private static final String ACTIONS_INTENTS = "actions-intents"; + private static final String FOREIGN_LANGUAGE = "foreign-language"; + private static final String ENTITY_TYPE = "entity-type"; + private static final String SCORE = "score"; + private static final String MODEL_VERSION = "model-version"; + private static final String MODEL_NAME = "model-name"; + + private ExtrasUtils() {} + + /** + * Bundles and returns foreign language detection information for TextClassifier responses. + */ + static Bundle createForeignLanguageExtra( + String language, float score, int modelVersion) { + final Bundle bundle = new Bundle(); + bundle.putString(ENTITY_TYPE, language); + bundle.putFloat(SCORE, score); + bundle.putInt(MODEL_VERSION, modelVersion); + bundle.putString(MODEL_NAME, "langId_v" + modelVersion); + return bundle; + } + + /** + * Stores {@code extra} as foreign language information in TextClassifier response object's + * extras {@code container}. + */ + static void putForeignLanguageExtra(Bundle container, Bundle extra) { + container.putParcelable(FOREIGN_LANGUAGE, extra); + } + + /** + * Returns foreign language detection information contained in the TextClassification object. + * responses. + */ + @Nullable + public static Bundle getForeignLanguageExtra(TextClassification classification) { + return classification.getExtras().getBundle(FOREIGN_LANGUAGE); + } + + /** + * Stores {@code actionIntents} information in TextClassifier response object's extras + * {@code container}. + */ + static void putActionsIntents(Bundle container, ArrayList<Intent> actionsIntents) { + container.putParcelableArrayList(ACTIONS_INTENTS, actionsIntents); + } + + /** + * Returns {@code actionIntents} information contained in the TextClassification object. + */ + @Nullable + public static ArrayList<Intent> getActionsIntents(TextClassification classification) { + return classification.getExtras().getParcelableArrayList(ACTIONS_INTENTS); + } + + /** + * Returns the first "translate" action found in the {@code classification} object. + */ + @Nullable + public static RemoteAction findTranslateAction(TextClassification classification) { + final ArrayList<Intent> actionIntents = getActionsIntents(classification); + if (actionIntents != null) { + final int size = actionIntents.size(); + for (int i = 0; i < size; i++) { + if (Intent.ACTION_TRANSLATE.equals(actionIntents.get(i).getAction())) { + return classification.getActions().get(i); + } + } + } + return null; + } + + /** + * Returns the entity type contained in the {@code extra}. + */ + @Nullable + public static String getEntityType(Bundle extra) { + return extra.getString(ENTITY_TYPE); + } + + /** + * Returns the score contained in the {@code extra}. + */ + @Nullable + public static float getScore(Bundle extra) { + return extra.getFloat(SCORE, -1); + } + + /** + * Returns the model name contained in the {@code extra}. + */ + @Nullable + public static String getModelName(Bundle extra) { + return extra.getString(MODEL_NAME); + } +} diff --git a/core/java/android/view/textclassifier/TextClassification.java b/core/java/android/view/textclassifier/TextClassification.java index d9f79655d588..a05920960dcf 100644 --- a/core/java/android/view/textclassifier/TextClassification.java +++ b/core/java/android/view/textclassifier/TextClassification.java @@ -378,6 +378,8 @@ public final class TextClassification implements Parcelable { @Nullable private OnClickListener mLegacyOnClickListener; @Nullable private String mId; @Nullable private Bundle mExtras; + @NonNull private final ArrayList<Intent> mActionIntents = new ArrayList<>(); + @Nullable private Bundle mForeignLanguageExtra; /** * Sets the classified text. @@ -412,8 +414,19 @@ public final class TextClassification implements Parcelable { */ @NonNull public Builder addAction(@NonNull RemoteAction action) { + return addAction(action, null); + } + + /** + * @param intent the intent in the remote action. + * @see #addAction(RemoteAction) + * @hide + */ + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) + public Builder addAction(RemoteAction action, @Nullable Intent intent) { Preconditions.checkArgument(action != null); mActions.add(action); + mActionIntents.add(intent); return this; } @@ -499,13 +512,33 @@ public final class TextClassification implements Parcelable { } /** + * @see #setExtras(Bundle) + * @hide + */ + @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) + public Builder setForeignLanguageExtra(@Nullable Bundle extra) { + mForeignLanguageExtra = extra; + return this; + } + + /** * Builds and returns a {@link TextClassification} object. */ @NonNull public TextClassification build() { return new TextClassification(mText, mLegacyIcon, mLegacyLabel, mLegacyIntent, - mLegacyOnClickListener, mActions, mEntityConfidence, mId, - mExtras == null ? Bundle.EMPTY : mExtras.deepCopy()); + mLegacyOnClickListener, mActions, mEntityConfidence, mId, buildExtras()); + } + + private Bundle buildExtras() { + final Bundle extras = mExtras == null ? new Bundle() : mExtras.deepCopy(); + if (!mActionIntents.isEmpty()) { + ExtrasUtils.putActionsIntents(extras, mActionIntents); + } + if (mForeignLanguageExtra != null) { + ExtrasUtils.putForeignLanguageExtra(extras, mForeignLanguageExtra); + } + return extras.isEmpty() ? Bundle.EMPTY : extras; } } diff --git a/core/java/android/view/textclassifier/TextClassificationSession.java b/core/java/android/view/textclassifier/TextClassificationSession.java index 45668c01a8d3..ba1287fc6b0f 100644 --- a/core/java/android/view/textclassifier/TextClassificationSession.java +++ b/core/java/android/view/textclassifier/TextClassificationSession.java @@ -71,10 +71,23 @@ final class TextClassificationSession implements TextClassifier { @Override public void onSelectionEvent(SelectionEvent event) { - checkDestroyed(); - Preconditions.checkNotNull(event); - if (mEventHelper.sanitizeEvent(event)) { - mDelegate.onSelectionEvent(event); + try { + if (mEventHelper.sanitizeEvent(event)) { + mDelegate.onSelectionEvent(event); + } + } catch (Exception e) { + // Avoid crashing for event reporting. + Log.e(LOG_TAG, "Error reporting text classifier selection event", e); + } + } + + @Override + public void onTextClassifierEvent(TextClassifierEvent event) { + try { + mDelegate.onTextClassifierEvent(event); + } catch (Exception e) { + // Avoid crashing for event reporting. + Log.e(LOG_TAG, "Error reporting text classifier event", e); } } diff --git a/core/java/android/view/textclassifier/TextClassifier.java b/core/java/android/view/textclassifier/TextClassifier.java index 8a688d8454e7..e0101556910f 100644 --- a/core/java/android/view/textclassifier/TextClassifier.java +++ b/core/java/android/view/textclassifier/TextClassifier.java @@ -161,7 +161,12 @@ public interface TextClassifier { * No-op TextClassifier. * This may be used to turn off TextClassifier features. */ - TextClassifier NO_OP = new TextClassifier() {}; + TextClassifier NO_OP = new TextClassifier() { + @Override + public String toString() { + return "TextClassifier.NO_OP"; + } + }; /** * Extra that is included on activity intents coming from a TextClassifier when diff --git a/core/java/android/view/textclassifier/TextClassifierEvent.java b/core/java/android/view/textclassifier/TextClassifierEvent.java index cd13cc0ec577..0d4338b0af6b 100644 --- a/core/java/android/view/textclassifier/TextClassifierEvent.java +++ b/core/java/android/view/textclassifier/TextClassifierEvent.java @@ -141,6 +141,8 @@ public final class TextClassifierEvent implements Parcelable { @Nullable private final String mLanguage; private final float mScore; + @Nullable private final String mModelName; + private TextClassifierEvent( int eventCategory, int eventType, @@ -156,7 +158,8 @@ public final class TextClassifierEvent implements Parcelable { int relativeSuggestedWordEndIndex, int[] actionIndex, String language, - float score) { + float score, + String modelVersion) { mEventCategory = eventCategory; mEventType = eventType; mEntityTypes = entityTypes; @@ -172,6 +175,7 @@ public final class TextClassifierEvent implements Parcelable { mActionIndices = actionIndex; mLanguage = language; mScore = score; + mModelName = modelVersion; } @Override @@ -196,6 +200,7 @@ public final class TextClassifierEvent implements Parcelable { dest.writeIntArray(mActionIndices); dest.writeString(mLanguage); dest.writeFloat(mScore); + dest.writeString(mModelName); } private static TextClassifierEvent readFromParcel(Parcel in) { @@ -214,7 +219,8 @@ public final class TextClassifierEvent implements Parcelable { /* relativeSuggestedWordEndIndex= */ in.readInt(), /* actionIndices= */ in.createIntArray(), /* language= */ in.readString(), - /* score= */ in.readFloat()); + /* score= */ in.readFloat(), + /* modelVersion= */ in.readString()); } /** @@ -264,6 +270,7 @@ public final class TextClassifierEvent implements Parcelable { return mEventIndex; } + // TODO: Remove this API. /** * Returns the time this event occurred. This is the number of milliseconds since * January 1, 1970, 00:00:00 GMT. 0 indicates not set. @@ -339,6 +346,15 @@ public final class TextClassifierEvent implements Parcelable { } /** + * Returns the model name. + * @hide + */ + @Nullable + public String getModelName() { + return mModelName; + } + + /** * Builder to build a text classifier event. */ public static final class Builder { @@ -359,6 +375,8 @@ public final class TextClassifierEvent implements Parcelable { @Nullable private String mLanguage; private float mScore; + private String mModelName; + /** * Creates a builder for building {@link TextClassifierEvent}s. * @@ -407,6 +425,7 @@ public final class TextClassifierEvent implements Parcelable { return this; } + // TODO: Remove this API. /** * Sets the time this event occurred. This is the number of milliseconds since * January 1, 1970, 00:00:00 GMT. 0 indicates not set. @@ -501,6 +520,15 @@ public final class TextClassifierEvent implements Parcelable { } /** + * Sets the model name string. + * @hide + */ + public Builder setModelName(@Nullable String modelVersion) { + mModelName = modelVersion; + return this; + } + + /** * Builds and returns a text classifier event. */ @NonNull @@ -521,7 +549,8 @@ public final class TextClassifierEvent implements Parcelable { mRelativeSuggestedWordEndIndex, mActionIndices, mLanguage, - mScore); + mScore, + mModelName); } // TODO: Add build(boolean validate). } @@ -544,6 +573,7 @@ public final class TextClassifierEvent implements Parcelable { out.append(", mActionIndices=").append(Arrays.toString(mActionIndices)); out.append(", mLanguage=").append(mLanguage); out.append(", mScore=").append(mScore); + out.append(", mModelName=").append(mModelName); out.append("}"); return out.toString(); } diff --git a/core/java/android/view/textclassifier/TextClassifierEventTronLogger.java b/core/java/android/view/textclassifier/TextClassifierEventTronLogger.java index 5563dfc2eee5..6a122506d0ac 100644 --- a/core/java/android/view/textclassifier/TextClassifierEventTronLogger.java +++ b/core/java/android/view/textclassifier/TextClassifierEventTronLogger.java @@ -16,7 +16,6 @@ package android.view.textclassifier; import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_TEXTCLASSIFIER_MODEL; -import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_TEXT_CLASSIFIER_EVENT_TIME; import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_TEXT_CLASSIFIER_FIRST_ENTITY_TYPE; import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_TEXT_CLASSIFIER_SCORE; import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_TEXT_CLASSIFIER_SECOND_ENTITY_TYPE; @@ -46,7 +45,7 @@ public final class TextClassifierEventTronLogger { private final MetricsLogger mMetricsLogger; public TextClassifierEventTronLogger() { - mMetricsLogger = new MetricsLogger(); + this(new MetricsLogger()); } @VisibleForTesting @@ -57,6 +56,7 @@ public final class TextClassifierEventTronLogger { /** Emits a text classifier event to the logs. */ public void writeEvent(TextClassifierEvent event) { Preconditions.checkNotNull(event); + int category = getCategory(event); if (category == -1) { Log.w(TAG, "Unknown category: " + event.getEventCategory()); @@ -65,14 +65,12 @@ public final class TextClassifierEventTronLogger { final LogMaker log = new LogMaker(category) .setSubtype(getLogType(event)) .addTaggedData(FIELD_TEXT_CLASSIFIER_SESSION_ID, event.getResultId()) - .addTaggedData(FIELD_TEXT_CLASSIFIER_EVENT_TIME, event.getEventTime()) - .addTaggedData(FIELD_TEXTCLASSIFIER_MODEL, - SelectionSessionLogger.SignatureParser.getModelName(event.getResultId())) + .addTaggedData(FIELD_TEXTCLASSIFIER_MODEL, getModelName(event)) .addTaggedData(FIELD_TEXT_CLASSIFIER_SCORE, event.getScore()); String[] entityTypes = event.getEntityTypes(); - // TRON does not support a field of list type, and thus workaround by store them - // in three separate fields. This is no longer an issue once we have moved to Westworld. + // The old logger does not support a field of list type, and thus workaround by store them + // in three separate fields. This is not an issue with the new logger. if (entityTypes.length >= 1) { log.addTaggedData(FIELD_TEXT_CLASSIFIER_FIRST_ENTITY_TYPE, entityTypes[0]); } @@ -93,6 +91,13 @@ public final class TextClassifierEventTronLogger { debugLog(log); } + private static String getModelName(TextClassifierEvent event) { + if (event.getModelName() != null) { + return event.getModelName(); + } + return SelectionSessionLogger.SignatureParser.getModelName(event.getResultId()); + } + private static int getCategory(TextClassifierEvent event) { switch (event.getEventCategory()) { case TextClassifierEvent.CATEGORY_CONVERSATION_ACTIONS: diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java index c297928ae5f6..14afa339f192 100644 --- a/core/java/android/view/textclassifier/TextClassifierImpl.java +++ b/core/java/android/view/textclassifier/TextClassifierImpl.java @@ -65,9 +65,6 @@ import java.util.Objects; */ public final class TextClassifierImpl implements TextClassifier { - /** @hide */ - public static final String ACTIONS_INTENTS = "actions-intents"; - private static final String LOG_TAG = DEFAULT_LOG_TAG; private static final boolean DEBUG = false; @@ -343,7 +340,11 @@ public final class TextClassifierImpl implements TextClassifier { if (DEBUG) { Log.d(DEFAULT_LOG_TAG, "onTextClassifierEvent() called with: event = [" + event + "]"); } - mTextClassifierEventTronLogger.writeEvent(event); + try { + mTextClassifierEventTronLogger.writeEvent(event); + } catch (Exception e) { + Log.e(LOG_TAG, "Error writing event", e); + } } /** @inheritDoc */ @@ -566,12 +567,16 @@ public final class TextClassifierImpl implements TextClassifier { final float foreignTextThreshold = mSettings.getLangIdThresholdOverride() >= 0 ? mSettings.getLangIdThresholdOverride() : 0.5f /* TODO: Load this from the langId model. */; + final Bundle foreignLanguageBundle = + detectForeignLanguage(classifiedText, foreignTextThreshold); + builder.setForeignLanguageExtra(foreignLanguageBundle); + boolean isPrimaryAction = true; final ArrayList<Intent> sourceIntents = new ArrayList<>(); List<LabeledIntent> labeledIntents = mIntentFactory.create( mContext, classifiedText, - isForeignText(classifiedText, foreignTextThreshold), + foreignLanguageBundle != null, referenceTime, highestScoringResult); for (LabeledIntent labeledIntent : labeledIntents) { @@ -590,28 +595,28 @@ public final class TextClassifierImpl implements TextClassifier { labeledIntent.getIntent(), labeledIntent.getRequestCode()))); isPrimaryAction = false; } - builder.addAction(action); - sourceIntents.add(labeledIntent.getIntent()); + builder.addAction(action, labeledIntent.getIntent()); } - final Bundle extras = new Bundle(); - extras.putParcelableArrayList(ACTIONS_INTENTS, sourceIntents); - - return builder.setId(createId(text, start, end)) - .setExtras(extras) - .build(); + return builder.setId(createId(text, start, end)).build(); } - private boolean isForeignText(String text, float threshold) { + /** + * Returns a bundle with the language and confidence score if it finds the text to be + * in a foreign language. Otherwise returns null. + */ + @Nullable + private Bundle detectForeignLanguage(String text, float threshold) { if (threshold > 1) { - return false; + return null; } // TODO: Revisit this algorithm. try { - final LangIdModel.LanguageResult[] langResults = getLangIdImpl().detectLanguages(text); + final LangIdModel langId = getLangIdImpl(); + final LangIdModel.LanguageResult[] langResults = langId.detectLanguages(text); if (langResults.length <= 0) { - return false; + return null; } LangIdModel.LanguageResult highestScoringResult = langResults[0]; @@ -621,7 +626,7 @@ public final class TextClassifierImpl implements TextClassifier { } } if (highestScoringResult.getScore() < threshold) { - return false; + return null; } // TODO: Remove Log.d(LOG_TAG, String.format("Language detected: <%s:%s>", @@ -632,14 +637,15 @@ public final class TextClassifierImpl implements TextClassifier { final int size = deviceLocales.size(); for (int i = 0; i < size; i++) { if (deviceLocales.get(i).getLanguage().equals(detected.getLanguage())) { - return false; + return null; } } - return true; + return ExtrasUtils.createForeignLanguageExtra( + detected.getLanguage(), highestScoringResult.getScore(), langId.getVersion()); } catch (Throwable t) { Log.e(LOG_TAG, "Error detecting foreign text. Ignored.", t); } - return false; + return null; } @Override @@ -773,3 +779,4 @@ public final class TextClassifierImpl implements TextClassifier { } } } + diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java index 4a60b6a8185a..c38566b87d9c 100644 --- a/core/java/android/widget/Editor.java +++ b/core/java/android/widget/Editor.java @@ -4112,9 +4112,9 @@ public class Editor { } } - private MenuItem addAssistMenuItem(Menu menu, RemoteAction action, int intemId, int order, + private MenuItem addAssistMenuItem(Menu menu, RemoteAction action, int itemId, int order, int showAsAction) { - final MenuItem item = menu.add(TextView.ID_ASSIST, intemId, order, action.getTitle()) + final MenuItem item = menu.add(TextView.ID_ASSIST, itemId, order, action.getTitle()) .setContentDescription(action.getContentDescription()); if (action.shouldShowIcon()) { item.setIcon(action.getIcon().loadDrawable(mTextView.getContext())); @@ -4188,7 +4188,8 @@ public class Editor { @Override public boolean onActionItemClicked(ActionMode mode, MenuItem item) { - getSelectionActionModeHelper().onSelectionAction(item.getItemId()); + getSelectionActionModeHelper() + .onSelectionAction(item.getItemId(), item.getTitle().toString()); if (mProcessTextIntentActionsHandler.performMenuItemAction(item)) { return true; diff --git a/core/java/android/widget/SelectionActionModeHelper.java b/core/java/android/widget/SelectionActionModeHelper.java index 4caf28881edc..564cfdd20d76 100644 --- a/core/java/android/widget/SelectionActionModeHelper.java +++ b/core/java/android/widget/SelectionActionModeHelper.java @@ -20,12 +20,14 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UiThread; import android.annotation.WorkerThread; +import android.app.RemoteAction; import android.content.Context; import android.graphics.Canvas; import android.graphics.PointF; import android.graphics.RectF; import android.os.AsyncTask; import android.os.Build; +import android.os.Bundle; import android.os.LocaleList; import android.text.Layout; import android.text.Selection; @@ -34,13 +36,16 @@ import android.text.TextUtils; import android.text.util.Linkify; import android.util.Log; import android.view.ActionMode; +import android.view.textclassifier.ExtrasUtils; import android.view.textclassifier.SelectionEvent; import android.view.textclassifier.SelectionEvent.InvocationMethod; import android.view.textclassifier.SelectionSessionLogger; import android.view.textclassifier.TextClassification; import android.view.textclassifier.TextClassificationConstants; +import android.view.textclassifier.TextClassificationContext; import android.view.textclassifier.TextClassificationManager; import android.view.textclassifier.TextClassifier; +import android.view.textclassifier.TextClassifierEvent; import android.view.textclassifier.TextSelection; import android.widget.Editor.SelectionModifierCursorController; @@ -166,16 +171,17 @@ public final class SelectionActionModeHelper { } } - public void onSelectionAction(int menuItemId) { + /** Reports a selection action event. */ + public void onSelectionAction(int menuItemId, @Nullable String actionLabel) { mSelectionTracker.onSelectionAction( mTextView.getSelectionStart(), mTextView.getSelectionEnd(), - getActionType(menuItemId), mTextClassification); + getActionType(menuItemId), actionLabel, mTextClassification); } public void onSelectionDrag() { mSelectionTracker.onSelectionAction( mTextView.getSelectionStart(), mTextView.getSelectionEnd(), - SelectionEvent.ACTION_DRAG, mTextClassification); + SelectionEvent.ACTION_DRAG, /* actionLabel= */ null, mTextClassification); } public void onTextChanged(int start, int end) { @@ -511,8 +517,11 @@ public final class SelectionActionModeHelper { mOriginalEnd = mSelectionEnd = selectionEnd; mAllowReset = false; maybeInvalidateLogger(); - mLogger.logSelectionStarted(mTextView.getTextClassificationSession(), - text, selectionStart, + mLogger.logSelectionStarted( + mTextView.getTextClassificationSession(), + mTextView.getTextClassificationContext(), + text, + selectionStart, isLink ? SelectionEvent.INVOCATION_LINK : SelectionEvent.INVOCATION_MANUAL); } @@ -570,10 +579,12 @@ public final class SelectionActionModeHelper { public void onSelectionAction( int selectionStart, int selectionEnd, @SelectionEvent.ActionType int action, + @Nullable String actionLabel, @Nullable TextClassification classification) { if (isSelectionStarted()) { mAllowReset = false; - mLogger.logSelectionAction(selectionStart, selectionEnd, action, classification); + mLogger.logSelectionAction( + selectionStart, selectionEnd, action, actionLabel, classification); } } @@ -596,7 +607,8 @@ public final class SelectionActionModeHelper { mSelectionEnd = editor.getTextView().getSelectionEnd(); mLogger.logSelectionAction( textView.getSelectionStart(), textView.getSelectionEnd(), - SelectionEvent.ACTION_RESET, null /* classification */); + SelectionEvent.ACTION_RESET, + /* actionLabel= */ null, /* classification= */ null); } return selected; } @@ -605,7 +617,9 @@ public final class SelectionActionModeHelper { public void onTextChanged(int start, int end, TextClassification classification) { if (isSelectionStarted() && start == mSelectionStart && end == mSelectionEnd) { - onSelectionAction(start, end, SelectionEvent.ACTION_OVERTYPE, classification); + onSelectionAction( + start, end, SelectionEvent.ACTION_OVERTYPE, + /* actionLabel= */ null, classification); } } @@ -644,7 +658,8 @@ public final class SelectionActionModeHelper { if (mIsPending) { mLogger.logSelectionAction( mSelectionStart, mSelectionEnd, - SelectionEvent.ACTION_ABANDON, null /* classification */); + SelectionEvent.ACTION_ABANDON, + /* actionLabel= */ null, /* classification= */ null); mSelectionStart = mSelectionEnd = -1; mLogger.endTextClassificationSession(); mIsPending = false; @@ -679,6 +694,11 @@ public final class SelectionActionModeHelper { private final BreakIterator mTokenIterator; @Nullable private TextClassifier mClassificationSession; + @Nullable private TextClassificationContext mClassificationContext; + + @Nullable private TextClassifierEvent mTranslateViewEvent; + @Nullable private TextClassifierEvent mTranslateClickEvent; + private int mStartIndex; private String mText; @@ -690,6 +710,7 @@ public final class SelectionActionModeHelper { public void logSelectionStarted( TextClassifier classificationSession, + TextClassificationContext classificationContext, CharSequence text, int index, @InvocationMethod int invocationMethod) { try { @@ -701,6 +722,7 @@ public final class SelectionActionModeHelper { mTokenIterator.setText(mText); mStartIndex = index; mClassificationSession = classificationSession; + mClassificationContext = classificationContext; if (hasActiveClassificationSession()) { mClassificationSession.onSelectionEvent( SelectionEvent.createSelectionStartedEvent(invocationMethod, 0)); @@ -731,6 +753,7 @@ public final class SelectionActionModeHelper { SelectionEvent.createSelectionModifiedEvent( wordIndices[0], wordIndices[1])); } + maybeGenerateTranslateViewEvent(classification); } } catch (Exception e) { // Avoid crashes due to logging. @@ -741,6 +764,7 @@ public final class SelectionActionModeHelper { public void logSelectionAction( int start, int end, @SelectionEvent.ActionType int action, + @Nullable String actionLabel, @Nullable TextClassification classification) { try { if (hasActiveClassificationSession()) { @@ -757,6 +781,9 @@ public final class SelectionActionModeHelper { SelectionEvent.createSelectionActionEvent( wordIndices[0], wordIndices[1], action)); } + + maybeGenerateTranslateClickEvent(classification, actionLabel); + if (SelectionEvent.isTerminal(action)) { endTextClassificationSession(); } @@ -773,6 +800,7 @@ public final class SelectionActionModeHelper { public void endTextClassificationSession() { if (hasActiveClassificationSession()) { + maybeReportTranslateEvents(); mClassificationSession.destroy(); } } @@ -843,6 +871,78 @@ public final class SelectionActionModeHelper { private boolean isWhitespace(int start, int end) { return PATTERN_WHITESPACE.matcher(mText.substring(start, end)).matches(); } + + private void maybeGenerateTranslateViewEvent(@Nullable TextClassification classification) { + if (classification != null) { + final TextClassifierEvent event = generateTranslateEvent( + TextClassifierEvent.TYPE_ACTIONS_SHOWN, + classification, mClassificationContext, /* actionLabel= */null); + mTranslateViewEvent = (event != null) ? event : mTranslateViewEvent; + } + } + + private void maybeGenerateTranslateClickEvent( + @Nullable TextClassification classification, String actionLabel) { + if (classification != null) { + mTranslateClickEvent = generateTranslateEvent( + TextClassifierEvent.TYPE_SMART_ACTION, + classification, mClassificationContext, actionLabel); + } + } + + private void maybeReportTranslateEvents() { + // Translate view and click events should only be logged once per selection session. + if (mTranslateViewEvent != null) { + mClassificationSession.onTextClassifierEvent(mTranslateViewEvent); + mTranslateViewEvent = null; + } + if (mTranslateClickEvent != null) { + mClassificationSession.onTextClassifierEvent(mTranslateClickEvent); + mTranslateClickEvent = null; + } + } + + @Nullable + private static TextClassifierEvent generateTranslateEvent( + int eventType, TextClassification classification, + TextClassificationContext classificationContext, @Nullable String actionLabel) { + + // The platform attempts to log "views" and "clicks" of the "Translate" action. + // Views are logged if a user is presented with the translate action during a selection + // session. + // Clicks are logged if the user clicks on the translate action. + // The index of the translate action is also logged to indicate whether it might have + // been in the main panel or overflow panel of the selection toolbar. + // NOTE that the "views" metric may be flawed if a TextView removes the translate menu + // item via a custom action mode callback or does not show a selection menu item. + + final RemoteAction translateAction = ExtrasUtils.findTranslateAction(classification); + if (translateAction == null) { + // No translate action present. Nothing to log. Exit. + return null; + } + + if (eventType == TextClassifierEvent.TYPE_SMART_ACTION + && !translateAction.getTitle().toString().equals(actionLabel)) { + // Clicked action is not a translate action. Nothing to log. Exit. + // Note that we don't expect an actionLabel for "view" events. + return null; + } + + final Bundle foreignLanguageExtra = ExtrasUtils.getForeignLanguageExtra(classification); + final String language = ExtrasUtils.getEntityType(foreignLanguageExtra); + final float score = ExtrasUtils.getScore(foreignLanguageExtra); + final String model = ExtrasUtils.getModelName(foreignLanguageExtra); + return new TextClassifierEvent.Builder( + TextClassifierEvent.CATEGORY_LANGUAGE_DETECTION, eventType) + .setEventContext(classificationContext) + .setResultId(classification.getId()) + .setEntityTypes(language) + .setScore(score) + .setActionIndices(classification.getActions().indexOf(translateAction)) + .setModelName(model) + .build(); + } } /** diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 2b45c0697155..8029cf0eb50e 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -456,6 +456,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener private TextClassifier mTextClassifier; private TextClassifier mTextClassificationSession; + private TextClassificationContext mTextClassificationContext; // A flag to prevent repeated movements from escaping the enclosing text view. The idea here is // that if a user is holding down a movement key to traverse text, we shouldn't also traverse @@ -12068,16 +12069,15 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } else { widgetType = TextClassifier.WIDGET_TYPE_UNSELECTABLE_TEXTVIEW; } - final TextClassificationContext textClassificationContext = - new TextClassificationContext.Builder( - mContext.getPackageName(), widgetType) - .build(); + mTextClassificationContext = new TextClassificationContext.Builder( + mContext.getPackageName(), widgetType) + .build(); if (mTextClassifier != null) { mTextClassificationSession = tcm.createTextClassificationSession( - textClassificationContext, mTextClassifier); + mTextClassificationContext, mTextClassifier); } else { mTextClassificationSession = tcm.createTextClassificationSession( - textClassificationContext); + mTextClassificationContext); } } else { mTextClassificationSession = TextClassifier.NO_OP; @@ -12087,6 +12087,15 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } /** + * Returns the {@link TextClassificationContext} for the current TextClassifier session. + * @see #getTextClassificationSession() + */ + @Nullable + TextClassificationContext getTextClassificationContext() { + return mTextClassificationContext; + } + + /** * Returns true if this TextView uses a no-op TextClassifier. */ boolean usesNoOpTextClassifier() { diff --git a/core/java/com/android/internal/os/OWNERS b/core/java/com/android/internal/os/OWNERS new file mode 100644 index 000000000000..928310549e6e --- /dev/null +++ b/core/java/com/android/internal/os/OWNERS @@ -0,0 +1 @@ +per-file ZygoteArguments.java,ZygoteConnection.java,ZygoteInit.java,Zygote.java,ZygoteServer.java = chriswailes@google.com, ngeoffray@google.com, sehr@google.com, narayan@google.com, maco@google.com diff --git a/core/jni/OWNERS b/core/jni/OWNERS index a365a566f038..86342c47c455 100644 --- a/core/jni/OWNERS +++ b/core/jni/OWNERS @@ -4,3 +4,6 @@ per-file *Camera*,*camera* = shuzhenwang@google.com, yinchiayeh@google.com, zhij # Connectivity per-file android_net_* = ek@google.com, lorenzo@google.com, satk@google.com + +# Zygote +per-file com_android_inernal_os_Zygote.*,fd_utils.* = chriswailes@google.com, ngeoffray@google.com, sehr@google.com, narayan@google.com, maco@google.com diff --git a/core/jni/android_media_AudioAttributes.cpp b/core/jni/android_media_AudioAttributes.cpp index 4be4def4a87b..b87a34d6c7aa 100644 --- a/core/jni/android_media_AudioAttributes.cpp +++ b/core/jni/android_media_AudioAttributes.cpp @@ -135,7 +135,7 @@ JNIAudioAttributeHelper::UniqueAaPtr JNIAudioAttributeHelper::makeUnique() { audio_attributes_t *aa = new (calloc(1, sizeof(audio_attributes_t))) audio_attributes_t{AUDIO_ATTRIBUTES_INITIALIZER}; - return UniqueAaPtr{aa, free}; + return UniqueAaPtr{aa}; } jint JNIAudioAttributeHelper::nativeFromJava(JNIEnv* env, jobject jAudioAttributes, diff --git a/core/jni/android_media_AudioAttributes.h b/core/jni/android_media_AudioAttributes.h index c55835222086..628f7e3469e8 100644 --- a/core/jni/android_media_AudioAttributes.h +++ b/core/jni/android_media_AudioAttributes.h @@ -27,7 +27,11 @@ namespace android { class JNIAudioAttributeHelper { public: - using UniqueAaPtr = std::unique_ptr<audio_attributes_t, decltype(free)*>; + struct FreeDeleter { + void operator()(void *p) const { ::free(p); } + }; + + using UniqueAaPtr = std::unique_ptr<audio_attributes_t, FreeDeleter>; /** * @brief makeUnique helper to prevent leak diff --git a/core/jni/android_os_VintfObject.cpp b/core/jni/android_os_VintfObject.cpp index e64d2afe7bf3..ee11b6162db0 100644 --- a/core/jni/android_os_VintfObject.cpp +++ b/core/jni/android_os_VintfObject.cpp @@ -96,7 +96,7 @@ static jobjectArray android_os_VintfObject_report(JNIEnv* env, jclass) return toJavaStringArray(env, cStrings); } -static jint verify(JNIEnv* env, jobjectArray packageInfo, android::vintf::CheckFlags::Type checks) { +static jint android_os_VintfObject_verify(JNIEnv* env, jclass, jobjectArray packageInfo) { std::vector<std::string> cPackageInfo; if (packageInfo) { size_t count = env->GetArrayLength(packageInfo); @@ -109,18 +109,19 @@ static jint verify(JNIEnv* env, jobjectArray packageInfo, android::vintf::CheckF } } std::string error; - int32_t status = VintfObject::CheckCompatibility(cPackageInfo, &error, checks); + int32_t status = VintfObject::CheckCompatibility(cPackageInfo, &error); if (status) LOG(WARNING) << "VintfObject.verify() returns " << status << ": " << error; return status; } -static jint android_os_VintfObject_verify(JNIEnv* env, jclass, jobjectArray packageInfo) { - return verify(env, packageInfo, ::android::vintf::CheckFlags::ENABLE_ALL_CHECKS); -} - static jint android_os_VintfObject_verifyWithoutAvb(JNIEnv* env, jclass) { - return verify(env, nullptr, ::android::vintf::CheckFlags::DISABLE_AVB_CHECK); + std::string error; + int32_t status = VintfObject::CheckCompatibility({}, &error, + ::android::vintf::CheckFlags::DISABLE_AVB_CHECK); + if (status) + LOG(WARNING) << "VintfObject.verifyWithoutAvb() returns " << status << ": " << error; + return status; } static jobjectArray android_os_VintfObject_getHalNamesAndVersions(JNIEnv* env, jclass) { diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml index ef3834cccc15..baf758752abe 100644 --- a/core/res/res/values/dimens.xml +++ b/core/res/res/values/dimens.xml @@ -240,7 +240,7 @@ <dimen name="notification_header_icon_size">18dp</dimen> <!-- size (width and height) of the icon in the notification header --> - <dimen name="notification_header_icon_size_ambient">20dp</dimen> + <dimen name="notification_header_icon_size_ambient">18dp</dimen> <!-- The margin before the start of the app name in the header. --> <dimen name="notification_header_app_name_margin_start">3dp</dimen> diff --git a/core/res/res/values/styles_device_defaults.xml b/core/res/res/values/styles_device_defaults.xml index 79afe697c504..0dc54e091f9d 100644 --- a/core/res/res/values/styles_device_defaults.xml +++ b/core/res/res/values/styles_device_defaults.xml @@ -374,7 +374,9 @@ easier. <style name="TextAppearance.DeviceDefault.Caption" parent="TextAppearance.Material.Caption"> <item name="fontFamily">@string/config_bodyFontFamily</item> </style> - <style name="TextAppearance.DeviceDefault.ListItem" parent="TextAppearance.DeviceDefault.Subhead"/> + <style name="TextAppearance.DeviceDefault.ListItem" parent="TextAppearance.DeviceDefault.Subhead"> + <item name="fontFamily">@string/config_headlineFontFamily</item> + </style> <style name="TextAppearance.DeviceDefault.ListItemSecondary" parent="TextAppearance.DeviceDefault.Body1"/> <!-- Preference Styles --> diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java index 5e58f82038f1..582be9d51731 100644 --- a/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java +++ b/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java @@ -21,8 +21,10 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; +import android.app.RemoteAction; import android.content.Context; import android.content.Intent; +import android.os.Bundle; import android.os.LocaleList; import android.text.Spannable; import android.text.SpannableString; @@ -246,25 +248,31 @@ public class TextClassifierTest { public void testClassifyText_foreignText() { LocaleList originalLocales = LocaleList.getDefault(); LocaleList.setDefault(LocaleList.forLanguageTags("en")); - String foreignText = "これは日本語のテキストです"; + String japaneseText = "これは日本語のテキストです"; Context context = new FakeContextBuilder() .setIntentComponent(Intent.ACTION_TRANSLATE, FakeContextBuilder.DEFAULT_COMPONENT) .build(); TextClassifier classifier = new TextClassifierImpl(context, TC_CONSTANTS); TextClassification.Request request = new TextClassification.Request.Builder( - foreignText, 0, foreignText.length()) + japaneseText, 0, japaneseText.length()) .setDefaultLocales(LOCALES) .build(); TextClassification classification = classifier.classifyText(request); + RemoteAction translateAction = classification.getActions().get(0); assertEquals(1, classification.getActions().size()); assertEquals( context.getString(com.android.internal.R.string.translate), - classification.getActions().get(0).getTitle()); - Intent intent = (Intent) classification.getExtras() - .getParcelableArrayList(TextClassifierImpl.ACTIONS_INTENTS).get(0); + translateAction.getTitle()); + + assertEquals(translateAction, ExtrasUtils.findTranslateAction(classification)); + Intent intent = ExtrasUtils.getActionsIntents(classification).get(0); assertEquals(Intent.ACTION_TRANSLATE, intent.getAction()); + Bundle foreignLanguageInfo = ExtrasUtils.getForeignLanguageExtra(classification); + assertEquals("ja", ExtrasUtils.getEntityType(foreignLanguageInfo)); + assertTrue(ExtrasUtils.getScore(foreignLanguageInfo) >= 0); + assertTrue(ExtrasUtils.getScore(foreignLanguageInfo) <= 1); LocaleList.setDefault(originalLocales); } diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml index a47ab875804f..bcac5fd63930 100644 --- a/data/etc/privapp-permissions-platform.xml +++ b/data/etc/privapp-permissions-platform.xml @@ -329,6 +329,7 @@ applications that come with the platform <permission name="android.permission.USE_RESERVED_DISK"/> <permission name="android.permission.WRITE_MEDIA_STORAGE"/> <permission name="android.permission.WRITE_SECURE_SETTINGS"/> + <permission name="android.permission.STATUS_BAR_SERVICE"/> <permission name="android.permission.REQUEST_INCIDENT_REPORT_APPROVAL"/> </privapp-permissions> diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java index 97cb2ec2b4f7..f9e7dd177342 100644 --- a/graphics/java/android/graphics/Bitmap.java +++ b/graphics/java/android/graphics/Bitmap.java @@ -21,7 +21,6 @@ import android.annotation.ColorInt; import android.annotation.ColorLong; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.TestApi; import android.annotation.UnsupportedAppUsage; import android.annotation.WorkerThread; import android.content.res.ResourcesImpl; @@ -1762,9 +1761,7 @@ public final class Bitmap implements Parcelable { * previously assigned color space. * * @param colorSpace to assign to the bitmap - * @hide */ - @TestApi public void setColorSpace(@NonNull ColorSpace colorSpace) { checkRecycled("setColorSpace called on a recycled bitmap"); if (colorSpace == null) { @@ -1815,9 +1812,7 @@ public final class Bitmap implements Parcelable { * @throws IllegalArgumentException if the color space encoded in the long * is invalid or unknown. * - * @hide pending API approval */ - @TestApi public void eraseColor(@ColorLong long c) { checkRecycled("Can't erase a recycled bitmap"); if (!isMutable()) { @@ -1864,9 +1859,7 @@ public final class Bitmap implements Parcelable { * @throws IllegalArgumentException if x, y exceed the bitmap's bounds * @throws IllegalStateException if the bitmap's config is {@link Config#HARDWARE} * - * @hide pending API approval */ - @TestApi public Color getColor(int x, int y) { checkRecycled("Can't call getColor() on a recycled bitmap"); checkHardware("unable to getColor(), " diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java index 7eee6f4bf37d..73442db1c143 100644 --- a/graphics/java/android/graphics/Paint.java +++ b/graphics/java/android/graphics/Paint.java @@ -24,7 +24,6 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.Px; import android.annotation.Size; -import android.annotation.TestApi; import android.annotation.UnsupportedAppUsage; import android.graphics.fonts.FontVariationAxis; import android.os.Build; @@ -974,10 +973,7 @@ public class Paint { * @see Color for APIs that help manipulate a color long. * * @return the paint's color (and alpha). - * - * @hide pending API approval */ - @TestApi @ColorLong public long getColorLong() { return mColor; @@ -1006,10 +1002,7 @@ public class Paint { * to set in the paint. * @throws IllegalArgumentException if the color space encoded in the long * is invalid or unknown. - * - * @hide pending API approval */ - @TestApi public void setColor(@ColorLong long color) { ColorSpace cs = Color.colorSpace(color); float r = Color.red(color); @@ -1445,10 +1438,7 @@ public class Paint { * * @throws IllegalArgumentException if the color space encoded in the long * is invalid or unknown. - * - * @hide pending API approval */ - @TestApi public void setShadowLayer(float radius, float dx, float dy, @ColorLong long shadowColor) { ColorSpace cs = Color.colorSpace(shadowColor); float r = Color.red(shadowColor); @@ -1517,9 +1507,7 @@ public class Paint { * Returns the color of the shadow layer. * @see #setShadowLayer(float,float,float,int) * @see #setShadowLayer(float,float,float,long) - * @hide pending API approval */ - @TestApi public @ColorLong long getShadowLayerColorLong() { return mShadowLayerColor; } diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp index b67aea224055..d9456355cb88 100644 --- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp +++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp @@ -142,10 +142,8 @@ void SkiaRecordingCanvas::callDrawGLFunction(Functor* functor, void SkiaRecordingCanvas::drawWebViewFunctor(int functor) { FunctorDrawable* functorDrawable; if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) { - // TODO(cblume) use VkFunctorDrawable instead of VkInteropFunctorDrawable here when the - // interop is disabled. functorDrawable = - mDisplayList->allocateDrawable<VkInteropFunctorDrawable>(functor, asSkCanvas()); + mDisplayList->allocateDrawable<VkFunctorDrawable>(functor, asSkCanvas()); } else { functorDrawable = mDisplayList->allocateDrawable<GLFunctorDrawable>(functor, asSkCanvas()); } diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java index 59c6a0a21cd1..63b57d166f1f 100644 --- a/location/java/android/location/LocationManager.java +++ b/location/java/android/location/LocationManager.java @@ -181,22 +181,14 @@ public class LocationManager { "android.location.GPS_ENABLED_CHANGE"; /** - * Broadcast intent action when the configured location providers - * change. For use with {@link #isProviderEnabled(String)}. If you're interacting with the - * {@link android.provider.Settings.Secure#LOCATION_MODE} API, use {@link #MODE_CHANGED_ACTION} - * instead. + * Broadcast intent action when the set of enabled location providers changes. To check the + * status of a provider, use {@link #isProviderEnabled(String)}. */ - public static final String PROVIDERS_CHANGED_ACTION = - "android.location.PROVIDERS_CHANGED"; + public static final String PROVIDERS_CHANGED_ACTION = "android.location.PROVIDERS_CHANGED"; /** - * Broadcast intent action when {@link android.provider.Settings.Secure#LOCATION_MODE} changes. - * For use with the {@link android.provider.Settings.Secure#LOCATION_MODE} API. - * If you're interacting with {@link #isProviderEnabled(String)}, use - * {@link #PROVIDERS_CHANGED_ACTION} instead. - * - * In the future, there may be mode changes that do not result in - * {@link #PROVIDERS_CHANGED_ACTION} broadcasts. + * Broadcast intent action when the device location mode changes. To check the location mode, + * use {@link #isLocationEnabled()}. */ public static final String MODE_CHANGED_ACTION = "android.location.MODE_CHANGED"; @@ -207,8 +199,10 @@ public class LocationManager { * If you're interacting with {@link #isProviderEnabled(String)}, use * {@link #PROVIDERS_CHANGED_ACTION} instead. * + * @deprecated Do not use. * @hide */ + @Deprecated public static final String MODE_CHANGING_ACTION = "com.android.settings.location.MODE_CHANGING"; /** @@ -299,7 +293,7 @@ public class LocationManager { "com.android.settings.location.FOOTER_STRING"; // Map from LocationListeners to their associated ListenerTransport objects - private HashMap<LocationListener,ListenerTransport> mListeners = + private final HashMap<LocationListener, ListenerTransport> mListeners = new HashMap<LocationListener,ListenerTransport>(); private class ListenerTransport extends ILocationListener.Stub { @@ -1264,39 +1258,20 @@ public class LocationManager { } /** - * Returns the current enabled/disabled status of location + * Returns the current enabled/disabled state of location. To listen for changes, see + * {@link #MODE_CHANGED_ACTION}. * - * @return true if location is enabled. false if location is disabled. + * @return true if location is enabled and false if location is disabled. */ public boolean isLocationEnabled() { return isLocationEnabledForUser(Process.myUserHandle()); } /** - * Method for enabling or disabling location. - * - * @param enabled true to enable location. false to disable location - * @param userHandle the user to set - * - * @hide - */ - @SystemApi - @RequiresPermission(WRITE_SECURE_SETTINGS) - public void setLocationEnabledForUser(boolean enabled, UserHandle userHandle) { - Settings.Secure.putIntForUser( - mContext.getContentResolver(), - Settings.Secure.LOCATION_MODE, - enabled - ? Settings.Secure.LOCATION_MODE_HIGH_ACCURACY - : Settings.Secure.LOCATION_MODE_OFF, - userHandle.getIdentifier()); - } - - /** - * Returns the current enabled/disabled status of location + * Returns the current enabled/disabled state of location. * * @param userHandle the user to query - * @return true location is enabled. false if location is disabled. + * @return true if location is enabled and false if location is disabled. * * @hide */ @@ -1310,19 +1285,32 @@ public class LocationManager { } /** - * Returns the current enabled/disabled status of the given provider. + * Enables or disables the location setting. * - * <p>If the user has enabled this provider in the Settings menu, true - * is returned otherwise false is returned + * @param enabled true to enable location and false to disable location. + * @param userHandle the user to set * - * <p>Callers should instead use {@link #isLocationEnabled()} - * unless they depend on provider-specific APIs such as - * {@link #requestLocationUpdates(String, long, float, LocationListener)}. + * @hide + */ + @SystemApi + @RequiresPermission(WRITE_SECURE_SETTINGS) + public void setLocationEnabledForUser(boolean enabled, UserHandle userHandle) { + Settings.Secure.putIntForUser( + mContext.getContentResolver(), + Settings.Secure.LOCATION_MODE, + enabled + ? Settings.Secure.LOCATION_MODE_ON + : Settings.Secure.LOCATION_MODE_OFF, + userHandle.getIdentifier()); + } + + /** + * Returns the current enabled/disabled status of the given provider. To listen for changes, see + * {@link #PROVIDERS_CHANGED_ACTION}. * - * <p> - * Before API version {@link android.os.Build.VERSION_CODES#LOLLIPOP}, this - * method would throw {@link SecurityException} if the location permissions - * were not sufficient to use the specified provider. + * Before API version {@link android.os.Build.VERSION_CODES#LOLLIPOP}, this method would throw + * {@link SecurityException} if the location permissions were not sufficient to use the + * specified provider. * * @param provider the name of the provider * @return true if the provider exists and is enabled @@ -1334,19 +1322,13 @@ public class LocationManager { } /** - * Returns the current enabled/disabled status of the given provider and user. - * - * <p>If the user has enabled this provider in the Settings menu, true - * is returned otherwise false is returned - * - * <p>Callers should instead use {@link #isLocationEnabled()} - * unless they depend on provider-specific APIs such as - * {@link #requestLocationUpdates(String, long, float, LocationListener)}. + * Returns the current enabled/disabled status of the given provider and user. Callers should + * prefer {@link #isLocationEnabledForUser(UserHandle)} unless they depend on provider-specific + * APIs. * - * <p> - * Before API version {@link android.os.Build.VERSION_CODES#LOLLIPOP}, this - * method would throw {@link SecurityException} if the location permissions - * were not sufficient to use the specified provider. + * Before API version {@link android.os.Build.VERSION_CODES#LOLLIPOP}, this method would throw + * {@link SecurityException} if the location permissions were not sufficient to use the + * specified provider. * * @param provider the name of the provider * @param userHandle the user to query @@ -1367,12 +1349,14 @@ public class LocationManager { } /** - * Method for enabling or disabling a single location provider. + * Method for enabling or disabling a single location provider. This method is deprecated and + * functions as a best effort. It should not be relied on in any meaningful sense as providers + * may no longer be enabled or disabled by clients. * * @param provider the name of the provider * @param enabled true to enable the provider. false to disable the provider * @param userHandle the user to set - * @return true if the value was set, false on database errors + * @return true if the value was set, false otherwise * * @throws IllegalArgumentException if provider is null * @deprecated Do not manipulate providers individually, use diff --git a/location/java/android/location/LocationRequest.java b/location/java/android/location/LocationRequest.java index 3d0afb098697..0480eab580ac 100644 --- a/location/java/android/location/LocationRequest.java +++ b/location/java/android/location/LocationRequest.java @@ -683,6 +683,7 @@ public final class LocationRequest implements Parcelable { request.setSmallestDisplacement(in.readFloat()); request.setHideFromAppOps(in.readInt() != 0); request.setLowPowerMode(in.readInt() != 0); + request.setLocationSettingsIgnored(in.readInt() != 0); String provider = in.readString(); if (provider != null) request.setProvider(provider); WorkSource workSource = in.readParcelable(null); @@ -711,6 +712,7 @@ public final class LocationRequest implements Parcelable { parcel.writeFloat(mSmallestDisplacement); parcel.writeInt(mHideFromAppOps ? 1 : 0); parcel.writeInt(mLowPowerMode ? 1 : 0); + parcel.writeInt(mLocationSettingsIgnored ? 1 : 0); parcel.writeString(mProvider); parcel.writeParcelable(mWorkSource, 0); } @@ -755,6 +757,9 @@ public final class LocationRequest implements Parcelable { s.append(" num=").append(mNumUpdates); } s.append(" lowPowerMode=").append(mLowPowerMode); + if (mLocationSettingsIgnored) { + s.append(" ignoreSettings"); + } s.append(']'); return s.toString(); } diff --git a/media/Android.bp b/media/Android.bp index e7d5faf52d69..d7b8dd23bd6b 100644 --- a/media/Android.bp +++ b/media/Android.bp @@ -1,30 +1,4 @@ java_library { - name: "updatable-media1", - - srcs: [ - ":media1-srcs", - ":framework-media-annotation-srcs", - ], - - aidl: { - export_include_dirs: [ - "apex/java", - ], - - // TODO: find out a way to include only the necessary aidl files instead of dirs. - include_dirs: [ - "frameworks/base/core/java", - "frameworks/base/media/java", - ], - }, - - installable: true, - - // Make sure that the implementaion only relies on SDK or system APIs. - sdk_version: "system_current", -} - -java_library { name: "updatable-media", srcs: [ @@ -57,55 +31,12 @@ java_library { filegroup { name: "media-srcs-without-aidls", srcs : [ - ":media1-srcs-without-aidls", ":mediasession2-srcs-without-aidls", ":mediaplayer2-srcs", ], } filegroup { - name: "media1-srcs", - srcs: [ - "apex/java/android/media/MediaDescription.java", - "apex/java/android/media/MediaParceledListSlice.java", - "apex/java/android/media/Rating.java", - "apex/java/android/media/VolumeProvider.java", - "apex/java/android/media/browse/MediaBrowser.java", - "apex/java/android/media/browse/MediaBrowserUtils.java", - "apex/java/android/media/session/ControllerCallbackLink.java", - "apex/java/android/media/session/ControllerLink.java", - "apex/java/android/media/session/ISession.aidl", - "apex/java/android/media/session/ISessionCallback.aidl", - "apex/java/android/media/session/ISessionController.aidl", - "apex/java/android/media/session/ISessionControllerCallback.aidl", - "apex/java/android/media/session/MediaController.java", - "apex/java/android/media/session/MediaSessionEngine.java", - "apex/java/android/media/session/MediaSessionProviderService.java", - "apex/java/android/media/session/PlaybackState.java", - "apex/java/android/media/session/SessionCallbackLink.java", - "apex/java/android/media/session/SessionLink.java", - "apex/java/android/service/media/IMediaBrowserService.aidl", - "apex/java/android/service/media/IMediaBrowserServiceCallbacks.aidl", - "apex/java/android/service/media/MediaBrowserService.java", - ], -} - -filegroup { - name: "media1-srcs-without-aidls", - srcs: [ - ":media1-srcs", - ], - exclude_srcs: [ - "apex/java/android/media/session/ISession.aidl", - "apex/java/android/media/session/ISessionCallback.aidl", - "apex/java/android/media/session/ISessionController.aidl", - "apex/java/android/media/session/ISessionControllerCallback.aidl", - "apex/java/android/service/media/IMediaBrowserService.aidl", - "apex/java/android/service/media/IMediaBrowserServiceCallbacks.aidl", - ], -} - -filegroup { name: "mediasession2-srcs", srcs: [ "apex/java/android/media/Controller2Link.java", diff --git a/media/apex/java/android/media/MediaPlayer2.java b/media/apex/java/android/media/MediaPlayer2.java index 1a1f6fb4457a..0fd496bda251 100644 --- a/media/apex/java/android/media/MediaPlayer2.java +++ b/media/apex/java/android/media/MediaPlayer2.java @@ -21,6 +21,7 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.StringDef; +import android.annotation.TestApi; import android.content.ContentResolver; import android.content.Context; import android.content.res.AssetFileDescriptor; @@ -3667,53 +3668,66 @@ public class MediaPlayer2 implements AutoCloseable } /** - * The status codes for {@link DrmEventCallback#onDrmPrepared} listener. + * A status code for {@link DrmEventCallback#onDrmPrepared} listener. * <p> * * DRM preparation has succeeded. - * @hide */ public static final int PREPARE_DRM_STATUS_SUCCESS = 0; /** + * A status code for {@link DrmEventCallback#onDrmPrepared} listener. + * <p> + * * The device required DRM provisioning but couldn't reach the provisioning server. - * @hide */ public static final int PREPARE_DRM_STATUS_PROVISIONING_NETWORK_ERROR = 1; /** + * A status code for {@link DrmEventCallback#onDrmPrepared} listener. + * <p> + * * The device required DRM provisioning but the provisioning server denied the request. - * @hide */ public static final int PREPARE_DRM_STATUS_PROVISIONING_SERVER_ERROR = 2; /** + * A status code for {@link DrmEventCallback#onDrmPrepared} listener. + * <p> + * * The DRM preparation has failed . - * @hide */ public static final int PREPARE_DRM_STATUS_PREPARATION_ERROR = 3; /** + * A status code for {@link DrmEventCallback#onDrmPrepared} listener. + * <p> + * * The crypto scheme UUID is not supported by the device. - * @hide */ public static final int PREPARE_DRM_STATUS_UNSUPPORTED_SCHEME = 4; /** + * A status code for {@link DrmEventCallback#onDrmPrepared} listener. + * <p> + * * The hardware resources are not available, due to being in use. - * @hide */ public static final int PREPARE_DRM_STATUS_RESOURCE_BUSY = 5; /** + * A status code for {@link DrmEventCallback#onDrmPrepared} listener. + * <p> + * * Restoring persisted offline keys failed. - * @hide */ public static final int PREPARE_DRM_STATUS_RESTORE_ERROR = 6; /** + * A status code for {@link DrmEventCallback#onDrmPrepared} listener. + * <p> + * * Error during key request/response exchange with license server. - * @hide */ public static final int PREPARE_DRM_STATUS_KEY_EXCHANGE_ERROR = 7; @@ -3758,6 +3772,7 @@ public class MediaPlayer2 implements AutoCloseable * @throws IllegalStateException if called before being prepared * @hide */ + @TestApi public DrmInfo getDrmInfo(@NonNull DataSourceDesc dsd) { final SourceInfo sourceInfo = getSourceInfo(dsd); if (sourceInfo != null) { @@ -3814,6 +3829,7 @@ public class MediaPlayer2 implements AutoCloseable * @hide */ // This is an asynchronous call. + @TestApi public Object prepareDrm(@NonNull DataSourceDesc dsd, @NonNull UUID uuid) { return addTask(newPrepareDrmTask(dsd, uuid)); } @@ -3905,6 +3921,7 @@ public class MediaPlayer2 implements AutoCloseable * @hide */ // This is a synchronous call. + @TestApi public void releaseDrm(@NonNull DataSourceDesc dsd) throws NoDrmSchemeException { final SourceInfo sourceInfo = getSourceInfo(dsd); @@ -3955,6 +3972,7 @@ public class MediaPlayer2 implements AutoCloseable * @throws NoDrmSchemeException if there is no active DRM session * @hide */ + @TestApi public MediaDrm.KeyRequest getDrmKeyRequest( @NonNull DataSourceDesc dsd, @Nullable byte[] keySetId, @Nullable byte[] initData, @@ -3997,6 +4015,7 @@ public class MediaPlayer2 implements AutoCloseable * @hide */ // This is a synchronous call. + @TestApi public byte[] provideDrmKeyResponse( @NonNull DataSourceDesc dsd, @Nullable byte[] keySetId, @NonNull byte[] response) @@ -4023,6 +4042,7 @@ public class MediaPlayer2 implements AutoCloseable * @hide */ // This is a synchronous call. + @TestApi public void restoreDrmKeys( @NonNull DataSourceDesc dsd, @NonNull byte[] keySetId) @@ -4050,6 +4070,7 @@ public class MediaPlayer2 implements AutoCloseable * @throws NoDrmSchemeException if there is no active DRM session * @hide */ + @TestApi public String getDrmPropertyString( @NonNull DataSourceDesc dsd, @NonNull @MediaDrmStringProperty String propertyName) @@ -4078,6 +4099,7 @@ public class MediaPlayer2 implements AutoCloseable * @hide */ // This is a synchronous call. + @TestApi public void setDrmPropertyString( @NonNull DataSourceDesc dsd, @NonNull @MediaDrmStringProperty String propertyName, @NonNull String value) diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java index f756658b4fa8..0c3d6255f871 100644 --- a/media/java/android/media/MediaCodec.java +++ b/media/java/android/media/MediaCodec.java @@ -3314,7 +3314,7 @@ final public class MediaCodec { */ public void setAudioPresentation(@NonNull AudioPresentation presentation) { if (presentation == null) { - throw new IllegalArgumentException("audio presentation is null"); + throw new NullPointerException("audio presentation is null"); } native_setAudioPresentation(presentation.getPresentationId(), presentation.getProgramId()); } diff --git a/media/apex/java/android/media/MediaDescription.aidl b/media/java/android/media/MediaDescription.aidl index 6f934f75aa28..6f934f75aa28 100644 --- a/media/apex/java/android/media/MediaDescription.aidl +++ b/media/java/android/media/MediaDescription.aidl diff --git a/media/apex/java/android/media/MediaDescription.java b/media/java/android/media/MediaDescription.java index 39eeb3eae49f..39eeb3eae49f 100644 --- a/media/apex/java/android/media/MediaDescription.java +++ b/media/java/android/media/MediaDescription.java diff --git a/media/apex/java/android/media/MediaParceledListSlice.aidl b/media/java/android/media/MediaParceledListSlice.aidl index 5c0e5bc84720..5c0e5bc84720 100644 --- a/media/apex/java/android/media/MediaParceledListSlice.aidl +++ b/media/java/android/media/MediaParceledListSlice.aidl diff --git a/media/apex/java/android/media/MediaParceledListSlice.java b/media/java/android/media/MediaParceledListSlice.java index 16a37d99fb86..16a37d99fb86 100644 --- a/media/apex/java/android/media/MediaParceledListSlice.java +++ b/media/java/android/media/MediaParceledListSlice.java diff --git a/media/apex/java/android/media/Rating.aidl b/media/java/android/media/Rating.aidl index 1dc336aeb79d..1dc336aeb79d 100644 --- a/media/apex/java/android/media/Rating.aidl +++ b/media/java/android/media/Rating.aidl diff --git a/media/apex/java/android/media/Rating.java b/media/java/android/media/Rating.java index ffe7e48f25e4..ffe7e48f25e4 100644 --- a/media/apex/java/android/media/Rating.java +++ b/media/java/android/media/Rating.java diff --git a/media/apex/java/android/media/VolumeProvider.java b/media/java/android/media/VolumeProvider.java index 49202eecef19..49202eecef19 100644 --- a/media/apex/java/android/media/VolumeProvider.java +++ b/media/java/android/media/VolumeProvider.java diff --git a/media/apex/java/android/media/browse/MediaBrowser.aidl b/media/java/android/media/browse/MediaBrowser.aidl index 782e09471a56..782e09471a56 100644 --- a/media/apex/java/android/media/browse/MediaBrowser.aidl +++ b/media/java/android/media/browse/MediaBrowser.aidl diff --git a/media/apex/java/android/media/browse/MediaBrowser.java b/media/java/android/media/browse/MediaBrowser.java index 2dffef9fb40a..2dffef9fb40a 100644 --- a/media/apex/java/android/media/browse/MediaBrowser.java +++ b/media/java/android/media/browse/MediaBrowser.java diff --git a/media/apex/java/android/media/browse/MediaBrowserUtils.java b/media/java/android/media/browse/MediaBrowserUtils.java index 19d9f008d3db..19d9f008d3db 100644 --- a/media/apex/java/android/media/browse/MediaBrowserUtils.java +++ b/media/java/android/media/browse/MediaBrowserUtils.java diff --git a/media/apex/java/android/media/session/ControllerCallbackLink.aidl b/media/java/android/media/session/ControllerCallbackLink.aidl index 8ee8c7d00148..8ee8c7d00148 100644 --- a/media/apex/java/android/media/session/ControllerCallbackLink.aidl +++ b/media/java/android/media/session/ControllerCallbackLink.aidl diff --git a/media/apex/java/android/media/session/ControllerCallbackLink.java b/media/java/android/media/session/ControllerCallbackLink.java index adc14a550b7d..adc14a550b7d 100644 --- a/media/apex/java/android/media/session/ControllerCallbackLink.java +++ b/media/java/android/media/session/ControllerCallbackLink.java diff --git a/media/apex/java/android/media/session/ControllerLink.aidl b/media/java/android/media/session/ControllerLink.aidl index 532df59d16cf..532df59d16cf 100644 --- a/media/apex/java/android/media/session/ControllerLink.aidl +++ b/media/java/android/media/session/ControllerLink.aidl diff --git a/media/apex/java/android/media/session/ControllerLink.java b/media/java/android/media/session/ControllerLink.java index f60ec000f2d2..f60ec000f2d2 100644 --- a/media/apex/java/android/media/session/ControllerLink.java +++ b/media/java/android/media/session/ControllerLink.java diff --git a/media/apex/java/android/media/session/ISession.aidl b/media/java/android/media/session/ISession.aidl index 9b1ad7bcf77c..9b1ad7bcf77c 100644 --- a/media/apex/java/android/media/session/ISession.aidl +++ b/media/java/android/media/session/ISession.aidl diff --git a/media/apex/java/android/media/session/ISessionCallback.aidl b/media/java/android/media/session/ISessionCallback.aidl index 9b86bfced340..9b86bfced340 100644 --- a/media/apex/java/android/media/session/ISessionCallback.aidl +++ b/media/java/android/media/session/ISessionCallback.aidl diff --git a/media/apex/java/android/media/session/ISessionController.aidl b/media/java/android/media/session/ISessionController.aidl index e697c65e11c0..e697c65e11c0 100644 --- a/media/apex/java/android/media/session/ISessionController.aidl +++ b/media/java/android/media/session/ISessionController.aidl diff --git a/media/apex/java/android/media/session/ISessionControllerCallback.aidl b/media/java/android/media/session/ISessionControllerCallback.aidl index 56ae852d6f50..56ae852d6f50 100644 --- a/media/apex/java/android/media/session/ISessionControllerCallback.aidl +++ b/media/java/android/media/session/ISessionControllerCallback.aidl diff --git a/media/apex/java/android/media/session/MediaController.aidl b/media/java/android/media/session/MediaController.aidl index 17167f45d0e3..17167f45d0e3 100644 --- a/media/apex/java/android/media/session/MediaController.aidl +++ b/media/java/android/media/session/MediaController.aidl diff --git a/media/apex/java/android/media/session/MediaController.java b/media/java/android/media/session/MediaController.java index 1333ab097219..1333ab097219 100644 --- a/media/apex/java/android/media/session/MediaController.java +++ b/media/java/android/media/session/MediaController.java diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java index ca3346c9a8c4..03627de9343c 100644 --- a/media/java/android/media/session/MediaSession.java +++ b/media/java/android/media/session/MediaSession.java @@ -142,10 +142,9 @@ public final class MediaSession { MediaSessionManager manager = (MediaSessionManager) context .getSystemService(Context.MEDIA_SESSION_SERVICE); try { - MediaSessionEngine.CallbackStub cbStub = new MediaSessionEngine.CallbackStub(); - SessionCallbackLink cbLink = new SessionCallbackLink(context, cbStub); + SessionCallbackLink cbLink = new SessionCallbackLink(context); SessionLink sessionLink = manager.createSession(cbLink, tag); - mImpl = new MediaSessionEngine(context, sessionLink, cbLink, cbStub); + mImpl = new MediaSessionEngine(context, sessionLink, cbLink); mMaxBitmapSize = context.getResources().getDimensionPixelSize( android.R.dimen.config_mediaMetadataBitmapMaxSize); } catch (RuntimeException e) { diff --git a/media/apex/java/android/media/session/MediaSessionEngine.java b/media/java/android/media/session/MediaSessionEngine.java index 31714e1bde7f..7fea90dd0c43 100644 --- a/media/apex/java/android/media/session/MediaSessionEngine.java +++ b/media/java/android/media/session/MediaSessionEngine.java @@ -19,7 +19,6 @@ package android.media.session; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; import android.app.Activity; import android.app.PendingIntent; import android.content.Context; @@ -44,7 +43,6 @@ import android.util.Pair; import android.view.KeyEvent; import android.view.ViewConfiguration; -import java.lang.ref.WeakReference; import java.util.List; import java.util.Objects; @@ -60,10 +58,7 @@ public final class MediaSessionEngine implements AutoCloseable { private final MediaSession.Token mSessionToken; private final MediaController mController; private final SessionLink mSessionLink; - private final SessionCallbackLink mCbLink; - // Do not change the name of mCallbackWrapper. Support lib accesses this by using reflection. - @UnsupportedAppUsage private CallbackMessageHandler mCallbackHandler; private VolumeProvider mVolumeProvider; private PlaybackState mPlaybackState; @@ -78,14 +73,12 @@ public final class MediaSessionEngine implements AutoCloseable { * * @param context The context to use to create the session. * @param sessionLink A session link for the binder of MediaSessionRecord - * @param cbStub A callback link that handles incoming command to {@link MediaSession.Callback}. */ public MediaSessionEngine(@NonNull Context context, @NonNull SessionLink sessionLink, - @NonNull SessionCallbackLink cbLink, @NonNull CallbackStub cbStub) { + @NonNull SessionCallbackLink cbLink) { mSessionLink = sessionLink; - mCbLink = cbLink; - cbStub.setSessionImpl(this); + cbLink.setSessionEngine(this); mSessionToken = new MediaSession.Token(mSessionLink.getController()); mController = new MediaController(context, mSessionToken); } @@ -479,97 +472,97 @@ public final class MediaSessionEngine implements AutoCloseable { } } - private void dispatchPrepare(RemoteUserInfo caller) { + void dispatchPrepare(RemoteUserInfo caller) { postToCallback(caller, CallbackMessageHandler.MSG_PREPARE, null, null); } - private void dispatchPrepareFromMediaId(RemoteUserInfo caller, String mediaId, Bundle extras) { + void dispatchPrepareFromMediaId(RemoteUserInfo caller, String mediaId, Bundle extras) { postToCallback(caller, CallbackMessageHandler.MSG_PREPARE_MEDIA_ID, mediaId, extras); } - private void dispatchPrepareFromSearch(RemoteUserInfo caller, String query, Bundle extras) { + void dispatchPrepareFromSearch(RemoteUserInfo caller, String query, Bundle extras) { postToCallback(caller, CallbackMessageHandler.MSG_PREPARE_SEARCH, query, extras); } - private void dispatchPrepareFromUri(RemoteUserInfo caller, Uri uri, Bundle extras) { + void dispatchPrepareFromUri(RemoteUserInfo caller, Uri uri, Bundle extras) { postToCallback(caller, CallbackMessageHandler.MSG_PREPARE_URI, uri, extras); } - private void dispatchPlay(RemoteUserInfo caller) { + void dispatchPlay(RemoteUserInfo caller) { postToCallback(caller, CallbackMessageHandler.MSG_PLAY, null, null); } - private void dispatchPlayFromMediaId(RemoteUserInfo caller, String mediaId, Bundle extras) { + void dispatchPlayFromMediaId(RemoteUserInfo caller, String mediaId, Bundle extras) { postToCallback(caller, CallbackMessageHandler.MSG_PLAY_MEDIA_ID, mediaId, extras); } - private void dispatchPlayFromSearch(RemoteUserInfo caller, String query, Bundle extras) { + void dispatchPlayFromSearch(RemoteUserInfo caller, String query, Bundle extras) { postToCallback(caller, CallbackMessageHandler.MSG_PLAY_SEARCH, query, extras); } - private void dispatchPlayFromUri(RemoteUserInfo caller, Uri uri, Bundle extras) { + void dispatchPlayFromUri(RemoteUserInfo caller, Uri uri, Bundle extras) { postToCallback(caller, CallbackMessageHandler.MSG_PLAY_URI, uri, extras); } - private void dispatchSkipToItem(RemoteUserInfo caller, long id) { + void dispatchSkipToItem(RemoteUserInfo caller, long id) { postToCallback(caller, CallbackMessageHandler.MSG_SKIP_TO_ITEM, id, null); } - private void dispatchPause(RemoteUserInfo caller) { + void dispatchPause(RemoteUserInfo caller) { postToCallback(caller, CallbackMessageHandler.MSG_PAUSE, null, null); } - private void dispatchStop(RemoteUserInfo caller) { + void dispatchStop(RemoteUserInfo caller) { postToCallback(caller, CallbackMessageHandler.MSG_STOP, null, null); } - private void dispatchNext(RemoteUserInfo caller) { + void dispatchNext(RemoteUserInfo caller) { postToCallback(caller, CallbackMessageHandler.MSG_NEXT, null, null); } - private void dispatchPrevious(RemoteUserInfo caller) { + void dispatchPrevious(RemoteUserInfo caller) { postToCallback(caller, CallbackMessageHandler.MSG_PREVIOUS, null, null); } - private void dispatchFastForward(RemoteUserInfo caller) { + void dispatchFastForward(RemoteUserInfo caller) { postToCallback(caller, CallbackMessageHandler.MSG_FAST_FORWARD, null, null); } - private void dispatchRewind(RemoteUserInfo caller) { + void dispatchRewind(RemoteUserInfo caller) { postToCallback(caller, CallbackMessageHandler.MSG_REWIND, null, null); } - private void dispatchSeekTo(RemoteUserInfo caller, long pos) { + void dispatchSeekTo(RemoteUserInfo caller, long pos) { postToCallback(caller, CallbackMessageHandler.MSG_SEEK_TO, pos, null); } - private void dispatchRate(RemoteUserInfo caller, Rating rating) { + void dispatchRate(RemoteUserInfo caller, Rating rating) { postToCallback(caller, CallbackMessageHandler.MSG_RATE, rating, null); } - private void dispatchCustomAction(RemoteUserInfo caller, String action, Bundle args) { + void dispatchCustomAction(RemoteUserInfo caller, String action, Bundle args) { postToCallback(caller, CallbackMessageHandler.MSG_CUSTOM_ACTION, action, args); } - private void dispatchMediaButton(RemoteUserInfo caller, Intent mediaButtonIntent) { + void dispatchMediaButton(RemoteUserInfo caller, Intent mediaButtonIntent) { postToCallback(caller, CallbackMessageHandler.MSG_MEDIA_BUTTON, mediaButtonIntent, null); } - private void dispatchMediaButtonDelayed(RemoteUserInfo info, Intent mediaButtonIntent, + void dispatchMediaButtonDelayed(RemoteUserInfo info, Intent mediaButtonIntent, long delay) { postToCallbackDelayed(info, CallbackMessageHandler.MSG_PLAY_PAUSE_KEY_DOUBLE_TAP_TIMEOUT, mediaButtonIntent, null, delay); } - private void dispatchAdjustVolume(RemoteUserInfo caller, int direction) { + void dispatchAdjustVolume(RemoteUserInfo caller, int direction) { postToCallback(caller, CallbackMessageHandler.MSG_ADJUST_VOLUME, direction, null); } - private void dispatchSetVolumeTo(RemoteUserInfo caller, int volume) { + void dispatchSetVolumeTo(RemoteUserInfo caller, int volume) { postToCallback(caller, CallbackMessageHandler.MSG_SET_VOLUME, volume, null); } - private void dispatchCommand(RemoteUserInfo caller, String command, Bundle args, + void dispatchCommand(RemoteUserInfo caller, String command, Bundle args, ResultReceiver resultCb) { Command cmd = new Command(command, args, resultCb); postToCallback(caller, CallbackMessageHandler.MSG_COMMAND, cmd, null); @@ -979,259 +972,7 @@ public final class MediaSessionEngine implements AutoCloseable { } } - /** - * @hide - */ - @SystemApi - public static final class CallbackStub extends SessionCallbackLink.CallbackStub { - private WeakReference<MediaSessionEngine> mSessionImpl; - - private static RemoteUserInfo createRemoteUserInfo(String packageName, int pid, int uid) { - return new RemoteUserInfo(packageName, pid, uid); - } - - public CallbackStub() { - } - - @Override - public void onCommand(String packageName, int pid, int uid, - ControllerCallbackLink caller, String command, Bundle args, ResultReceiver cb) { - MediaSessionEngine sessionImpl = mSessionImpl.get(); - if (sessionImpl != null) { - sessionImpl.dispatchCommand(createRemoteUserInfo(packageName, pid, uid), - command, args, cb); - } - } - - @Override - public void onMediaButton(String packageName, int pid, int uid, Intent mediaButtonIntent, - int sequenceNumber, ResultReceiver cb) { - MediaSessionEngine sessionImpl = mSessionImpl.get(); - try { - if (sessionImpl != null) { - sessionImpl.dispatchMediaButton( - createRemoteUserInfo(packageName, pid, uid), mediaButtonIntent); - } - } finally { - if (cb != null) { - cb.send(sequenceNumber, null); - } - } - } - - @Override - public void onMediaButtonFromController(String packageName, int pid, int uid, - ControllerCallbackLink caller, Intent mediaButtonIntent) { - MediaSessionEngine sessionImpl = mSessionImpl.get(); - if (sessionImpl != null) { - sessionImpl.dispatchMediaButton(createRemoteUserInfo(packageName, pid, uid), - mediaButtonIntent); - } - } - - @Override - public void onPrepare(String packageName, int pid, int uid, - ControllerCallbackLink caller) { - MediaSessionEngine sessionImpl = mSessionImpl.get(); - if (sessionImpl != null) { - sessionImpl.dispatchPrepare(createRemoteUserInfo(packageName, pid, uid)); - } - } - - @Override - public void onPrepareFromMediaId(String packageName, int pid, int uid, - ControllerCallbackLink caller, String mediaId, - Bundle extras) { - MediaSessionEngine sessionImpl = mSessionImpl.get(); - if (sessionImpl != null) { - sessionImpl.dispatchPrepareFromMediaId( - createRemoteUserInfo(packageName, pid, uid), mediaId, extras); - } - } - - @Override - public void onPrepareFromSearch(String packageName, int pid, int uid, - ControllerCallbackLink caller, String query, - Bundle extras) { - MediaSessionEngine sessionImpl = mSessionImpl.get(); - if (sessionImpl != null) { - sessionImpl.dispatchPrepareFromSearch( - createRemoteUserInfo(packageName, pid, uid), query, extras); - } - } - - @Override - public void onPrepareFromUri(String packageName, int pid, int uid, - ControllerCallbackLink caller, Uri uri, Bundle extras) { - MediaSessionEngine sessionImpl = mSessionImpl.get(); - if (sessionImpl != null) { - sessionImpl.dispatchPrepareFromUri( - createRemoteUserInfo(packageName, pid, uid), uri, extras); - } - } - - @Override - public void onPlay(String packageName, int pid, int uid, - ControllerCallbackLink caller) { - MediaSessionEngine sessionImpl = mSessionImpl.get(); - if (sessionImpl != null) { - sessionImpl.dispatchPlay(createRemoteUserInfo(packageName, pid, uid)); - } - } - - @Override - public void onPlayFromMediaId(String packageName, int pid, int uid, - ControllerCallbackLink caller, String mediaId, - Bundle extras) { - MediaSessionEngine sessionImpl = mSessionImpl.get(); - if (sessionImpl != null) { - sessionImpl.dispatchPlayFromMediaId( - createRemoteUserInfo(packageName, pid, uid), mediaId, extras); - } - } - - @Override - public void onPlayFromSearch(String packageName, int pid, int uid, - ControllerCallbackLink caller, String query, - Bundle extras) { - MediaSessionEngine sessionImpl = mSessionImpl.get(); - if (sessionImpl != null) { - sessionImpl.dispatchPlayFromSearch( - createRemoteUserInfo(packageName, pid, uid), query, extras); - } - } - - @Override - public void onPlayFromUri(String packageName, int pid, int uid, - ControllerCallbackLink caller, Uri uri, Bundle extras) { - MediaSessionEngine sessionImpl = mSessionImpl.get(); - if (sessionImpl != null) { - sessionImpl.dispatchPlayFromUri( - createRemoteUserInfo(packageName, pid, uid), uri, extras); - } - } - - @Override - public void onSkipToTrack(String packageName, int pid, int uid, - ControllerCallbackLink caller, long id) { - MediaSessionEngine sessionImpl = mSessionImpl.get(); - if (sessionImpl != null) { - sessionImpl.dispatchSkipToItem( - createRemoteUserInfo(packageName, pid, uid), id); - } - } - - @Override - public void onPause(String packageName, int pid, int uid, - ControllerCallbackLink caller) { - MediaSessionEngine sessionImpl = mSessionImpl.get(); - if (sessionImpl != null) { - sessionImpl.dispatchPause(createRemoteUserInfo(packageName, pid, uid)); - } - } - - @Override - public void onStop(String packageName, int pid, int uid, - ControllerCallbackLink caller) { - MediaSessionEngine sessionImpl = mSessionImpl.get(); - if (sessionImpl != null) { - sessionImpl.dispatchStop(createRemoteUserInfo(packageName, pid, uid)); - } - } - - @Override - public void onNext(String packageName, int pid, int uid, - ControllerCallbackLink caller) { - MediaSessionEngine sessionImpl = mSessionImpl.get(); - if (sessionImpl != null) { - sessionImpl.dispatchNext(createRemoteUserInfo(packageName, pid, uid)); - } - } - - @Override - public void onPrevious(String packageName, int pid, int uid, - ControllerCallbackLink caller) { - MediaSessionEngine sessionImpl = mSessionImpl.get(); - if (sessionImpl != null) { - sessionImpl.dispatchPrevious(createRemoteUserInfo(packageName, pid, uid)); - } - } - - @Override - public void onFastForward(String packageName, int pid, int uid, - ControllerCallbackLink caller) { - MediaSessionEngine sessionImpl = mSessionImpl.get(); - if (sessionImpl != null) { - sessionImpl.dispatchFastForward( - createRemoteUserInfo(packageName, pid, uid)); - } - } - - @Override - public void onRewind(String packageName, int pid, int uid, - ControllerCallbackLink caller) { - MediaSessionEngine sessionImpl = mSessionImpl.get(); - if (sessionImpl != null) { - sessionImpl.dispatchRewind(createRemoteUserInfo(packageName, pid, uid)); - } - } - - @Override - public void onSeekTo(String packageName, int pid, int uid, - ControllerCallbackLink caller, long pos) { - MediaSessionEngine sessionImpl = mSessionImpl.get(); - if (sessionImpl != null) { - sessionImpl.dispatchSeekTo( - createRemoteUserInfo(packageName, pid, uid), pos); - } - } - - @Override - public void onRate(String packageName, int pid, int uid, ControllerCallbackLink caller, - Rating rating) { - MediaSessionEngine sessionImpl = mSessionImpl.get(); - if (sessionImpl != null) { - sessionImpl.dispatchRate( - createRemoteUserInfo(packageName, pid, uid), rating); - } - } - - @Override - public void onCustomAction(String packageName, int pid, int uid, - ControllerCallbackLink caller, String action, Bundle args) { - MediaSessionEngine sessionImpl = mSessionImpl.get(); - if (sessionImpl != null) { - sessionImpl.dispatchCustomAction( - createRemoteUserInfo(packageName, pid, uid), action, args); - } - } - - @Override - public void onAdjustVolume(String packageName, int pid, int uid, - ControllerCallbackLink caller, int direction) { - MediaSessionEngine sessionImpl = mSessionImpl.get(); - if (sessionImpl != null) { - sessionImpl.dispatchAdjustVolume( - createRemoteUserInfo(packageName, pid, uid), direction); - } - } - - @Override - public void onSetVolumeTo(String packageName, int pid, int uid, - ControllerCallbackLink caller, int value) { - MediaSessionEngine sessionImpl = mSessionImpl.get(); - if (sessionImpl != null) { - sessionImpl.dispatchSetVolumeTo( - createRemoteUserInfo(packageName, pid, uid), value); - } - } - - void setSessionImpl(MediaSessionEngine sessionImpl) { - mSessionImpl = new WeakReference<>(sessionImpl); - } - } - - /** + /** * A single item that is part of the play queue. It contains a description * of the item and its id in the queue. */ diff --git a/media/apex/java/android/media/session/MediaSessionProviderService.java b/media/java/android/media/session/MediaSessionProviderService.java index 9a346ff4a12e..9a346ff4a12e 100644 --- a/media/apex/java/android/media/session/MediaSessionProviderService.java +++ b/media/java/android/media/session/MediaSessionProviderService.java diff --git a/media/apex/java/android/media/session/PlaybackState.aidl b/media/java/android/media/session/PlaybackState.aidl index 0876ebd2d4d2..0876ebd2d4d2 100644 --- a/media/apex/java/android/media/session/PlaybackState.aidl +++ b/media/java/android/media/session/PlaybackState.aidl diff --git a/media/apex/java/android/media/session/PlaybackState.java b/media/java/android/media/session/PlaybackState.java index 6b28c976c710..6b28c976c710 100644 --- a/media/apex/java/android/media/session/PlaybackState.java +++ b/media/java/android/media/session/PlaybackState.java diff --git a/media/apex/java/android/media/session/SessionCallbackLink.aidl b/media/java/android/media/session/SessionCallbackLink.aidl index c489e5bee6e2..c489e5bee6e2 100644 --- a/media/apex/java/android/media/session/SessionCallbackLink.aidl +++ b/media/java/android/media/session/SessionCallbackLink.aidl diff --git a/media/apex/java/android/media/session/SessionCallbackLink.java b/media/java/android/media/session/SessionCallbackLink.java index 3bcb65c42010..4c2918a0fa94 100644 --- a/media/apex/java/android/media/session/SessionCallbackLink.java +++ b/media/java/android/media/session/SessionCallbackLink.java @@ -25,6 +25,7 @@ import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.media.Rating; +import android.media.session.MediaSessionManager.RemoteUserInfo; import android.net.Uri; import android.os.Binder; import android.os.Bundle; @@ -35,6 +36,8 @@ import android.os.Process; import android.os.RemoteException; import android.os.ResultReceiver; +import java.lang.ref.WeakReference; + /** * Handles incoming commands to {@link MediaSession.Callback}. * @hide @@ -42,16 +45,15 @@ import android.os.ResultReceiver; @SystemApi public final class SessionCallbackLink implements Parcelable { final Context mContext; - final CallbackStub mCallbackStub; final ISessionCallback mISessionCallback; /** * Constructor for stub (Callee) + * @hide */ - SessionCallbackLink(@NonNull Context context, @NonNull CallbackStub callbackStub) { + public SessionCallbackLink(@NonNull Context context) { mContext = context; - mCallbackStub = callbackStub; - mISessionCallback = new CallbackStubProxy(); + mISessionCallback = new CallbackStub(); } /** @@ -59,11 +61,19 @@ public final class SessionCallbackLink implements Parcelable { */ public SessionCallbackLink(IBinder binder) { mContext = null; - mCallbackStub = null; mISessionCallback = ISessionCallback.Stub.asInterface(binder); } /** + * Set {@link MediaSessionEngine} which will be used by {@link CallbackStub}. + */ + void setSessionEngine(@Nullable MediaSessionEngine sessionImpl) { + if (mISessionCallback instanceof CallbackStub) { + ((CallbackStub) mISessionCallback).mSessionImpl = new WeakReference<>(sessionImpl); + } + } + + /** * Notify session that a controller sends a command. * * @param packageName the package name of the controller @@ -540,139 +550,24 @@ public final class SessionCallbackLink implements Parcelable { } }; - /** - * Class for Stub implementation - */ - abstract static class CallbackStub { - /** Stub method for ISessionCallback.notifyCommand */ - public void onCommand(@NonNull String packageName, int pid, int uid, - @NonNull ControllerCallbackLink caller, @NonNull String command, - @Nullable Bundle args, @Nullable ResultReceiver cb) { - } - - /** Stub method for ISessionCallback.notifyMediaButton */ - public void onMediaButton(@NonNull String packageName, int pid, int uid, - @NonNull Intent mediaButtonIntent, int sequenceNumber, - @Nullable ResultReceiver cb) { - } - - /** Stub method for ISessionCallback.notifyMediaButtonFromController */ - public void onMediaButtonFromController(@NonNull String packageName, int pid, int uid, - @NonNull ControllerCallbackLink caller, @NonNull Intent mediaButtonIntent) { - } - - /** Stub method for ISessionCallback.notifyPrepare */ - public void onPrepare(@NonNull String packageName, int pid, int uid, - @NonNull ControllerCallbackLink caller) { - } - - /** Stub method for ISessionCallback.notifyPrepareFromMediaId */ - public void onPrepareFromMediaId(@NonNull String packageName, int pid, int uid, - @NonNull ControllerCallbackLink caller, @NonNull String mediaId, - @Nullable Bundle extras) { - } - - /** Stub method for ISessionCallback.notifyPrepareFromSearch */ - public void onPrepareFromSearch(@NonNull String packageName, int pid, int uid, - @NonNull ControllerCallbackLink caller, String query, @Nullable Bundle extras) { - } - - /** Stub method for ISessionCallback.notifyPrepareFromUri */ - public void onPrepareFromUri(@NonNull String packageName, int pid, int uid, - @NonNull ControllerCallbackLink caller, @NonNull Uri uri, @Nullable Bundle extras) { - } - - /** Stub method for ISessionCallback.notifyPlay */ - public void onPlay(@NonNull String packageName, int pid, int uid, - @NonNull ControllerCallbackLink caller) { - } - - /** Stub method for ISessionCallback.notifyPlayFromMediaId */ - public void onPlayFromMediaId(@NonNull String packageName, int pid, int uid, - @NonNull ControllerCallbackLink caller, @NonNull String mediaId, - @Nullable Bundle extras) { - } - - /** Stub method for ISessionCallback.notifyPlayFromSearch */ - public void onPlayFromSearch(@NonNull String packageName, int pid, int uid, - @NonNull ControllerCallbackLink caller, String query, @Nullable Bundle extras) { - } - - /** Stub method for ISessionCallback.notifyPlayFromUri */ - public void onPlayFromUri(@NonNull String packageName, int pid, int uid, - @NonNull ControllerCallbackLink caller, @NonNull Uri uri, @Nullable Bundle extras) { - } - - /** Stub method for ISessionCallback.notifySkipToTrack */ - public void onSkipToTrack(@NonNull String packageName, int pid, int uid, - @NonNull ControllerCallbackLink caller, long id) { - } - - /** Stub method for ISessionCallback.notifyPause */ - public void onPause(@NonNull String packageName, int pid, int uid, - @NonNull ControllerCallbackLink caller) { - } - - /** Stub method for ISessionCallback.notifyStop */ - public void onStop(@NonNull String packageName, int pid, int uid, - @NonNull ControllerCallbackLink caller) { - } - - /** Stub method for ISessionCallback.notifyNext */ - public void onNext(@NonNull String packageName, int pid, int uid, - @NonNull ControllerCallbackLink caller) { - } - - /** Stub method for ISessionCallback.notifyPrevious */ - public void onPrevious(@NonNull String packageName, int pid, int uid, - @NonNull ControllerCallbackLink caller) { - } - - /** Stub method for ISessionCallback.notifyFastForward */ - public void onFastForward(@NonNull String packageName, int pid, int uid, - @NonNull ControllerCallbackLink caller) { - } - - /** Stub method for ISessionCallback.notifyRewind */ - public void onRewind(@NonNull String packageName, int pid, int uid, - @NonNull ControllerCallbackLink caller) { - } + private class CallbackStub extends ISessionCallback.Stub { + private WeakReference<MediaSessionEngine> mSessionImpl; - /** Stub method for ISessionCallback.notifySeekTo */ - public void onSeekTo(@NonNull String packageName, int pid, int uid, - @NonNull ControllerCallbackLink caller, long pos) { + private RemoteUserInfo createRemoteUserInfo(String packageName, int pid, int uid) { + return new RemoteUserInfo(packageName, pid, uid); } - /** Stub method for ISessionCallback.notifyRate */ - public void onRate(@NonNull String packageName, int pid, int uid, - @NonNull ControllerCallbackLink caller, @NonNull Rating rating) { - } - - /** Stub method for ISessionCallback.notifyCustomAction */ - public void onCustomAction(@NonNull String packageName, int pid, int uid, - @NonNull ControllerCallbackLink caller, @NonNull String action, - @Nullable Bundle args) { - } - - /** Stub method for ISessionCallback.notifyAdjustVolume */ - public void onAdjustVolume(@NonNull String packageName, int pid, int uid, - @NonNull ControllerCallbackLink caller, int direction) { - } - - /** Stub method for ISessionCallback.notifySetVolumeTo */ - public void onSetVolumeTo(@NonNull String packageName, int pid, int uid, - @NonNull ControllerCallbackLink caller, int value) { - } - } - - private class CallbackStubProxy extends ISessionCallback.Stub { @Override public void notifyCommand(String packageName, int pid, int uid, ControllerCallbackLink caller, String command, Bundle args, ResultReceiver cb) { ensureMediaControlPermission(); final long token = Binder.clearCallingIdentity(); try { - mCallbackStub.onCommand(packageName, pid, uid, caller, command, args, cb); + MediaSessionEngine sessionImpl = mSessionImpl.get(); + if (sessionImpl != null) { + sessionImpl.dispatchCommand(createRemoteUserInfo(packageName, pid, uid), + command, args, cb); + } } finally { Binder.restoreCallingIdentity(token); } @@ -684,9 +579,15 @@ public final class SessionCallbackLink implements Parcelable { ensureMediaControlPermission(); final long token = Binder.clearCallingIdentity(); try { - mCallbackStub.onMediaButton(packageName, pid, uid, mediaButtonIntent, - sequenceNumber, cb); + MediaSessionEngine sessionImpl = mSessionImpl.get(); + if (sessionImpl != null) { + sessionImpl.dispatchMediaButton( + createRemoteUserInfo(packageName, pid, uid), mediaButtonIntent); + } } finally { + if (cb != null) { + cb.send(sequenceNumber, null); + } Binder.restoreCallingIdentity(token); } } @@ -697,8 +598,11 @@ public final class SessionCallbackLink implements Parcelable { ensureMediaControlPermission(); final long token = Binder.clearCallingIdentity(); try { - mCallbackStub.onMediaButtonFromController(packageName, pid, uid, caller, - mediaButtonIntent); + MediaSessionEngine sessionImpl = mSessionImpl.get(); + if (sessionImpl != null) { + sessionImpl.dispatchMediaButton(createRemoteUserInfo(packageName, pid, uid), + mediaButtonIntent); + } } finally { Binder.restoreCallingIdentity(token); } @@ -710,7 +614,10 @@ public final class SessionCallbackLink implements Parcelable { ensureMediaControlPermission(); final long token = Binder.clearCallingIdentity(); try { - mCallbackStub.onPrepare(packageName, pid, uid, caller); + MediaSessionEngine sessionImpl = mSessionImpl.get(); + if (sessionImpl != null) { + sessionImpl.dispatchPrepare(createRemoteUserInfo(packageName, pid, uid)); + } } finally { Binder.restoreCallingIdentity(token); } @@ -722,7 +629,11 @@ public final class SessionCallbackLink implements Parcelable { ensureMediaControlPermission(); final long token = Binder.clearCallingIdentity(); try { - mCallbackStub.onPrepareFromMediaId(packageName, pid, uid, caller, mediaId, extras); + MediaSessionEngine sessionImpl = mSessionImpl.get(); + if (sessionImpl != null) { + sessionImpl.dispatchPrepareFromMediaId( + createRemoteUserInfo(packageName, pid, uid), mediaId, extras); + } } finally { Binder.restoreCallingIdentity(token); } @@ -734,7 +645,11 @@ public final class SessionCallbackLink implements Parcelable { ensureMediaControlPermission(); final long token = Binder.clearCallingIdentity(); try { - mCallbackStub.onPrepareFromSearch(packageName, pid, uid, caller, query, extras); + MediaSessionEngine sessionImpl = mSessionImpl.get(); + if (sessionImpl != null) { + sessionImpl.dispatchPrepareFromSearch( + createRemoteUserInfo(packageName, pid, uid), query, extras); + } } finally { Binder.restoreCallingIdentity(token); } @@ -746,7 +661,11 @@ public final class SessionCallbackLink implements Parcelable { ensureMediaControlPermission(); final long token = Binder.clearCallingIdentity(); try { - mCallbackStub.onPrepareFromUri(packageName, pid, uid, caller, uri, extras); + MediaSessionEngine sessionImpl = mSessionImpl.get(); + if (sessionImpl != null) { + sessionImpl.dispatchPrepareFromUri( + createRemoteUserInfo(packageName, pid, uid), uri, extras); + } } finally { Binder.restoreCallingIdentity(token); } @@ -758,7 +677,10 @@ public final class SessionCallbackLink implements Parcelable { ensureMediaControlPermission(); final long token = Binder.clearCallingIdentity(); try { - mCallbackStub.onPlay(packageName, pid, uid, caller); + MediaSessionEngine sessionImpl = mSessionImpl.get(); + if (sessionImpl != null) { + sessionImpl.dispatchPlay(createRemoteUserInfo(packageName, pid, uid)); + } } finally { Binder.restoreCallingIdentity(token); } @@ -770,7 +692,11 @@ public final class SessionCallbackLink implements Parcelable { ensureMediaControlPermission(); final long token = Binder.clearCallingIdentity(); try { - mCallbackStub.onPlayFromMediaId(packageName, pid, uid, caller, mediaId, extras); + MediaSessionEngine sessionImpl = mSessionImpl.get(); + if (sessionImpl != null) { + sessionImpl.dispatchPlayFromMediaId( + createRemoteUserInfo(packageName, pid, uid), mediaId, extras); + } } finally { Binder.restoreCallingIdentity(token); } @@ -782,7 +708,11 @@ public final class SessionCallbackLink implements Parcelable { ensureMediaControlPermission(); final long token = Binder.clearCallingIdentity(); try { - mCallbackStub.onPlayFromSearch(packageName, pid, uid, caller, query, extras); + MediaSessionEngine sessionImpl = mSessionImpl.get(); + if (sessionImpl != null) { + sessionImpl.dispatchPlayFromSearch( + createRemoteUserInfo(packageName, pid, uid), query, extras); + } } finally { Binder.restoreCallingIdentity(token); } @@ -794,7 +724,11 @@ public final class SessionCallbackLink implements Parcelable { ensureMediaControlPermission(); final long token = Binder.clearCallingIdentity(); try { - mCallbackStub.onPlayFromUri(packageName, pid, uid, caller, uri, extras); + MediaSessionEngine sessionImpl = mSessionImpl.get(); + if (sessionImpl != null) { + sessionImpl.dispatchPlayFromUri( + createRemoteUserInfo(packageName, pid, uid), uri, extras); + } } finally { Binder.restoreCallingIdentity(token); } @@ -806,7 +740,11 @@ public final class SessionCallbackLink implements Parcelable { ensureMediaControlPermission(); final long token = Binder.clearCallingIdentity(); try { - mCallbackStub.onSkipToTrack(packageName, pid, uid, caller, id); + MediaSessionEngine sessionImpl = mSessionImpl.get(); + if (sessionImpl != null) { + sessionImpl.dispatchSkipToItem( + createRemoteUserInfo(packageName, pid, uid), id); + } } finally { Binder.restoreCallingIdentity(token); } @@ -818,7 +756,10 @@ public final class SessionCallbackLink implements Parcelable { ensureMediaControlPermission(); final long token = Binder.clearCallingIdentity(); try { - mCallbackStub.onPause(packageName, pid, uid, caller); + MediaSessionEngine sessionImpl = mSessionImpl.get(); + if (sessionImpl != null) { + sessionImpl.dispatchPause(createRemoteUserInfo(packageName, pid, uid)); + } } finally { Binder.restoreCallingIdentity(token); } @@ -830,7 +771,10 @@ public final class SessionCallbackLink implements Parcelable { ensureMediaControlPermission(); final long token = Binder.clearCallingIdentity(); try { - mCallbackStub.onStop(packageName, pid, uid, caller); + MediaSessionEngine sessionImpl = mSessionImpl.get(); + if (sessionImpl != null) { + sessionImpl.dispatchStop(createRemoteUserInfo(packageName, pid, uid)); + } } finally { Binder.restoreCallingIdentity(token); } @@ -842,7 +786,10 @@ public final class SessionCallbackLink implements Parcelable { ensureMediaControlPermission(); final long token = Binder.clearCallingIdentity(); try { - mCallbackStub.onNext(packageName, pid, uid, caller); + MediaSessionEngine sessionImpl = mSessionImpl.get(); + if (sessionImpl != null) { + sessionImpl.dispatchNext(createRemoteUserInfo(packageName, pid, uid)); + } } finally { Binder.restoreCallingIdentity(token); } @@ -854,7 +801,10 @@ public final class SessionCallbackLink implements Parcelable { ensureMediaControlPermission(); final long token = Binder.clearCallingIdentity(); try { - mCallbackStub.onPrevious(packageName, pid, uid, caller); + MediaSessionEngine sessionImpl = mSessionImpl.get(); + if (sessionImpl != null) { + sessionImpl.dispatchPrevious(createRemoteUserInfo(packageName, pid, uid)); + } } finally { Binder.restoreCallingIdentity(token); } @@ -866,7 +816,11 @@ public final class SessionCallbackLink implements Parcelable { ensureMediaControlPermission(); final long token = Binder.clearCallingIdentity(); try { - mCallbackStub.onFastForward(packageName, pid, uid, caller); + MediaSessionEngine sessionImpl = mSessionImpl.get(); + if (sessionImpl != null) { + sessionImpl.dispatchFastForward( + createRemoteUserInfo(packageName, pid, uid)); + } } finally { Binder.restoreCallingIdentity(token); } @@ -878,7 +832,10 @@ public final class SessionCallbackLink implements Parcelable { ensureMediaControlPermission(); final long token = Binder.clearCallingIdentity(); try { - mCallbackStub.onRewind(packageName, pid, uid, caller); + MediaSessionEngine sessionImpl = mSessionImpl.get(); + if (sessionImpl != null) { + sessionImpl.dispatchRewind(createRemoteUserInfo(packageName, pid, uid)); + } } finally { Binder.restoreCallingIdentity(token); } @@ -890,7 +847,11 @@ public final class SessionCallbackLink implements Parcelable { ensureMediaControlPermission(); final long token = Binder.clearCallingIdentity(); try { - mCallbackStub.onSeekTo(packageName, pid, uid, caller, pos); + MediaSessionEngine sessionImpl = mSessionImpl.get(); + if (sessionImpl != null) { + sessionImpl.dispatchSeekTo( + createRemoteUserInfo(packageName, pid, uid), pos); + } } finally { Binder.restoreCallingIdentity(token); } @@ -902,7 +863,11 @@ public final class SessionCallbackLink implements Parcelable { ensureMediaControlPermission(); final long token = Binder.clearCallingIdentity(); try { - mCallbackStub.onRate(packageName, pid, uid, caller, rating); + MediaSessionEngine sessionImpl = mSessionImpl.get(); + if (sessionImpl != null) { + sessionImpl.dispatchRate( + createRemoteUserInfo(packageName, pid, uid), rating); + } } finally { Binder.restoreCallingIdentity(token); } @@ -913,7 +878,11 @@ public final class SessionCallbackLink implements Parcelable { ensureMediaControlPermission(); final long token = Binder.clearCallingIdentity(); try { - mCallbackStub.onCustomAction(packageName, pid, uid, caller, action, args); + MediaSessionEngine sessionImpl = mSessionImpl.get(); + if (sessionImpl != null) { + sessionImpl.dispatchCustomAction( + createRemoteUserInfo(packageName, pid, uid), action, args); + } } finally { Binder.restoreCallingIdentity(token); } @@ -925,7 +894,11 @@ public final class SessionCallbackLink implements Parcelable { ensureMediaControlPermission(); final long token = Binder.clearCallingIdentity(); try { - mCallbackStub.onAdjustVolume(packageName, pid, uid, caller, direction); + MediaSessionEngine sessionImpl = mSessionImpl.get(); + if (sessionImpl != null) { + sessionImpl.dispatchAdjustVolume( + createRemoteUserInfo(packageName, pid, uid), direction); + } } finally { Binder.restoreCallingIdentity(token); } @@ -937,7 +910,11 @@ public final class SessionCallbackLink implements Parcelable { ensureMediaControlPermission(); final long token = Binder.clearCallingIdentity(); try { - mCallbackStub.onSetVolumeTo(packageName, pid, uid, caller, value); + MediaSessionEngine sessionImpl = mSessionImpl.get(); + if (sessionImpl != null) { + sessionImpl.dispatchSetVolumeTo( + createRemoteUserInfo(packageName, pid, uid), value); + } } finally { Binder.restoreCallingIdentity(token); } diff --git a/media/apex/java/android/media/session/SessionLink.aidl b/media/java/android/media/session/SessionLink.aidl index c3be23e8f6b7..c3be23e8f6b7 100644 --- a/media/apex/java/android/media/session/SessionLink.aidl +++ b/media/java/android/media/session/SessionLink.aidl diff --git a/media/apex/java/android/media/session/SessionLink.java b/media/java/android/media/session/SessionLink.java index 4ea762367010..4ea762367010 100644 --- a/media/apex/java/android/media/session/SessionLink.java +++ b/media/java/android/media/session/SessionLink.java diff --git a/media/apex/java/android/service/media/IMediaBrowserService.aidl b/media/java/android/service/media/IMediaBrowserService.aidl index 1c50ec7ac421..1c50ec7ac421 100644 --- a/media/apex/java/android/service/media/IMediaBrowserService.aidl +++ b/media/java/android/service/media/IMediaBrowserService.aidl diff --git a/media/apex/java/android/service/media/IMediaBrowserServiceCallbacks.aidl b/media/java/android/service/media/IMediaBrowserServiceCallbacks.aidl index 507a8f72ea57..507a8f72ea57 100644 --- a/media/apex/java/android/service/media/IMediaBrowserServiceCallbacks.aidl +++ b/media/java/android/service/media/IMediaBrowserServiceCallbacks.aidl diff --git a/media/apex/java/android/service/media/MediaBrowserService.java b/media/java/android/service/media/MediaBrowserService.java index d9ef6ae40dfb..d9ef6ae40dfb 100644 --- a/media/apex/java/android/service/media/MediaBrowserService.java +++ b/media/java/android/service/media/MediaBrowserService.java diff --git a/native/webview/plat_support/draw_functor.cpp b/native/webview/plat_support/draw_functor.cpp index 6deb47f09347..e43a60c3f396 100644 --- a/native/webview/plat_support/draw_functor.cpp +++ b/native/webview/plat_support/draw_functor.cpp @@ -177,9 +177,6 @@ int CreateFunctor(void* data, AwDrawFnFunctorCallbacks* functor_callbacks) { webview_functor_callbacks.vk.initialize = &initializeVk; webview_functor_callbacks.vk.draw = &drawVk; webview_functor_callbacks.vk.postDraw = &postDrawVk; - // TODO(boliu): Remove this once SkiaRecordingCanvas::drawWebViewFunctor - // no longer uses GL interop. - webview_functor_callbacks.gles.draw = &draw_gl; break; } callbacks_initialized = true; diff --git a/packages/CarSystemUI/res/values/integers_car.xml b/packages/CarSystemUI/res/values/integers_car.xml index 777283d6bf92..be2cb0d8d900 100644 --- a/packages/CarSystemUI/res/values/integers_car.xml +++ b/packages/CarSystemUI/res/values/integers_car.xml @@ -23,7 +23,7 @@ <!-- Number of milliseconds user can spend driving with the keyguard up. After that, we switch to Guest. --> <!-- If the number is negative, the feature is disabled. If it's zero, we switch to guest immediately as we start driving. --> - <integer name="driving_on_keyguard_timeout_ms">30000</integer> + <integer name="driving_on_keyguard_timeout_ms">-1</integer> <!--Percentage of the screen height, from the bottom, that a notification panel being partially closed at will result in it remaining open if released--> diff --git a/packages/SettingsLib/OWNERS b/packages/SettingsLib/OWNERS index d188c65be883..d87908738b56 100644 --- a/packages/SettingsLib/OWNERS +++ b/packages/SettingsLib/OWNERS @@ -4,7 +4,7 @@ asargent@google.com dehboxturtle@google.com dhnishi@google.com dling@google.com -dsandler@google.com +dsandler@android.com evanlaird@google.com jackqdyulei@google.com jmonk@google.com diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java index 445312168eba..23e5f0eea46d 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java @@ -4231,7 +4231,7 @@ public class SettingsProvider extends ContentProvider { String defLocationMode = Integer.toString( !TextUtils.isEmpty(locationProvidersAllowed.getValue()) - ? Secure.LOCATION_MODE_HIGH_ACCURACY + ? Secure.LOCATION_MODE_ON : Secure.LOCATION_MODE_OFF); secureSettings.insertSettingLocked( Secure.LOCATION_MODE, defLocationMode, diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml index c3c3f25a9f03..c03268381367 100644 --- a/packages/Shell/AndroidManifest.xml +++ b/packages/Shell/AndroidManifest.xml @@ -145,6 +145,7 @@ <uses-permission android:name="android.permission.SET_TIME_ZONE" /> <uses-permission android:name="android.permission.DISABLE_HIDDEN_API_CHECKS" /> <uses-permission android:name="android.permission.MANAGE_ROLE_HOLDERS" /> + <uses-permission android:name="android.permission.STATUS_BAR_SERVICE" /> <!-- Permission needed to rename bugreport notifications (so they're not shown as Shell) --> <uses-permission android:name="android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME" /> <!-- Permission needed to hold a wakelock in dumpstate.cpp (drop_root_user()) --> diff --git a/packages/SystemUI/OWNERS b/packages/SystemUI/OWNERS index 2f6e32b2c6d2..e7e2c1aafa78 100644 --- a/packages/SystemUI/OWNERS +++ b/packages/SystemUI/OWNERS @@ -1,6 +1,6 @@ set noparent -dsandler@google.com +dsandler@android.com adamcohen@google.com asc@google.com diff --git a/packages/SystemUI/res-keyguard/values/strings.xml b/packages/SystemUI/res-keyguard/values/strings.xml index 7432f9cde639..41acf82a4567 100644 --- a/packages/SystemUI/res-keyguard/values/strings.xml +++ b/packages/SystemUI/res-keyguard/values/strings.xml @@ -405,7 +405,7 @@ number">%d</xliff:g> remaining attempts before SIM becomes permanently unusable. <!-- Header for typographic clock face. [CHAR LIMIT=8] --> <string name="type_clock_header">It\u2019s</string> - <!-- Hour displayed in words on the typographic clock face. [CHAR LIMIT=8] --> + <!-- Hour displayed in words on the typographic clock face. [CHAR LIMIT=12] --> <string-array name="type_clock_hours"> <item>Twelve</item> <item>One</item> @@ -421,7 +421,7 @@ number">%d</xliff:g> remaining attempts before SIM becomes permanently unusable. <item>Eleven</item> </string-array> - <!-- Minutes displayed in words on the typographic clock face. [CHAR LIMIT=16] --> + <!-- Minutes displayed in words on the typographic clock face. [CHAR LIMIT=20] --> <string-array name="type_clock_minutes"> <item>O\u2019Clock</item> <item>O\u2019One</item> diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedViewContainer.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedViewContainer.java index 71ae1f8620f6..231e725057d0 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedViewContainer.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedViewContainer.java @@ -19,6 +19,7 @@ package com.android.systemui.bubbles; import android.annotation.Nullable; import android.content.Context; import android.content.res.Resources; +import android.content.res.TypedArray; import android.graphics.Color; import android.graphics.drawable.ShapeDrawable; import android.text.TextUtils; @@ -68,9 +69,15 @@ public class BubbleExpandedViewContainer extends LinearLayout { mPointerView = findViewById(R.id.pointer_view); int width = res.getDimensionPixelSize(R.dimen.bubble_pointer_width); int height = res.getDimensionPixelSize(R.dimen.bubble_pointer_height); + + TypedArray ta = getContext().obtainStyledAttributes( + new int[] {android.R.attr.colorBackgroundFloating}); + int bgColor = ta.getColor(0, Color.WHITE); + ta.recycle(); + ShapeDrawable triangleDrawable = new ShapeDrawable( TriangleShape.create(width, height, true /* pointUp */)); - triangleDrawable.setTint(Color.WHITE); // TODO: dark mode + triangleDrawable.setTint(bgColor); mPointerView.setBackground(triangleDrawable); mHeaderView = findViewById(R.id.bubble_content_header); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java index cb1384cacec8..aa221993cd82 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java @@ -25,7 +25,6 @@ import android.app.NotificationChannel; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; -import android.metrics.LogMaker; import android.net.Uri; import android.os.ServiceManager; import android.os.UserHandle; @@ -392,12 +391,6 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx return false; } - LogMaker logMaker = (row.getStatusBarNotification() == null) - ? new LogMaker(MetricsProto.MetricsEvent.ACTION_NOTE_CONTROLS) - : row.getStatusBarNotification().getLogMaker(); - mMetricsLogger.write(logMaker.setCategory(MetricsProto.MetricsEvent.ACTION_NOTE_CONTROLS) - .setType(MetricsProto.MetricsEvent.TYPE_ACTION)); - // ensure that it's laid but not visible until actually laid out guts.setVisibility(View.INVISIBLE); // Post to ensure the the guts are properly laid out. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java index 359bc6ec71d8..b6948fc4bd1f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java @@ -126,18 +126,23 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G private OnClickListener mOnKeepShowing = v -> { mExitReason = NotificationCounters.BLOCKING_HELPER_KEEP_SHOWING; closeControls(v); - mMetricsLogger.write(getLogMaker().setCategory(MetricsEvent.NOTIFICATION_BLOCKING_HELPER) - .setType(MetricsEvent.TYPE_ACTION) - .setSubtype(MetricsEvent.BLOCKING_HELPER_CLICK_STAY_SILENT)); + if (mIsForBlockingHelper) { + mMetricsLogger.write(getLogMaker().setCategory( + MetricsEvent.NOTIFICATION_BLOCKING_HELPER) + .setType(MetricsEvent.TYPE_ACTION) + .setSubtype(MetricsEvent.BLOCKING_HELPER_CLICK_STAY_SILENT)); + } }; private OnClickListener mOnToggleSilent = v -> { Runnable saveImportance = () -> { swapContent(ACTION_TOGGLE_SILENT, true /* animate */); - mMetricsLogger.write(getLogMaker() - .setCategory(MetricsEvent.NOTIFICATION_BLOCKING_HELPER) - .setType(MetricsEvent.TYPE_ACTION) - .setSubtype(MetricsEvent.BLOCKING_HELPER_CLICK_ALERT_ME)); + if (mIsForBlockingHelper) { + mMetricsLogger.write(getLogMaker() + .setCategory(MetricsEvent.NOTIFICATION_BLOCKING_HELPER) + .setType(MetricsEvent.TYPE_ACTION) + .setSubtype(MetricsEvent.BLOCKING_HELPER_CLICK_ALERT_ME)); + } }; if (mCheckSaveListener != null) { mCheckSaveListener.checkSave(saveImportance, mSbn); @@ -149,10 +154,12 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G private OnClickListener mOnStopOrMinimizeNotifications = v -> { Runnable saveImportance = () -> { swapContent(ACTION_BLOCK, true /* animate */); - mMetricsLogger.write(getLogMaker() - .setCategory(MetricsEvent.NOTIFICATION_BLOCKING_HELPER) - .setType(MetricsEvent.TYPE_ACTION) - .setSubtype(MetricsEvent.BLOCKING_HELPER_CLICK_BLOCKED)); + if (mIsForBlockingHelper) { + mMetricsLogger.write(getLogMaker() + .setCategory(MetricsEvent.NOTIFICATION_BLOCKING_HELPER) + .setType(MetricsEvent.TYPE_ACTION) + .setSubtype(MetricsEvent.BLOCKING_HELPER_CLICK_BLOCKED)); + } }; if (mCheckSaveListener != null) { mCheckSaveListener.checkSave(saveImportance, mSbn); @@ -164,12 +171,16 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G private OnClickListener mOnUndo = v -> { // Reset exit counter that we'll log and record an undo event separately (not an exit event) mExitReason = NotificationCounters.BLOCKING_HELPER_DISMISSED; - logBlockingHelperCounter(NotificationCounters.BLOCKING_HELPER_UNDO); - mMetricsLogger.write(importanceChangeLogMaker().setType(MetricsEvent.TYPE_DISMISS)); + if (mIsForBlockingHelper) { + logBlockingHelperCounter(NotificationCounters.BLOCKING_HELPER_UNDO); + mMetricsLogger.write(getLogMaker().setCategory( + MetricsEvent.NOTIFICATION_BLOCKING_HELPER) + .setType(MetricsEvent.TYPE_DISMISS) + .setSubtype(MetricsEvent.BLOCKING_HELPER_CLICK_UNDO)); + } else { + mMetricsLogger.write(importanceChangeLogMaker().setType(MetricsEvent.TYPE_DISMISS)); + } swapContent(ACTION_UNDO, true /* animate */); - mMetricsLogger.write(getLogMaker().setCategory(MetricsEvent.NOTIFICATION_BLOCKING_HELPER) - .setType(MetricsEvent.TYPE_DISMISS) - .setSubtype(MetricsEvent.BLOCKING_HELPER_CLICK_UNDO)); }; public NotificationInfo(Context context, AttributeSet attrs) { @@ -269,11 +280,11 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G bindPrompt(); bindButtons(); - mMetricsLogger.write(getLogMaker().setCategory(MetricsEvent.NOTIFICATION_BLOCKING_HELPER) - .setType(MetricsEvent.TYPE_OPEN) - .setSubtype(MetricsEvent.BLOCKING_HELPER_DISPLAY)); + mMetricsLogger.write(notificationControlsLogMaker()); } + + private void bindHeader() throws RemoteException { // Package name Drawable pkgicon = null; @@ -404,19 +415,6 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G } } - /** - * Returns an initialized LogMaker for logging importance changes. - * The caller may override the type (to DISMISS) before passing it to mMetricsLogger. - * @return new LogMaker - */ - private LogMaker importanceChangeLogMaker() { - Integer chosenImportance = - mChosenImportance != null ? mChosenImportance : mStartingChannelImportance; - return new LogMaker(MetricsEvent.ACTION_SAVE_IMPORTANCE) - .setType(MetricsEvent.TYPE_ACTION) - .setSubtype(chosenImportance - mStartingChannelImportance); - } - private boolean hasImportanceChanged() { return mSingleNotificationChannel != null && mChosenImportance != null @@ -616,8 +614,8 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G confirmation.setAlpha(1f); header.setVisibility(VISIBLE); header.setAlpha(1f); - mMetricsLogger.write(getLogMaker().setCategory(MetricsEvent.NOTIFICATION_BLOCKING_HELPER) - .setType(MetricsEvent.TYPE_CLOSE)); + + mMetricsLogger.write(notificationControlsLogMaker().setType(MetricsEvent.TYPE_CLOSE)); } @Override @@ -764,7 +762,39 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G } } + /** + * Returns a LogMaker with all available notification information. + * Caller should set category, type, and maybe subtype, before passing it to mMetricsLogger. + * @return LogMaker + */ private LogMaker getLogMaker() { - return mSbn.getLogMaker(); + // The constructor requires a category, so also do it in the other branch for consistency. + return mSbn == null ? new LogMaker(MetricsEvent.NOTIFICATION_BLOCKING_HELPER) + : mSbn.getLogMaker().setCategory(MetricsEvent.NOTIFICATION_BLOCKING_HELPER); + } + + /** + * Returns an initialized LogMaker for logging importance changes. + * The caller may override the type before passing it to mMetricsLogger. + * @return LogMaker + */ + private LogMaker importanceChangeLogMaker() { + Integer chosenImportance = + mChosenImportance != null ? mChosenImportance : mStartingChannelImportance; + return getLogMaker().setCategory(MetricsEvent.ACTION_SAVE_IMPORTANCE) + .setType(MetricsEvent.TYPE_ACTION) + .setSubtype(chosenImportance - mStartingChannelImportance); + } + + /** + * Returns an initialized LogMaker for logging open/close of the info display. + * The caller may override the type before passing it to mMetricsLogger. + * @return LogMaker + */ + private LogMaker notificationControlsLogMaker() { + return getLogMaker().setCategory(MetricsEvent.ACTION_NOTE_CONTROLS) + .setType(MetricsEvent.TYPE_OPEN) + .setSubtype(mIsForBlockingHelper ? MetricsEvent.BLOCKING_HELPER_DISPLAY + : MetricsEvent.BLOCKING_HELPER_UNKNOWN); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java index fdc9e0c4d7e4..727e9af94146 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java @@ -45,7 +45,6 @@ import android.app.Notification; import android.app.NotificationChannel; import android.content.Intent; import android.content.pm.PackageManager; -import android.metrics.LogMaker; import android.os.Binder; import android.os.Handler; import android.provider.Settings; @@ -57,7 +56,6 @@ import android.util.ArraySet; import android.view.View; import com.android.internal.logging.MetricsLogger; -import com.android.internal.logging.nano.MetricsProto; import com.android.systemui.SysuiTestCase; import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin; import com.android.systemui.statusbar.NotificationPresenter; @@ -220,34 +218,6 @@ public class NotificationGutsManagerTest extends SysuiTestCase { } @Test - public void testOpenGutsLogging() { - NotificationGutsManager gutsManager = spy(mGutsManager); - doReturn(true).when(gutsManager).bindGuts(any(), any()); - - NotificationGuts guts = spy(new NotificationGuts(mContext)); - doReturn(true).when(guts).post(any()); - - ExpandableNotificationRow realRow = createTestNotificationRow(); - NotificationMenuRowPlugin.MenuItem menuItem = createTestMenuItem(realRow); - - ExpandableNotificationRow row = spy(realRow); - when(row.getWindowToken()).thenReturn(new Binder()); - when(row.getGuts()).thenReturn(guts); - StatusBarNotification notification = spy(realRow.getStatusBarNotification()); - when(row.getStatusBarNotification()).thenReturn(notification); - - assertTrue(gutsManager.openGuts(row, 0, 0, menuItem)); - - ArgumentCaptor<LogMaker> logMakerCaptor = ArgumentCaptor.forClass(LogMaker.class); - verify(notification).getLogMaker(); - verify(mMetricsLogger).write(logMakerCaptor.capture()); - assertEquals(MetricsProto.MetricsEvent.ACTION_NOTE_CONTROLS, - logMakerCaptor.getValue().getCategory()); - assertEquals(MetricsProto.MetricsEvent.TYPE_ACTION, - logMakerCaptor.getValue().getType()); - } - - @Test public void testAppOpsSettingsIntent_camera() { ArraySet<Integer> ops = new ArraySet<>(); ops.add(OP_CAMERA); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java index 554baaf1ab9e..2a64445f342a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java @@ -83,7 +83,6 @@ import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; -import org.mockito.ArgumentMatcher; import org.mockito.Mock; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; @@ -107,11 +106,16 @@ public class NotificationInfoTest extends SysuiTestCase { private NotificationChannel mDefaultNotificationChannel; private StatusBarNotification mSbn; - @Rule public MockitoRule mockito = MockitoJUnit.rule(); - @Mock private MetricsLogger mMetricsLogger; - @Mock private INotificationManager mMockINotificationManager; - @Mock private PackageManager mMockPackageManager; - @Mock private NotificationBlockingHelperManager mBlockingHelperManager; + @Rule + public MockitoRule mockito = MockitoJUnit.rule(); + @Mock + private MetricsLogger mMetricsLogger; + @Mock + private INotificationManager mMockINotificationManager; + @Mock + private PackageManager mMockPackageManager; + @Mock + private NotificationBlockingHelperManager mBlockingHelperManager; @Before public void setUp() throws Exception { @@ -172,44 +176,25 @@ public class NotificationInfoTest extends SysuiTestCase { PollingCheck.waitFor(1000, () -> VISIBLE == mNotificationInfo.findViewById(R.id.confirmation).getVisibility()); } + private void ensureNoUndoButton() { PollingCheck.waitFor(1000, () -> GONE == mNotificationInfo.findViewById(R.id.confirmation).getVisibility() && !mNotificationInfo.isAnimating()); } + private void waitForStopButton() { PollingCheck.waitFor(1000, () -> VISIBLE == mNotificationInfo.findViewById(R.id.prompt).getVisibility()); } - class ImportanceChangeLogMaker implements ArgumentMatcher<LogMaker> { - private static final int CATEGORY = MetricsProto.MetricsEvent.ACTION_SAVE_IMPORTANCE; - private int mType, mSubtype; - - ImportanceChangeLogMaker(int type, int subtype) { - mType = type; - mSubtype = subtype; - } - public boolean matches(LogMaker l) { - return (l.getCategory() == CATEGORY) - && (l.getType() == mType) - && (l.getSubtype() == mSubtype); - } - - public String toString() { - return String.format("LogMaker(%d, %d, %d)", CATEGORY, mType, mSubtype); - } - } - - private LogMaker importanceChangeLog(int type, int subtype) { - return argThat(new ImportanceChangeLogMaker(type, subtype)); - } - @Test public void testBindNotification_SetsTextApplicationName() throws Exception { when(mMockPackageManager.getApplicationLabel(any())).thenReturn("App Name"); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, + TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, + null, null, null, + true, false, IMPORTANCE_DEFAULT, true); final TextView textView = mNotificationInfo.findViewById(R.id.pkgname); assertTrue(textView.getText().toString().contains("App Name")); @@ -330,9 +315,9 @@ public class NotificationInfoTest extends SysuiTestCase { @Test public void testBindNotification_BlockButton() throws Exception { - mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, - IMPORTANCE_DEFAULT, true); + mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, + TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, + IMPORTANCE_DEFAULT, true); final View block = mNotificationInfo.findViewById(R.id.int_block); final View minimize = mNotificationInfo.findViewById(R.id.block_or_minimize); assertEquals(VISIBLE, block.getVisibility()); @@ -340,7 +325,7 @@ public class NotificationInfoTest extends SysuiTestCase { } @Test - public void testBindNotification_BlockButton_BlockHelper() throws Exception { + public void testBindNotification_BlockButton_BlockingHelper() throws Exception { mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, true /* isBlockingHelper */, false, IMPORTANCE_DEFAULT, true); @@ -498,13 +483,29 @@ public class NotificationInfoTest extends SysuiTestCase { } @Test - public void testLogBlockingHelperCounter_logGutsViewDisplayed() throws Exception { + public void testBindNotificationLogging_notBlockingHelper() throws Exception { mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, + TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, + null, null, null, + true, false, + IMPORTANCE_DEFAULT, true); + verify(mMetricsLogger).write(argThat(logMaker -> + logMaker.getCategory() == MetricsEvent.ACTION_NOTE_CONTROLS + && logMaker.getType() == MetricsEvent.TYPE_OPEN + && logMaker.getSubtype() == MetricsEvent.BLOCKING_HELPER_UNKNOWN + )); + } + + @Test + public void testBindNotificationLogging_BlockingHelper() throws Exception { + mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, + TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, + null, null, null, + false, true, + true, true, IMPORTANCE_DEFAULT, true); - mNotificationInfo.logBlockingHelperCounter("HowCanNotifsBeRealIfAppsArent"); verify(mMetricsLogger).write(argThat(logMaker -> - logMaker.getCategory() == MetricsEvent.NOTIFICATION_BLOCKING_HELPER + logMaker.getCategory() == MetricsEvent.ACTION_NOTE_CONTROLS && logMaker.getType() == MetricsEvent.TYPE_OPEN && logMaker.getSubtype() == MetricsEvent.BLOCKING_HELPER_DISPLAY )); @@ -513,8 +514,11 @@ public class NotificationInfoTest extends SysuiTestCase { @Test public void testLogBlockingHelperCounter_logsForBlockingHelper() throws Exception { mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, false, true, - true, true, IMPORTANCE_DEFAULT, true); + TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, + null, null, null, + false, true, + true, true, + IMPORTANCE_DEFAULT, true); mNotificationInfo.logBlockingHelperCounter("HowCanNotifsBeRealIfAppsArent"); verify(mMetricsLogger).count(eq("HowCanNotifsBeRealIfAppsArent"), eq(1)); } @@ -680,7 +684,7 @@ public class NotificationInfoTest extends SysuiTestCase { mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel /* notificationChannel */, 10 /* numUniqueChannelsInRow */, mSbn, null /* checkSaveListener */, - null /* onSettingsClick */, null /* onAppSettingsClick */ , + null /* onSettingsClick */, null /* onAppSettingsClick */, true, false /* isNonblockable */, IMPORTANCE_DEFAULT, false ); @@ -722,7 +726,7 @@ public class NotificationInfoTest extends SysuiTestCase { mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel /* notificationChannel */, 10 /* numUniqueChannelsInRow */, mSbn, null /* checkSaveListener */, - null /* onSettingsClick */, null /* onAppSettingsClick */ , + null /* onSettingsClick */, null /* onAppSettingsClick */, true /* provisioned */, false /* isNonblockable */, true /* isForBlockingHelper */, true /* isUserSentimentNegative */, IMPORTANCE_DEFAULT, true); @@ -744,14 +748,14 @@ public class NotificationInfoTest extends SysuiTestCase { } @Test - public void testCloseControls_nonNullCheckSaveListenerDoesntDelayKeepShowing() + public void testCloseControls_nonNullCheckSaveListenerDoesntDelayKeepShowing_BlockingHelper() throws Exception { NotificationInfo.CheckSaveListener listener = mock(NotificationInfo.CheckSaveListener.class); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel /* notificationChannel */, 10 /* numUniqueChannelsInRow */, mSbn, listener /* checkSaveListener */, - null /* onSettingsClick */, null /* onAppSettingsClick */ , true /* provisioned */, + null /* onSettingsClick */, null /* onAppSettingsClick */, true /* provisioned */, false /* isNonblockable */, true /* isForBlockingHelper */, true /* isUserSentimentNegative */, IMPORTANCE_DEFAULT, true); @@ -772,14 +776,14 @@ public class NotificationInfoTest extends SysuiTestCase { } @Test - public void testCloseControls_nonNullCheckSaveListenerDoesntDelayDismiss() + public void testCloseControls_nonNullCheckSaveListenerDoesntDelayDismiss_BlockingHelper() throws Exception { NotificationInfo.CheckSaveListener listener = mock(NotificationInfo.CheckSaveListener.class); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, TEST_PACKAGE_NAME, mNotificationChannel /* notificationChannel */, 10 /* numUniqueChannelsInRow */, mSbn, listener /* checkSaveListener */, - null /* onSettingsClick */, null /* onAppSettingsClick */ , + null /* onSettingsClick */, null /* onAppSettingsClick */, false /* isNonblockable */, true /* isForBlockingHelper */, true, true /* isUserSentimentNegative */, /* isNoisy */ IMPORTANCE_DEFAULT, true); @@ -791,7 +795,7 @@ public class NotificationInfoTest extends SysuiTestCase { } @Test - public void testCloseControls_checkSaveListenerDelaysStopNotifications() + public void testCloseControls_checkSaveListenerDelaysStopNotifications_BlockingHelper() throws Exception { NotificationInfo.CheckSaveListener listener = mock(NotificationInfo.CheckSaveListener.class); @@ -849,18 +853,25 @@ public class NotificationInfoTest extends SysuiTestCase { } @Test - public void testBlockChangedCallsUpdateNotificationChannel() throws Exception { + public void testBlockChangedCallsUpdateNotificationChannel_notBlockingHelper() + throws Exception { mNotificationChannel.setImportance(IMPORTANCE_LOW); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, + TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, + null, null, null, + true, false, IMPORTANCE_DEFAULT, false); mNotificationInfo.findViewById(R.id.int_block).performClick(); waitForUndoButton(); mNotificationInfo.handleCloseControls(true, false); - verify(mMetricsLogger).write(importanceChangeLog( - MetricsProto.MetricsEvent.TYPE_ACTION, IMPORTANCE_NONE - IMPORTANCE_LOW)); + ArgumentCaptor<LogMaker> logMakerCaptor = ArgumentCaptor.forClass(LogMaker.class); + verify(mMetricsLogger, times(2)).write(logMakerCaptor.capture()); + assertEquals(MetricsProto.MetricsEvent.TYPE_ACTION, + logMakerCaptor.getValue().getType()); + assertEquals(IMPORTANCE_NONE - IMPORTANCE_LOW, + logMakerCaptor.getValue().getSubtype()); mTestableLooper.processAllMessages(); ArgumentCaptor<NotificationChannel> updated = @@ -896,8 +907,12 @@ public class NotificationInfoTest extends SysuiTestCase { waitForUndoButton(); mNotificationInfo.handleCloseControls(true, false); - verify(mMetricsLogger).write(importanceChangeLog( - MetricsProto.MetricsEvent.TYPE_ACTION, IMPORTANCE_NONE - IMPORTANCE_LOW)); + ArgumentCaptor<LogMaker> logMakerCaptor = ArgumentCaptor.forClass(LogMaker.class); + verify(mMetricsLogger, times(3)).write(logMakerCaptor.capture()); + assertEquals(MetricsProto.MetricsEvent.TYPE_ACTION, + logMakerCaptor.getValue().getType()); + assertEquals(IMPORTANCE_NONE - IMPORTANCE_LOW, + logMakerCaptor.getValue().getSubtype()); mTestableLooper.processAllMessages(); ArgumentCaptor<NotificationChannel> updated = @@ -965,10 +980,12 @@ public class NotificationInfoTest extends SysuiTestCase { } @Test - public void testBlockUndoDoesNotBlockNotificationChannel() throws Exception { + public void testBlockUndoDoesNotBlockNotificationChannel_notBlockingHelper() throws Exception { mNotificationChannel.setImportance(IMPORTANCE_LOW); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false, + TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, + null, null, null, + true, false, IMPORTANCE_DEFAULT, false); mNotificationInfo.findViewById(R.id.int_block).performClick(); @@ -977,8 +994,15 @@ public class NotificationInfoTest extends SysuiTestCase { waitForStopButton(); // mNotificationInfo.handleCloseControls doesn't get called by this interaction. - verify(mMetricsLogger).write(importanceChangeLog( - MetricsProto.MetricsEvent.TYPE_DISMISS, IMPORTANCE_NONE - IMPORTANCE_LOW)); + ArgumentCaptor<LogMaker> logMakerCaptor = ArgumentCaptor.forClass(LogMaker.class); + verify(mMetricsLogger, times(2)).write(logMakerCaptor.capture()); + assertEquals(MetricsEvent.ACTION_SAVE_IMPORTANCE, + logMakerCaptor.getValue().getCategory()); + assertEquals(MetricsEvent.TYPE_DISMISS, + logMakerCaptor.getValue().getType()); + assertEquals(IMPORTANCE_NONE - IMPORTANCE_LOW, + logMakerCaptor.getValue().getSubtype()); + mTestableLooper.processAllMessages(); verify(mMockINotificationManager, never()).updateNotificationChannelForPackage( @@ -986,11 +1010,12 @@ public class NotificationInfoTest extends SysuiTestCase { } @Test - public void testMinUndoDoesNotMinNotificationChannel() throws Exception { + public void testMinUndoDoesNotMinNotificationChannel_notBlockingHelper() throws Exception { mNotificationChannel.setImportance(IMPORTANCE_LOW); mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager, - TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true, - IMPORTANCE_DEFAULT, false); + TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, + null, null, null, true, + true, IMPORTANCE_DEFAULT, false); mNotificationInfo.findViewById(R.id.minimize).performClick(); waitForUndoButton(); diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java index f4ac13074903..fc43882b4ffd 100644 --- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java +++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java @@ -348,8 +348,8 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ } int getRelevantEventTypes() { - return (mUsesAccessibilityCache ? AccessibilityCache.CACHE_CRITICAL_EVENTS_MASK : 0) - | mEventTypes; + return (mUsesAccessibilityCache ? AccessibilityCache.CACHE_CRITICAL_EVENTS_MASK + : AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) | mEventTypes; } @Override diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java index d2c6354e91b8..33c6dd24012a 100644 --- a/services/core/java/com/android/server/LocationManagerService.java +++ b/services/core/java/com/android/server/LocationManagerService.java @@ -405,6 +405,7 @@ public class LocationManagerService extends ILocationManager.Stub { // initialize in-memory settings values onBackgroundThrottleWhitelistChangedLocked(); + onIgnoreSettingsWhitelistChangedLocked(); } @GuardedBy("mLock") @@ -547,18 +548,17 @@ public class LocationManagerService extends ILocationManager.Stub { @GuardedBy("mLock") private void onBackgroundThrottleWhitelistChangedLocked() { + mBackgroundThrottlePackageWhitelist.clear(); + mBackgroundThrottlePackageWhitelist.addAll( + SystemConfig.getInstance().getAllowUnthrottledLocation()); + String setting = Settings.Global.getString( mContext.getContentResolver(), Settings.Global.LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST); - if (setting == null) { - setting = ""; + if (!TextUtils.isEmpty(setting)) { + mBackgroundThrottlePackageWhitelist.addAll(Arrays.asList(setting.split(","))); } - mBackgroundThrottlePackageWhitelist.clear(); - mBackgroundThrottlePackageWhitelist.addAll( - SystemConfig.getInstance().getAllowUnthrottledLocation()); - mBackgroundThrottlePackageWhitelist.addAll(Arrays.asList(setting.split(","))); - for (LocationProvider p : mProviders) { applyRequirementsLocked(p); } @@ -566,18 +566,17 @@ public class LocationManagerService extends ILocationManager.Stub { @GuardedBy("lock") private void onIgnoreSettingsWhitelistChangedLocked() { + mIgnoreSettingsPackageWhitelist.clear(); + mIgnoreSettingsPackageWhitelist.addAll( + SystemConfig.getInstance().getAllowIgnoreLocationSettings()); + String setting = Settings.Global.getString( mContext.getContentResolver(), Settings.Global.LOCATION_IGNORE_SETTINGS_PACKAGE_WHITELIST); - if (setting == null) { - setting = ""; + if (!TextUtils.isEmpty(setting)) { + mIgnoreSettingsPackageWhitelist.addAll(Arrays.asList(setting.split(","))); } - mIgnoreSettingsPackageWhitelist.clear(); - mIgnoreSettingsPackageWhitelist.addAll( - SystemConfig.getInstance().getAllowIgnoreLocationSettings()); - mIgnoreSettingsPackageWhitelist.addAll(Arrays.asList(setting.split(","))); - for (LocationProvider p : mProviders) { applyRequirementsLocked(p); } @@ -2200,7 +2199,7 @@ public class LocationManagerService extends ILocationManager.Stub { return false; } - if (mBackgroundThrottlePackageWhitelist.contains(record.mReceiver.mIdentity.mPackageName)) { + if (mIgnoreSettingsPackageWhitelist.contains(record.mReceiver.mIdentity.mPackageName)) { return true; } diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java index cecd55a325d3..f2329d3ebf8e 100644 --- a/services/core/java/com/android/server/StorageManagerService.java +++ b/services/core/java/com/android/server/StorageManagerService.java @@ -1541,10 +1541,6 @@ class StorageManagerService extends IStorageManager.Stub mCallbacks = new Callbacks(FgThread.get().getLooper()); mLockPatternUtils = new LockPatternUtils(mContext); - mPmInternal = LocalServices.getService(PackageManagerInternal.class); - mUmInternal = LocalServices.getService(UserManagerInternal.class); - mAmInternal = LocalServices.getService(ActivityManagerInternal.class); - HandlerThread hthread = new HandlerThread(TAG); hthread.start(); mHandler = new StorageManagerServiceHandler(hthread.getLooper()); @@ -1662,6 +1658,19 @@ class StorageManagerService extends IStorageManager.Stub } private void servicesReady() { + mPmInternal = LocalServices.getService(PackageManagerInternal.class); + mUmInternal = LocalServices.getService(UserManagerInternal.class); + mAmInternal = LocalServices.getService(ActivityManagerInternal.class); + + mIPackageManager = IPackageManager.Stub.asInterface( + ServiceManager.getService("package")); + mIAppOpsService = IAppOpsService.Stub.asInterface( + ServiceManager.getService(Context.APP_OPS_SERVICE)); + try { + mIAppOpsService.startWatchingMode(OP_REQUEST_INSTALL_PACKAGES, null, mAppOpsCallback); + } catch (RemoteException e) { + } + synchronized (mLock) { final boolean thisIsolatedStorage = StorageManager.hasIsolatedStorage(); if (mLastIsolatedStorage == thisIsolatedStorage) { @@ -1734,14 +1743,6 @@ class StorageManagerService extends IStorageManager.Stub .registerScreenObserver(this); mSystemReady = true; - mIPackageManager = IPackageManager.Stub.asInterface( - ServiceManager.getService("package")); - mIAppOpsService = IAppOpsService.Stub.asInterface( - ServiceManager.getService(Context.APP_OPS_SERVICE)); - try { - mIAppOpsService.startWatchingMode(OP_REQUEST_INSTALL_PACKAGES, null, mAppOpsCallback); - } catch (RemoteException e) { - } mHandler.obtainMessage(H_SYSTEM_READY).sendToTarget(); } diff --git a/services/core/java/com/android/server/ThreadPriorityBooster.java b/services/core/java/com/android/server/ThreadPriorityBooster.java index 53e8ce43fff8..f74a438509c2 100644 --- a/services/core/java/com/android/server/ThreadPriorityBooster.java +++ b/services/core/java/com/android/server/ThreadPriorityBooster.java @@ -43,9 +43,9 @@ public class ThreadPriorityBooster { public void boost() { final int tid = myTid(); - final int prevPriority = getThreadPriority(tid); final PriorityState state = mThreadState.get(); if (state.regionCounter == 0) { + final int prevPriority = getThreadPriority(tid); state.prevPriority = prevPriority; if (prevPriority > mBoostToPriority) { setThreadPriority(tid, mBoostToPriority); @@ -60,9 +60,11 @@ public class ThreadPriorityBooster { public void reset() { final PriorityState state = mThreadState.get(); state.regionCounter--; - final int currentPriority = getThreadPriority(myTid()); - if (state.regionCounter == 0 && state.prevPriority != currentPriority) { - setThreadPriority(myTid(), state.prevPriority); + if (state.regionCounter == 0) { + final int currentPriority = getThreadPriority(myTid()); + if (state.prevPriority != currentPriority) { + setThreadPriority(myTid(), state.prevPriority); + } } } @@ -77,9 +79,11 @@ public class ThreadPriorityBooster { mBoostToPriority = priority; final PriorityState state = mThreadState.get(); final int tid = myTid(); - final int prevPriority = getThreadPriority(tid); - if (state.regionCounter != 0 && prevPriority != priority) { - setThreadPriority(tid, priority); + if (state.regionCounter != 0) { + final int prevPriority = getThreadPriority(tid); + if (prevPriority != priority) { + setThreadPriority(tid, priority); + } } } diff --git a/services/core/java/com/android/server/am/AppCompactor.java b/services/core/java/com/android/server/am/AppCompactor.java index bb55ec3100c0..1118014dab96 100644 --- a/services/core/java/com/android/server/am/AppCompactor.java +++ b/services/core/java/com/android/server/am/AppCompactor.java @@ -19,6 +19,7 @@ package com.android.server.am; import static android.os.Process.THREAD_PRIORITY_FOREGROUND; import static android.provider.DeviceConfig.ActivityManager.KEY_COMPACT_ACTION_1; import static android.provider.DeviceConfig.ActivityManager.KEY_COMPACT_ACTION_2; +import static android.provider.DeviceConfig.ActivityManager.KEY_COMPACT_STATSD_SAMPLE_RATE; import static android.provider.DeviceConfig.ActivityManager.KEY_COMPACT_THROTTLE_1; import static android.provider.DeviceConfig.ActivityManager.KEY_COMPACT_THROTTLE_2; import static android.provider.DeviceConfig.ActivityManager.KEY_COMPACT_THROTTLE_3; @@ -45,6 +46,7 @@ import com.android.server.ServiceThread; import java.io.FileOutputStream; import java.io.PrintWriter; import java.util.ArrayList; +import java.util.Random; public final class AppCompactor { @@ -65,6 +67,8 @@ public final class AppCompactor { @VisibleForTesting static final long DEFAULT_COMPACT_THROTTLE_2 = 10_000; @VisibleForTesting static final long DEFAULT_COMPACT_THROTTLE_3 = 500; @VisibleForTesting static final long DEFAULT_COMPACT_THROTTLE_4 = 10_000; + // The sampling rate to push app compaction events into statsd for upload. + @VisibleForTesting static final float DEFAULT_STATSD_SAMPLE_RATE = 0.1f; @VisibleForTesting interface PropertyChangedCallbackForTest { @@ -104,6 +108,8 @@ public final class AppCompactor { || KEY_COMPACT_THROTTLE_3.equals(name) || KEY_COMPACT_THROTTLE_4.equals(name)) { updateCompactionThrottles(); + } else if (KEY_COMPACT_STATSD_SAMPLE_RATE.equals(name)) { + updateStatsdSampleRate(); } } if (mTestCallback != null) { @@ -116,21 +122,25 @@ public final class AppCompactor { // Configured by phenotype. Updates from the server take effect immediately. @GuardedBy("mPhenotypeFlagLock") - @VisibleForTesting String mCompactActionSome = + @VisibleForTesting volatile String mCompactActionSome = compactActionIntToString(DEFAULT_COMPACT_ACTION_1); @GuardedBy("mPhenotypeFlagLock") - @VisibleForTesting String mCompactActionFull = + @VisibleForTesting volatile String mCompactActionFull = compactActionIntToString(DEFAULT_COMPACT_ACTION_2); @GuardedBy("mPhenotypeFlagLock") - @VisibleForTesting long mCompactThrottleSomeSome = DEFAULT_COMPACT_THROTTLE_1; + @VisibleForTesting volatile long mCompactThrottleSomeSome = DEFAULT_COMPACT_THROTTLE_1; @GuardedBy("mPhenotypeFlagLock") - @VisibleForTesting long mCompactThrottleSomeFull = DEFAULT_COMPACT_THROTTLE_2; + @VisibleForTesting volatile long mCompactThrottleSomeFull = DEFAULT_COMPACT_THROTTLE_2; @GuardedBy("mPhenotypeFlagLock") - @VisibleForTesting long mCompactThrottleFullSome = DEFAULT_COMPACT_THROTTLE_3; + @VisibleForTesting volatile long mCompactThrottleFullSome = DEFAULT_COMPACT_THROTTLE_3; @GuardedBy("mPhenotypeFlagLock") - @VisibleForTesting long mCompactThrottleFullFull = DEFAULT_COMPACT_THROTTLE_4; + @VisibleForTesting volatile long mCompactThrottleFullFull = DEFAULT_COMPACT_THROTTLE_4; @GuardedBy("mPhenotypeFlagLock") - private boolean mUseCompaction = DEFAULT_USE_COMPACTION; + private volatile boolean mUseCompaction = DEFAULT_USE_COMPACTION; + + private final Random mRandom = new Random(); + @GuardedBy("mPhenotypeFlagLock") + @VisibleForTesting volatile float mStatsdSampleRate = DEFAULT_STATSD_SAMPLE_RATE; // Handler on which compaction runs. private Handler mCompactionHandler; @@ -158,6 +168,7 @@ public final class AppCompactor { updateUseCompaction(); updateCompactionActions(); updateCompactionThrottles(); + updateStatsdSampleRate(); } } @@ -181,6 +192,7 @@ public final class AppCompactor { pw.println(" " + KEY_COMPACT_THROTTLE_2 + "=" + mCompactThrottleSomeFull); pw.println(" " + KEY_COMPACT_THROTTLE_3 + "=" + mCompactThrottleFullSome); pw.println(" " + KEY_COMPACT_THROTTLE_4 + "=" + mCompactThrottleFullFull); + pw.println(" " + KEY_COMPACT_STATSD_SAMPLE_RATE + "=" + mStatsdSampleRate); } } @@ -289,6 +301,19 @@ public final class AppCompactor { } } + @GuardedBy("mPhenotypeFlagLock") + private void updateStatsdSampleRate() { + String sampleRateFlag = DeviceConfig.getProperty(DeviceConfig.ActivityManager.NAMESPACE, + KEY_COMPACT_STATSD_SAMPLE_RATE); + try { + mStatsdSampleRate = TextUtils.isEmpty(sampleRateFlag) + ? DEFAULT_STATSD_SAMPLE_RATE : Float.parseFloat(sampleRateFlag); + } catch (NumberFormatException e) { + mStatsdSampleRate = DEFAULT_STATSD_SAMPLE_RATE; + } + mStatsdSampleRate = Math.min(1.0f, Math.max(0.0f, mStatsdSampleRate)); + } + @VisibleForTesting static String compactActionIntToString(int action) { switch(action) { @@ -385,11 +410,16 @@ public final class AppCompactor { rssBefore[0], rssBefore[1], rssBefore[2], rssBefore[3], rssAfter[0], rssAfter[1], rssAfter[2], rssAfter[3], time, lastCompactAction, lastCompactTime, msg.arg1, msg.arg2); - StatsLog.write(StatsLog.APP_COMPACTED, pid, name, pendingAction, - rssBefore[0], rssBefore[1], rssBefore[2], rssBefore[3], - rssAfter[0], rssAfter[1], rssAfter[2], rssAfter[3], time, - lastCompactAction, lastCompactTime, msg.arg1, - ActivityManager.processStateAmToProto(msg.arg2)); + // Note that as above not taking mPhenoTypeFlagLock here to avoid locking + // on every single compaction for a flag that will seldom change and the + // impact of reading the wrong value here is low. + if (mRandom.nextFloat() < mStatsdSampleRate) { + StatsLog.write(StatsLog.APP_COMPACTED, pid, name, pendingAction, + rssBefore[0], rssBefore[1], rssBefore[2], rssBefore[3], + rssAfter[0], rssAfter[1], rssAfter[2], rssAfter[3], time, + lastCompactAction, lastCompactTime, msg.arg1, + ActivityManager.processStateAmToProto(msg.arg2)); + } synchronized (mAm) { proc.lastCompactTime = end; proc.lastCompactAction = pendingAction; diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java index 64a36ef66f12..1fb11baab2e4 100644 --- a/services/core/java/com/android/server/am/BroadcastQueue.java +++ b/services/core/java/com/android/server/am/BroadcastQueue.java @@ -450,7 +450,7 @@ public final class BroadcastQueue { if (state == BroadcastRecord.IDLE) { Slog.w(TAG, "finishReceiver [" + mQueueName + "] called but state is IDLE"); } - if (r.allowBackgroundActivityStarts) { + if (r.allowBackgroundActivityStarts && r.curApp != null) { r.curApp.removeAllowBackgroundActivityStartsToken(r); } // If we're abandoning this broadcast before any receivers were actually spun up, diff --git a/services/core/java/com/android/server/attention/AttentionManagerService.java b/services/core/java/com/android/server/attention/AttentionManagerService.java index 5b469fe2dc7a..2061b2681268 100644 --- a/services/core/java/com/android/server/attention/AttentionManagerService.java +++ b/services/core/java/com/android/server/attention/AttentionManagerService.java @@ -16,9 +16,9 @@ package com.android.server.attention; +import static android.provider.DeviceConfig.AttentionManagerService.COMPONENT_NAME; import static android.provider.DeviceConfig.AttentionManagerService.NAMESPACE; -import static android.provider.DeviceConfig.AttentionManagerService.PROPERTY_COMPONENT_NAME; -import static android.provider.DeviceConfig.AttentionManagerService.PROPERTY_SERVICE_ENABLED; +import static android.provider.DeviceConfig.AttentionManagerService.SERVICE_ENABLED; import android.Manifest; import android.annotation.Nullable; @@ -129,7 +129,7 @@ public class AttentionManagerService extends SystemService { } private boolean isServiceEnabled() { - final String enabled = DeviceConfig.getProperty(NAMESPACE, PROPERTY_SERVICE_ENABLED); + final String enabled = DeviceConfig.getProperty(NAMESPACE, SERVICE_ENABLED); return enabled == null ? DEFAULT_SERVICE_ENABLED : "true".equals(enabled); } @@ -279,7 +279,7 @@ public class AttentionManagerService extends SystemService { * system. */ private static ComponentName resolveAttentionService(Context context) { - final String flag = DeviceConfig.getProperty(NAMESPACE, PROPERTY_COMPONENT_NAME); + final String flag = DeviceConfig.getProperty(NAMESPACE, COMPONENT_NAME); final String componentNameString = flag != null ? flag : context.getString( R.string.config_defaultAttentionService); diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java index d652f93ccf04..deaa9313fadd 100644 --- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java +++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java @@ -600,7 +600,7 @@ import java.util.ArrayList; break; case MSG_IL_SET_A2DP_SINK_CONNECTION_STATE: mDeviceInventory.onSetA2dpSinkConnectionState( - (BtHelper.BluetoothA2dpDeviceInfo) msg.obj, msg.arg1, msg.arg2); + (BtHelper.BluetoothA2dpDeviceInfo) msg.obj, msg.arg1); break; case MSG_IL_SET_A2DP_SOURCE_CONNECTION_STATE: mDeviceInventory.onSetA2dpSourceConnectionState( diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java index eb76e6e02edc..97649a741f62 100644 --- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java +++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java @@ -147,18 +147,20 @@ public final class AudioDeviceInventory { } /*package*/ void onSetA2dpSinkConnectionState(@NonNull BtHelper.BluetoothA2dpDeviceInfo btInfo, - @AudioService.BtProfileConnectionState int state, int a2dpVolume) { + @AudioService.BtProfileConnectionState int state) { final BluetoothDevice btDevice = btInfo.getBtDevice(); + int a2dpVolume = btInfo.getVolume(); if (AudioService.DEBUG_DEVICES) { Log.d(TAG, "onSetA2dpSinkConnectionState btDevice=" + btDevice + " state=" - + state + " is dock=" + btDevice.isBluetoothDock()); + + state + " is dock=" + btDevice.isBluetoothDock() + " vol=" + a2dpVolume); } String address = btDevice.getAddress(); if (!BluetoothAdapter.checkBluetoothAddress(address)) { address = ""; } AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent( - "A2DP sink connected: device addr=" + address + " state=" + state)); + "A2DP sink connected: device addr=" + address + " state=" + state + + " vol=" + a2dpVolume)); final int a2dpCodec; synchronized (mDeviceBroker.mA2dpAvrcpLock) { diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index df33bf249133..1723163a132d 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -392,12 +392,14 @@ public class AudioService extends IAudioService.Stub * e.g. user on homescreen, no app playing anything, presses hardware volume buttons, this * stream type is controlled. */ - protected static final int DEFAULT_VOL_STREAM_NO_PLAYBACK = AudioSystem.STREAM_MUSIC; + protected static final int DEFAULT_VOL_STREAM_NO_PLAYBACK = AudioSystem.STREAM_MUSIC; private final AudioSystem.ErrorCallback mAudioSystemCallback = new AudioSystem.ErrorCallback() { public void onError(int error) { switch (error) { case AudioSystem.AUDIO_STATUS_SERVER_DIED: + mRecordMonitor.clear(); + sendMsg(mAudioHandler, MSG_AUDIO_SERVER_DIED, SENDMSG_NOOP, 0, 0, null, 0); sendMsg(mAudioHandler, MSG_DISPATCH_AUDIO_SERVER_STATE, diff --git a/services/core/java/com/android/server/audio/RecordingActivityMonitor.java b/services/core/java/com/android/server/audio/RecordingActivityMonitor.java index 9d6628cf0c40..b2c7ff3bfdf6 100644 --- a/services/core/java/com/android/server/audio/RecordingActivityMonitor.java +++ b/services/core/java/com/android/server/audio/RecordingActivityMonitor.java @@ -78,24 +78,27 @@ public final class RecordingActivityMonitor implements AudioSystem.AudioRecordin updateSnapshot(event, uid, session, source, recordingInfo, portId, silenced, activeSource, clientEffects, effects); if (configsSystem != null){ - synchronized (mClients) { - // list of recording configurations for "public consumption". It is only computed if - // there are non-system recording activity listeners. - final List<AudioRecordingConfiguration> configsPublic = mHasPublicClients ? - anonymizeForPublicConsumption(configsSystem) : - new ArrayList<AudioRecordingConfiguration>(); - final Iterator<RecMonitorClient> clientIterator = mClients.iterator(); - while (clientIterator.hasNext()) { - final RecMonitorClient rmc = clientIterator.next(); - try { - if (rmc.mIsPrivileged) { - rmc.mDispatcherCb.dispatchRecordingConfigChange(configsSystem); - } else { - rmc.mDispatcherCb.dispatchRecordingConfigChange(configsPublic); - } - } catch (RemoteException e) { - Log.w(TAG, "Could not call dispatchRecordingConfigChange() on client", e); + dispatchCallbacks(configsSystem); + } + } + private void dispatchCallbacks(List<AudioRecordingConfiguration> configs) { + synchronized (mClients) { + // list of recording configurations for "public consumption". It is only computed if + // there are non-system recording activity listeners. + final List<AudioRecordingConfiguration> configsPublic = mHasPublicClients + ? anonymizeForPublicConsumption(configs) : + new ArrayList<AudioRecordingConfiguration>(); + final Iterator<RecMonitorClient> clientIterator = mClients.iterator(); + while (clientIterator.hasNext()) { + final RecMonitorClient rmc = clientIterator.next(); + try { + if (rmc.mIsPrivileged) { + rmc.mDispatcherCb.dispatchRecordingConfigChange(configs); + } else { + rmc.mDispatcherCb.dispatchRecordingConfigChange(configsPublic); } + } catch (RemoteException e) { + Log.w(TAG, "Could not call dispatchRecordingConfigChange() on client", e); } } } @@ -130,6 +133,13 @@ public final class RecordingActivityMonitor implements AudioSystem.AudioRecordin AudioSystem.setRecordingCallback(this); } + void clear() { + synchronized (mRecordConfigs) { + mRecordConfigs.clear(); + } + dispatchCallbacks(new ArrayList<AudioRecordingConfiguration>()); + } + void registerRecordingCallback(IRecordingConfigDispatcher rcdb, boolean isPrivileged) { if (rcdb == null) { return; diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java index db3928ec5fde..2a8462bc03f7 100644 --- a/services/core/java/com/android/server/display/DisplayPowerController.java +++ b/services/core/java/com/android/server/display/DisplayPowerController.java @@ -592,6 +592,9 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call } public BrightnessConfiguration getDefaultBrightnessConfiguration() { + if (mAutomaticBrightnessController == null) { + return null; + } return mAutomaticBrightnessController.getDefaultConfig(); } diff --git a/services/core/java/com/android/server/dreams/OWNERS b/services/core/java/com/android/server/dreams/OWNERS index 3c9bbf8797ea..426f002ad236 100644 --- a/services/core/java/com/android/server/dreams/OWNERS +++ b/services/core/java/com/android/server/dreams/OWNERS @@ -1,3 +1,3 @@ -dsandler@google.com +dsandler@android.com michaelwr@google.com roosa@google.com diff --git a/services/core/java/com/android/server/incident/IncidentCompanionService.java b/services/core/java/com/android/server/incident/IncidentCompanionService.java index 3ebba0074a1c..6f2bfc3cd8d2 100644 --- a/services/core/java/com/android/server/incident/IncidentCompanionService.java +++ b/services/core/java/com/android/server/incident/IncidentCompanionService.java @@ -16,38 +16,18 @@ package com.android.server.incident; -import android.app.ActivityManager; -import android.app.AppOpsManager; -import android.content.ComponentName; import android.content.Context; -import android.content.Intent; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; -import android.content.pm.UserInfo; -import android.net.Uri; import android.os.Binder; -import android.os.Handler; import android.os.IIncidentAuthListener; import android.os.IIncidentCompanion; -import android.os.IncidentManager; -import android.os.RemoteException; -import android.os.SystemClock; -import android.os.UserHandle; -import android.os.UserManager; -import android.util.Log; import com.android.internal.util.DumpUtils; import com.android.server.SystemService; import java.io.FileDescriptor; import java.io.PrintWriter; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Date; import java.util.List; -// TODO: User changes should deny everything that's pending. - /** * Helper service for incidentd and dumpstated to provide user feedback * and authorization for bug and inicdent reports to be taken. @@ -55,83 +35,26 @@ import java.util.List; public class IncidentCompanionService extends SystemService { static final String TAG = "IncidentCompanionService"; - private final Handler mHandler = new Handler(); - private final RequestQueue mRequestQueue = new RequestQueue(mHandler); - private final PackageManager mPackageManager; - private final AppOpsManager mAppOpsManager; - - // - // All fields below must be protected by mLock - // - private final Object mLock = new Object(); - private final ArrayList<PendingReportRec> mPending = new ArrayList(); - /** - * The next ID we'll use when we make a PendingReportRec. + * Tracker for reports pending approval. */ - private int mNextPendingId = 1; - - /** - * One for each authorization that's pending. - */ - private final class PendingReportRec { - public int id; - public String callingPackage; - public int flags; - public IIncidentAuthListener listener; - public long addedRealtime; - public long addedWalltime; - - /** - * Construct a PendingReportRec, with an auto-incremented id. - */ - PendingReportRec(String callingPackage, int flags, IIncidentAuthListener listener) { - this.id = mNextPendingId++; - this.callingPackage = callingPackage; - this.flags = flags; - this.listener = listener; - this.addedRealtime = SystemClock.elapsedRealtime(); - this.addedWalltime = System.currentTimeMillis(); - } - - /** - * Get the Uri that contains the flattened data. - */ - Uri getUri() { - return (new Uri.Builder()) - .scheme(IncidentManager.URI_SCHEME) - .authority(IncidentManager.URI_AUTHORITY) - .path(IncidentManager.URI_PATH) - .appendQueryParameter(IncidentManager.URI_PARAM_ID, Integer.toString(id)) - .appendQueryParameter(IncidentManager.URI_PARAM_CALLING_PACKAGE, callingPackage) - .appendQueryParameter(IncidentManager.URI_PARAM_FLAGS, Integer.toString(flags)) - .appendQueryParameter(IncidentManager.URI_PARAM_TIMESTAMP, - Long.toString(addedWalltime)) - .build(); - } - } + private PendingReports mPendingReports; /** * Implementation of the IIncidentCompanion binder interface. */ private final class BinderService extends IIncidentCompanion.Stub { /** - * ONEWAY binder call to initiate authorizing the report. The actual logic is posted - * to mRequestQueue, and may happen later. The security checks need to happen here. + * ONEWAY binder call to initiate authorizing the report. */ @Override - public void authorizeReport(int callingUid, final String callingPackage, final int flags, + public void authorizeReport(int callingUid, final String callingPackage, int flags, final IIncidentAuthListener listener) { enforceRequestAuthorizationPermission(); final long ident = Binder.clearCallingIdentity(); try { - // Starting the system server is complicated, and rather than try to - // have a complicated lifecycle that we share with dumpstated and incidentd, - // we will accept the request, and then display it whenever it becomes possible to. - mRequestQueue.enqueue(listener.asBinder(), true, () -> { - authorizeReportImpl(callingUid, callingPackage, flags, listener); - }); + mPendingReports.authorizeReport(callingUid, callingPackage, flags, listener); } finally { Binder.restoreCallingIdentity(ident); } @@ -152,9 +75,7 @@ public class IncidentCompanionService extends SystemService { // authorize/cancel pairs. final long ident = Binder.clearCallingIdentity(); try { - mRequestQueue.enqueue(listener.asBinder(), false, () -> { - cancelReportImpl(listener); - }); + mPendingReports.cancelAuthorization(listener); } finally { Binder.restoreCallingIdentity(ident); } @@ -167,19 +88,11 @@ public class IncidentCompanionService extends SystemService { @Override public List<String> getPendingReports() { enforceAuthorizePermission(); - - synchronized (mLock) { - final int size = mPending.size(); - final ArrayList<String> result = new ArrayList(size); - for (int i = 0; i < size; i++) { - result.add(mPending.get(i).getUri().toString()); - } - return result; - } + return mPendingReports.getPendingReports(); } /** - * ONEWAY binder call to mark a report as approved. + * SYNCHRONOUS binder call to mark a report as approved. */ @Override public void approveReport(String uri) { @@ -187,32 +100,14 @@ public class IncidentCompanionService extends SystemService { final long ident = Binder.clearCallingIdentity(); try { - final PendingReportRec rec; - synchronized (mLock) { - rec = findAndRemovePendingReportRecLocked(uri); - if (rec == null) { - Log.e(TAG, "confirmApproved: Couldn't find record for uri: " + uri); - return; - } - } - - // Re-do the broadcast, so whoever is listening knows the list changed, - // in case another one was added in the meantime. - sendBroadcast(); - - Log.i(TAG, "Approved report: " + uri); - try { - rec.listener.onReportApproved(); - } catch (RemoteException ex) { - Log.w(TAG, "Failed calling back for approval for: " + uri, ex); - } + mPendingReports.approveReport(uri); } finally { Binder.restoreCallingIdentity(ident); } } /** - * ONEWAY binder call to mark a report as NOT approved. + * SYNCHRONOUS binder call to mark a report as NOT approved. */ @Override public void denyReport(String uri) { @@ -220,25 +115,7 @@ public class IncidentCompanionService extends SystemService { final long ident = Binder.clearCallingIdentity(); try { - final PendingReportRec rec; - synchronized (mLock) { - rec = findAndRemovePendingReportRecLocked(uri); - if (rec == null) { - Log.e(TAG, "confirmDenied: Couldn't find record for uri: " + uri); - return; - } - } - - // Re-do the broadcast, so whoever is listening knows the list changed, - // in case another one was added in the meantime. - sendBroadcast(); - - Log.i(TAG, "Denied report: " + uri); - try { - rec.listener.onReportDenied(); - } catch (RemoteException ex) { - Log.w(TAG, "Failed calling back for denial for: " + uri, ex); - } + mPendingReports.denyReport(uri); } finally { Binder.restoreCallingIdentity(ident); } @@ -252,27 +129,22 @@ public class IncidentCompanionService extends SystemService { if (!DumpUtils.checkDumpPermission(getContext(), TAG, writer)) { return; } - if (args.length == 0) { - // Standard text dumpsys - final SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); - synchronized (mLock) { - final int size = mPending.size(); - writer.println("mPending: (" + size + ")"); - for (int i = 0; i < size; i++) { - final PendingReportRec entry = mPending.get(i); - writer.println(String.format(" %11d %s: %s", entry.addedRealtime, - df.format(new Date(entry.addedWalltime)), - entry.getUri().toString())); - } - } - } + mPendingReports.dump(fd, writer, args); } + /** + * Inside the binder interface class because we want to do all of the authorization + * here, before calling out to the helper objects. + */ private void enforceRequestAuthorizationPermission() { getContext().enforceCallingOrSelfPermission( android.Manifest.permission.REQUEST_INCIDENT_REPORT_APPROVAL, null); } + /** + * Inside the binder interface class because we want to do all of the authorization + * here, before calling out to the helper objects. + */ private void enforceAuthorizePermission() { getContext().enforceCallingOrSelfPermission( android.Manifest.permission.APPROVE_INCIDENT_REPORTS, null); @@ -285,8 +157,7 @@ public class IncidentCompanionService extends SystemService { */ public IncidentCompanionService(Context context) { super(context); - mPackageManager = context.getPackageManager(); - mAppOpsManager = context.getSystemService(AppOpsManager.class); + mPendingReports = new PendingReports(context); } /** @@ -307,239 +178,9 @@ public class IncidentCompanionService extends SystemService { super.onBootPhase(phase); switch (phase) { case SystemService.PHASE_BOOT_COMPLETED: - // Release the enqueued work. - mRequestQueue.start(); + mPendingReports.onBootCompleted(); break; } } - - /** - * Start the confirmation process. - */ - private void authorizeReportImpl(int callingUid, final String callingPackage, int flags, - final IIncidentAuthListener listener) { - // Enforce that the calling package pertains to the callingUid. - if (!isPackageInUid(callingUid, callingPackage)) { - Log.w(TAG, "Calling uid " + callingUid + " doesn't match package " - + callingPackage); - denyReportBeforeAddingRec(listener, callingPackage); - return; - } - - // Find the primary user of this device. - final int primaryUser = getAndValidateUser(); - if (primaryUser == UserHandle.USER_NULL) { - denyReportBeforeAddingRec(listener, callingPackage); - return; - } - - // Find the approver app (hint: it's PermissionController). - final ComponentName receiver = getApproverComponent(primaryUser); - if (receiver == null) { - // We couldn't find an approver... so deny the request here and now, before we - // do anything else. - denyReportBeforeAddingRec(listener, callingPackage); - return; - } - - // Save the record for when the PermissionController comes back to authorize it. - PendingReportRec rec = null; - synchronized (mLock) { - rec = new PendingReportRec(callingPackage, flags, listener); - mPending.add(rec); - } - - try { - listener.asBinder().linkToDeath(() -> { - Log.i(TAG, "Got death notification listener=" + listener); - cancelReportImpl(listener, receiver, primaryUser); - }, 0); - } catch (RemoteException ex) { - Log.e(TAG, "Remote died while trying to register death listener: " + rec.getUri()); - // First, remove from our list. - cancelReportImpl(listener, receiver, primaryUser); - } - - // Go tell Permission controller to start asking the user. - sendBroadcast(receiver, primaryUser); - } - - /** - * Cancel a pending report request (because of an explicit call to cancel) - */ - private void cancelReportImpl(IIncidentAuthListener listener) { - final int primaryUser = getAndValidateUser(); - final ComponentName receiver = getApproverComponent(primaryUser); - if (primaryUser != UserHandle.USER_NULL && receiver != null) { - cancelReportImpl(listener, receiver, primaryUser); - } - } - - /** - * Cancel a pending report request (either because of an explicit call to cancel - * by the calling app, or because of a binder death). - */ - private void cancelReportImpl(IIncidentAuthListener listener, ComponentName receiver, - int primaryUser) { - // First, remove from our list. - synchronized (mLock) { - removePendingReportRecLocked(listener); - } - // Second, call back to PermissionController to say it's canceled. - sendBroadcast(receiver, primaryUser); - } - - /** - * Send an extra copy of the broadcast, to tell them that the list has changed - * because of an addition or removal. This function is less aggressive than - * authorizeReportImpl in logging about failures, because this is for use in - * cleanup cases to keep the apps' list in sync with ours. - */ - private void sendBroadcast() { - final int primaryUser = getAndValidateUser(); - if (primaryUser == UserHandle.USER_NULL) { - return; - } - final ComponentName receiver = getApproverComponent(primaryUser); - if (receiver == null) { - return; - } - sendBroadcast(receiver, primaryUser); - } - - /** - * Send the confirmation broadcast. - */ - private void sendBroadcast(ComponentName receiver, int primaryUser) { - final Intent intent = new Intent(Intent.ACTION_PENDING_INCIDENT_REPORTS_CHANGED); - intent.setComponent(receiver); - - // Send it to the primary user. - getContext().sendBroadcastAsUser(intent, UserHandle.getUserHandleForUid(primaryUser), - android.Manifest.permission.APPROVE_INCIDENT_REPORTS); - } - - /** - * Remove a PendingReportRec keyed by uri, and return it. - */ - private PendingReportRec findAndRemovePendingReportRecLocked(String uriString) { - final Uri uri = Uri.parse(uriString); - final int id; - try { - final String idStr = uri.getQueryParameter(IncidentManager.URI_PARAM_ID); - id = Integer.parseInt(idStr); - } catch (NumberFormatException ex) { - Log.w(TAG, "Can't parse id from: " + uriString); - return null; - } - final int size = mPending.size(); - for (int i = 0; i < size; i++) { - final PendingReportRec rec = mPending.get(i); - if (rec.id == id) { - mPending.remove(i); - return rec; - } - } - return null; - } - - /** - * Remove a PendingReportRec keyed by listener. - */ - private void removePendingReportRecLocked(IIncidentAuthListener listener) { - final int size = mPending.size(); - for (int i = 0; i < size; i++) { - final PendingReportRec rec = mPending.get(i); - if (rec.listener.asBinder() == listener.asBinder()) { - Log.i(TAG, " ...Removed PendingReportRec index=" + i + ": " + rec.getUri()); - mPending.remove(i); - } - } - } - - /** - * Just call listener.deny() (wrapping the RemoteException), without try to - * add it to the list. - */ - private void denyReportBeforeAddingRec(IIncidentAuthListener listener, String pkg) { - try { - listener.onReportDenied(); - } catch (RemoteException ex) { - Log.w(TAG, "Failed calling back for denial for " + pkg, ex); - } - } - - /** - * Check whether the current user is the primary user, and return the user id if they are. - * Returns UserHandle.USER_NULL if not valid. - */ - private int getAndValidateUser() { - // Current user - UserInfo currentUser; - try { - currentUser = ActivityManager.getService().getCurrentUser(); - } catch (RemoteException ex) { - // We're already inside the system process. - throw new RuntimeException(ex); - } - - // Primary user - final UserManager um = UserManager.get(getContext()); - final UserInfo primaryUser = um.getPrimaryUser(); - - // Check that we're using the right user. - if (currentUser == null) { - Log.w(TAG, "No current user. Nobody to approve the report." - + " The report will be denied."); - return UserHandle.USER_NULL; - } - if (primaryUser == null) { - Log.w(TAG, "No primary user. Nobody to approve the report." - + " The report will be denied."); - return UserHandle.USER_NULL; - } - if (primaryUser.id != currentUser.id) { - Log.w(TAG, "Only the primary user can approve bugreports, but they are not" - + " the current user. The report will be denied."); - return UserHandle.USER_NULL; - } - - return primaryUser.id; - } - - /** - * Return the ComponentName of the BroadcastReceiver that will approve reports. - * The system must have zero or one of these installed. We only look on the - * system partition. When the broadcast happens, the component will also need - * have the APPROVE_INCIDENT_REPORTS permission. - */ - private ComponentName getApproverComponent(int userId) { - // Find the one true BroadcastReceiver - final Intent intent = new Intent(Intent.ACTION_PENDING_INCIDENT_REPORTS_CHANGED); - final List<ResolveInfo> matches = mPackageManager.queryBroadcastReceiversAsUser(intent, - PackageManager.MATCH_SYSTEM_ONLY | PackageManager.MATCH_DIRECT_BOOT_AWARE - | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId); - if (matches.size() == 1) { - return matches.get(0).getComponentInfo().getComponentName(); - } else { - Log.w(TAG, "Didn't find exactly one BroadcastReceiver to handle " - + Intent.ACTION_PENDING_INCIDENT_REPORTS_CHANGED - + ". The report will be denied. size=" - + matches.size() + ": matches=" + matches); - return null; - } - } - - /** - * Return whether the package is one of the packages installed for the uid. - */ - private boolean isPackageInUid(int uid, String packageName) { - try { - mAppOpsManager.checkPackage(uid, packageName); - return true; - } catch (SecurityException ex) { - return false; - } - } } diff --git a/services/core/java/com/android/server/incident/PendingReports.java b/services/core/java/com/android/server/incident/PendingReports.java new file mode 100644 index 000000000000..519ed41670f6 --- /dev/null +++ b/services/core/java/com/android/server/incident/PendingReports.java @@ -0,0 +1,477 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.incident; + +import android.app.ActivityManager; +import android.app.AppOpsManager; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.content.pm.UserInfo; +import android.net.Uri; +import android.os.Handler; +import android.os.IIncidentAuthListener; +import android.os.IncidentManager; +import android.os.RemoteException; +import android.os.SystemClock; +import android.os.UserHandle; +import android.os.UserManager; +import android.util.Log; + +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +// TODO: User changes should deny everything that's pending. + +/** + * Tracker for reports pending approval. + */ +class PendingReports { + static final String TAG = IncidentCompanionService.TAG; + + private final Handler mHandler = new Handler(); + private final RequestQueue mRequestQueue = new RequestQueue(mHandler); + private final Context mContext; + private final PackageManager mPackageManager; + private final AppOpsManager mAppOpsManager; + + // + // All fields below must be protected by mLock + // + private final Object mLock = new Object(); + private final ArrayList<PendingReportRec> mPending = new ArrayList(); + + /** + * The next ID we'll use when we make a PendingReportRec. + */ + private int mNextPendingId = 1; + + /** + * One for each authorization that's pending. + */ + private final class PendingReportRec { + public int id; + public String callingPackage; + public int flags; + public IIncidentAuthListener listener; + public long addedRealtime; + public long addedWalltime; + + /** + * Construct a PendingReportRec, with an auto-incremented id. + */ + PendingReportRec(String callingPackage, int flags, IIncidentAuthListener listener) { + this.id = mNextPendingId++; + this.callingPackage = callingPackage; + this.flags = flags; + this.listener = listener; + this.addedRealtime = SystemClock.elapsedRealtime(); + this.addedWalltime = System.currentTimeMillis(); + } + + /** + * Get the Uri that contains the flattened data. + */ + Uri getUri() { + return (new Uri.Builder()) + .scheme(IncidentManager.URI_SCHEME) + .authority(IncidentManager.URI_AUTHORITY) + .path(IncidentManager.URI_PATH) + .appendQueryParameter(IncidentManager.URI_PARAM_ID, Integer.toString(id)) + .appendQueryParameter(IncidentManager.URI_PARAM_CALLING_PACKAGE, callingPackage) + .appendQueryParameter(IncidentManager.URI_PARAM_FLAGS, Integer.toString(flags)) + .appendQueryParameter(IncidentManager.URI_PARAM_TIMESTAMP, + Long.toString(addedWalltime)) + .build(); + } + } + + /** + * Construct new PendingReports with the context. + */ + PendingReports(Context context) { + mContext = context; + mPackageManager = context.getPackageManager(); + mAppOpsManager = context.getSystemService(AppOpsManager.class); + } + + /** + * ONEWAY binder call to initiate authorizing the report. The actual logic is posted + * to mRequestQueue, and may happen later. + * <p> + * The security checks are handled by IncidentCompanionService. + */ + public void authorizeReport(int callingUid, final String callingPackage, final int flags, + final IIncidentAuthListener listener) { + // Starting the system server is complicated, and rather than try to + // have a complicated lifecycle that we share with dumpstated and incidentd, + // we will accept the request, and then display it whenever it becomes possible to. + mRequestQueue.enqueue(listener.asBinder(), true, () -> { + authorizeReportImpl(callingUid, callingPackage, flags, listener); + }); + } + + /** + * ONEWAY binder call to cancel the inbound authorization request. + * <p> + * This is a oneway call, and so is authorizeReport, so the + * caller's ordering is preserved. The other calls on this object are synchronous, so + * their ordering is not guaranteed with respect to these calls. So the implementation + * sends out extra broadcasts to allow for eventual consistency. + * <p> + * The security checks are handled by IncidentCompanionService. + */ + public void cancelAuthorization(final IIncidentAuthListener listener) { + mRequestQueue.enqueue(listener.asBinder(), false, () -> { + cancelReportImpl(listener); + }); + } + + /** + * SYNCHRONOUS binder call to get the list of reports that are pending confirmation + * by the user. + * <p> + * The security checks are handled by IncidentCompanionService. + */ + public List<String> getPendingReports() { + synchronized (mLock) { + final int size = mPending.size(); + final ArrayList<String> result = new ArrayList(size); + for (int i = 0; i < size; i++) { + result.add(mPending.get(i).getUri().toString()); + } + return result; + } + } + + /** + * SYNCHRONOUS binder call to mark a report as approved. + * <p> + * The security checks are handled by IncidentCompanionService. + */ + public void approveReport(String uri) { + final PendingReportRec rec; + synchronized (mLock) { + rec = findAndRemovePendingReportRecLocked(uri); + if (rec == null) { + Log.e(TAG, "confirmApproved: Couldn't find record for uri: " + uri); + return; + } + } + + // Re-do the broadcast, so whoever is listening knows the list changed, + // in case another one was added in the meantime. + sendBroadcast(); + + Log.i(TAG, "Approved report: " + uri); + try { + rec.listener.onReportApproved(); + } catch (RemoteException ex) { + Log.w(TAG, "Failed calling back for approval for: " + uri, ex); + } + } + + /** + * SYNCHRONOUS binder call to mark a report as NOT approved. + */ + public void denyReport(String uri) { + final PendingReportRec rec; + synchronized (mLock) { + rec = findAndRemovePendingReportRecLocked(uri); + if (rec == null) { + Log.e(TAG, "confirmDenied: Couldn't find record for uri: " + uri); + return; + } + } + + // Re-do the broadcast, so whoever is listening knows the list changed, + // in case another one was added in the meantime. + sendBroadcast(); + + Log.i(TAG, "Denied report: " + uri); + try { + rec.listener.onReportDenied(); + } catch (RemoteException ex) { + Log.w(TAG, "Failed calling back for denial for: " + uri, ex); + } + } + + /** + * Implementation of adb shell dumpsys debugreportcompanion. + */ + protected void dump(FileDescriptor fd, final PrintWriter writer, String[] args) { + if (args.length == 0) { + // Standard text dumpsys + final SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); + synchronized (mLock) { + final int size = mPending.size(); + writer.println("mPending: (" + size + ")"); + for (int i = 0; i < size; i++) { + final PendingReportRec entry = mPending.get(i); + writer.println(String.format(" %11d %s: %s", entry.addedRealtime, + df.format(new Date(entry.addedWalltime)), + entry.getUri().toString())); + } + } + } + } + + /** + * Handle the boot process... Starts everything running once the system is + * up enough for us to do UI. + */ + public void onBootCompleted() { + // Release the enqueued work. + mRequestQueue.start(); + } + + /** + * Start the confirmation process. + */ + private void authorizeReportImpl(int callingUid, final String callingPackage, int flags, + final IIncidentAuthListener listener) { + // Enforce that the calling package pertains to the callingUid. + if (!isPackageInUid(callingUid, callingPackage)) { + Log.w(TAG, "Calling uid " + callingUid + " doesn't match package " + + callingPackage); + denyReportBeforeAddingRec(listener, callingPackage); + return; + } + + // Find the primary user of this device. + final int primaryUser = getAndValidateUser(); + if (primaryUser == UserHandle.USER_NULL) { + denyReportBeforeAddingRec(listener, callingPackage); + return; + } + + // Find the approver app (hint: it's PermissionController). + final ComponentName receiver = getApproverComponent(primaryUser); + if (receiver == null) { + // We couldn't find an approver... so deny the request here and now, before we + // do anything else. + denyReportBeforeAddingRec(listener, callingPackage); + return; + } + + // Save the record for when the PermissionController comes back to authorize it. + PendingReportRec rec = null; + synchronized (mLock) { + rec = new PendingReportRec(callingPackage, flags, listener); + mPending.add(rec); + } + + try { + listener.asBinder().linkToDeath(() -> { + Log.i(TAG, "Got death notification listener=" + listener); + cancelReportImpl(listener, receiver, primaryUser); + }, 0); + } catch (RemoteException ex) { + Log.e(TAG, "Remote died while trying to register death listener: " + rec.getUri()); + // First, remove from our list. + cancelReportImpl(listener, receiver, primaryUser); + } + + // Go tell Permission controller to start asking the user. + sendBroadcast(receiver, primaryUser); + } + + /** + * Cancel a pending report request (because of an explicit call to cancel) + */ + private void cancelReportImpl(IIncidentAuthListener listener) { + final int primaryUser = getAndValidateUser(); + final ComponentName receiver = getApproverComponent(primaryUser); + if (primaryUser != UserHandle.USER_NULL && receiver != null) { + cancelReportImpl(listener, receiver, primaryUser); + } + } + + /** + * Cancel a pending report request (either because of an explicit call to cancel + * by the calling app, or because of a binder death). + */ + private void cancelReportImpl(IIncidentAuthListener listener, ComponentName receiver, + int primaryUser) { + // First, remove from our list. + synchronized (mLock) { + removePendingReportRecLocked(listener); + } + // Second, call back to PermissionController to say it's canceled. + sendBroadcast(receiver, primaryUser); + } + + /** + * Send an extra copy of the broadcast, to tell them that the list has changed + * because of an addition or removal. This function is less aggressive than + * authorizeReportImpl in logging about failures, because this is for use in + * cleanup cases to keep the apps' list in sync with ours. + */ + private void sendBroadcast() { + final int primaryUser = getAndValidateUser(); + if (primaryUser == UserHandle.USER_NULL) { + return; + } + final ComponentName receiver = getApproverComponent(primaryUser); + if (receiver == null) { + return; + } + sendBroadcast(receiver, primaryUser); + } + + /** + * Send the confirmation broadcast. + */ + private void sendBroadcast(ComponentName receiver, int primaryUser) { + final Intent intent = new Intent(Intent.ACTION_PENDING_INCIDENT_REPORTS_CHANGED); + intent.setComponent(receiver); + + // Send it to the primary user. + mContext.sendBroadcastAsUser(intent, UserHandle.getUserHandleForUid(primaryUser), + android.Manifest.permission.APPROVE_INCIDENT_REPORTS); + } + + /** + * Remove a PendingReportRec keyed by uri, and return it. + */ + private PendingReportRec findAndRemovePendingReportRecLocked(String uriString) { + final Uri uri = Uri.parse(uriString); + final int id; + try { + final String idStr = uri.getQueryParameter(IncidentManager.URI_PARAM_ID); + id = Integer.parseInt(idStr); + } catch (NumberFormatException ex) { + Log.w(TAG, "Can't parse id from: " + uriString); + return null; + } + final int size = mPending.size(); + for (int i = 0; i < size; i++) { + final PendingReportRec rec = mPending.get(i); + if (rec.id == id) { + mPending.remove(i); + return rec; + } + } + return null; + } + + /** + * Remove a PendingReportRec keyed by listener. + */ + private void removePendingReportRecLocked(IIncidentAuthListener listener) { + final int size = mPending.size(); + for (int i = 0; i < size; i++) { + final PendingReportRec rec = mPending.get(i); + if (rec.listener.asBinder() == listener.asBinder()) { + Log.i(TAG, " ...Removed PendingReportRec index=" + i + ": " + rec.getUri()); + mPending.remove(i); + } + } + } + + /** + * Just call listener.deny() (wrapping the RemoteException), without try to + * add it to the list. + */ + private void denyReportBeforeAddingRec(IIncidentAuthListener listener, String pkg) { + try { + listener.onReportDenied(); + } catch (RemoteException ex) { + Log.w(TAG, "Failed calling back for denial for " + pkg, ex); + } + } + + /** + * Check whether the current user is the primary user, and return the user id if they are. + * Returns UserHandle.USER_NULL if not valid. + */ + private int getAndValidateUser() { + // Current user + UserInfo currentUser; + try { + currentUser = ActivityManager.getService().getCurrentUser(); + } catch (RemoteException ex) { + // We're already inside the system process. + throw new RuntimeException(ex); + } + + // Primary user + final UserManager um = UserManager.get(mContext); + final UserInfo primaryUser = um.getPrimaryUser(); + + // Check that we're using the right user. + if (currentUser == null) { + Log.w(TAG, "No current user. Nobody to approve the report." + + " The report will be denied."); + return UserHandle.USER_NULL; + } + if (primaryUser == null) { + Log.w(TAG, "No primary user. Nobody to approve the report." + + " The report will be denied."); + return UserHandle.USER_NULL; + } + if (primaryUser.id != currentUser.id) { + Log.w(TAG, "Only the primary user can approve bugreports, but they are not" + + " the current user. The report will be denied."); + return UserHandle.USER_NULL; + } + + return primaryUser.id; + } + + /** + * Return the ComponentName of the BroadcastReceiver that will approve reports. + * The system must have zero or one of these installed. We only look on the + * system partition. When the broadcast happens, the component will also need + * have the APPROVE_INCIDENT_REPORTS permission. + */ + private ComponentName getApproverComponent(int userId) { + // Find the one true BroadcastReceiver + final Intent intent = new Intent(Intent.ACTION_PENDING_INCIDENT_REPORTS_CHANGED); + final List<ResolveInfo> matches = mPackageManager.queryBroadcastReceiversAsUser(intent, + PackageManager.MATCH_SYSTEM_ONLY | PackageManager.MATCH_DIRECT_BOOT_AWARE + | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId); + if (matches.size() == 1) { + return matches.get(0).getComponentInfo().getComponentName(); + } else { + Log.w(TAG, "Didn't find exactly one BroadcastReceiver to handle " + + Intent.ACTION_PENDING_INCIDENT_REPORTS_CHANGED + + ". The report will be denied. size=" + + matches.size() + ": matches=" + matches); + return null; + } + } + + /** + * Return whether the package is one of the packages installed for the uid. + */ + private boolean isPackageInUid(int uid, String packageName) { + try { + mAppOpsManager.checkPackage(uid, packageName); + return true; + } catch (SecurityException ex) { + return false; + } + } +} + diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java index c2ac27a5b737..62c4815a7de0 100644 --- a/services/core/java/com/android/server/pm/LauncherAppsService.java +++ b/services/core/java/com/android/server/pm/LauncherAppsService.java @@ -34,9 +34,11 @@ import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.ILauncherApps; import android.content.pm.IOnAppsChangedListener; +import android.content.pm.IPackageInstallerCallback; import android.content.pm.LauncherApps; import android.content.pm.LauncherApps.ShortcutQuery; import android.content.pm.PackageInfo; +import android.content.pm.PackageInstaller.SessionInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; import android.content.pm.ParceledListSlice; @@ -56,6 +58,7 @@ import android.os.IInterface; import android.os.ParcelFileDescriptor; import android.os.RemoteCallbackList; import android.os.RemoteException; +import android.os.ServiceManager; import android.os.UserHandle; import android.os.UserManager; import android.os.UserManagerInternal; @@ -153,6 +156,8 @@ public class LauncherAppsService extends SystemService { private final Object mVouchedSignaturesLocked = new Object(); + private PackageInstallerService mPackageInstallerService; + public LauncherAppsImpl(Context context) { mContext = context; mUm = (UserManager) mContext.getSystemService(Context.USER_SERVICE); @@ -204,8 +209,7 @@ public class LauncherAppsService extends SystemService { } /* - * @see android.content.pm.ILauncherApps#addOnAppsChangedListener( - * android.content.pm.IOnAppsChangedListener) + * @see android.content.pm.ILauncherApps#addOnAppsChangedListener */ @Override public void addOnAppsChangedListener(String callingPackage, IOnAppsChangedListener listener) @@ -228,8 +232,7 @@ public class LauncherAppsService extends SystemService { } /* - * @see android.content.pm.ILauncherApps#removeOnAppsChangedListener( - * android.content.pm.IOnAppsChangedListener) + * @see android.content.pm.ILauncherApps#removeOnAppsChangedListener */ @Override public void removeOnAppsChangedListener(IOnAppsChangedListener listener) @@ -246,6 +249,44 @@ public class LauncherAppsService extends SystemService { } /** + * @see android.content.pm.ILauncherApps#registerPackageInstallerCallback + */ + @Override + public void registerPackageInstallerCallback(String callingPackage, + IPackageInstallerCallback callback) { + verifyCallingPackage(callingPackage); + UserHandle callingIdUserHandle = new UserHandle(getCallingUserId()); + getPackageInstallerService().registerCallback(callback, eventUserId -> + isEnabledProfileOf(callingIdUserHandle, + new UserHandle(eventUserId), "shouldReceiveEvent")); + } + + @Override + public ParceledListSlice<SessionInfo> getAllSessions(String callingPackage) { + verifyCallingPackage(callingPackage); + List<SessionInfo> sessionInfos = new ArrayList<>(); + int[] userIds = mUm.getEnabledProfileIds(getCallingUserId()); + long token = Binder.clearCallingIdentity(); + try { + for (int userId : userIds) { + sessionInfos.addAll(getPackageInstallerService().getAllSessions(userId) + .getList()); + } + } finally { + Binder.restoreCallingIdentity(token); + } + return new ParceledListSlice<>(sessionInfos); + } + + private PackageInstallerService getPackageInstallerService() { + if (mPackageInstallerService == null) { + mPackageInstallerService = ((PackageInstallerService) ((PackageManagerService) + ServiceManager.getService("package")).getPackageInstaller()); + } + return mPackageInstallerService; + } + + /** * Register a receiver to watch for package broadcasts */ private void startWatchingPackageBroadcasts() { @@ -430,6 +471,9 @@ public class LauncherAppsService extends SystemService { if (!mVouchedSignaturesByUser.containsKey(user)) { initVouchedSignatures(user); } + if (isManagedProfileAdmin(user, appInfo.packageName)) { + return false; + } if (mVouchProviders.contains(appInfo.packageName)) { // If it's a vouching packages then we must show hidden app return true; @@ -453,6 +497,24 @@ public class LauncherAppsService extends SystemService { return true; } + private boolean isManagedProfileAdmin(UserHandle user, String packageName) { + final List<UserInfo> userInfoList = mUm.getProfiles(user.getIdentifier()); + for (int i = 0; i < userInfoList.size(); i++) { + UserInfo userInfo = userInfoList.get(i); + if (!userInfo.isManagedProfile()) { + continue; + } + ComponentName componentName = mDpm.getProfileOwnerAsUser(userInfo.getUserHandle()); + if (componentName == null) { + continue; + } + if (componentName.getPackageName().equals(packageName)) { + return true; + } + } + return false; + } + @VisibleForTesting static String computePackageCertDigest(Signature signature) { MessageDigest messageDigest; @@ -848,6 +910,29 @@ public class LauncherAppsService extends SystemService { } @Override + public void startSessionDetailsActivityAsUser(IApplicationThread caller, + String callingPackage, SessionInfo sessionInfo, Rect sourceBounds, + Bundle opts, UserHandle userHandle) throws RemoteException { + int userId = userHandle.getIdentifier(); + if (!canAccessProfile(userId, "Cannot start details activity")) { + return; + } + + Intent i = new Intent(Intent.ACTION_VIEW) + .setData(new Uri.Builder() + .scheme("market") + .authority("details") + .appendQueryParameter("id", sessionInfo.appPackageName) + .build()) + .putExtra(Intent.EXTRA_REFERRER, new Uri.Builder().scheme("android-app") + .authority(callingPackage).build()); + i.setSourceBounds(sourceBounds); + + mActivityTaskManagerInternal.startActivityAsUser(caller, callingPackage, i, opts, + userId); + } + + @Override public void startActivityAsUser(IApplicationThread caller, String callingPackage, ComponentName component, Rect sourceBounds, Bundle opts, UserHandle user) throws RemoteException { diff --git a/services/core/java/com/android/server/pm/OWNERS b/services/core/java/com/android/server/pm/OWNERS index 60d792530101..33b8641c145e 100644 --- a/services/core/java/com/android/server/pm/OWNERS +++ b/services/core/java/com/android/server/pm/OWNERS @@ -51,6 +51,8 @@ per-file UserManagerService.java = omakoto@google.com per-file UserManagerService.java = yamasani@google.com per-file UserRestrictionsUtils.java = omakoto@google.com per-file UserRestrictionsUtils.java = yamasani@google.com +per-file UserRestrictionsUtils.java = rubinxu@google.com +per-file UserRestrictionsUtils.java = sandness@google.com # security per-file KeySetHandle.java = cbrubaker@google.com diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java index 146a2f3d8433..a3e0d8db8ad5 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerService.java +++ b/services/core/java/com/android/server/pm/PackageInstallerService.java @@ -59,7 +59,6 @@ import android.os.Process; import android.os.RemoteCallbackList; import android.os.RemoteException; import android.os.SELinux; -import android.os.UserHandle; import android.os.UserManager; import android.os.storage.StorageManager; import android.system.ErrnoException; @@ -107,6 +106,7 @@ import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.Random; +import java.util.function.IntPredicate; /** The service responsible for installing packages. */ public class PackageInstallerService extends IPackageInstaller.Stub implements @@ -804,7 +804,14 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements public void registerCallback(IPackageInstallerCallback callback, int userId) { mPermissionManager.enforceCrossUserPermission( Binder.getCallingUid(), userId, true, false, "registerCallback"); - mCallbacks.register(callback, userId); + registerCallback(callback, eventUserId -> userId == eventUserId); + } + + /** + * Assume permissions already checked and caller's identity cleared + */ + public void registerCallback(IPackageInstallerCallback callback, IntPredicate userCheck) { + mCallbacks.register(callback, userCheck); } @Override @@ -1026,8 +1033,8 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements super(looper); } - public void register(IPackageInstallerCallback callback, int userId) { - mCallbacks.register(callback, new UserHandle(userId)); + public void register(IPackageInstallerCallback callback, IntPredicate userCheck) { + mCallbacks.register(callback, userCheck); } public void unregister(IPackageInstallerCallback callback) { @@ -1040,9 +1047,8 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements final int n = mCallbacks.beginBroadcast(); for (int i = 0; i < n; i++) { final IPackageInstallerCallback callback = mCallbacks.getBroadcastItem(i); - final UserHandle user = (UserHandle) mCallbacks.getBroadcastCookie(i); - // TODO: dispatch notifications for slave profiles - if (userId == user.getIdentifier()) { + final IntPredicate userCheck = (IntPredicate) mCallbacks.getBroadcastCookie(i); + if (userCheck.test(userId)) { try { invokeCallback(callback, msg); } catch (RemoteException ignored) { diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index 494ec3ff67aa..de0849fa9951 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -473,6 +473,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { final SessionInfo info = new SessionInfo(); synchronized (mLock) { info.sessionId = sessionId; + info.userId = userId; info.installerPackageName = mInstallerPackageName; info.resolvedBaseCodePath = (mResolvedBaseFile != null) ? mResolvedBaseFile.getAbsolutePath() : null; diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index 4f20590a47ff..d0f192d597c6 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -1109,14 +1109,7 @@ public class UserManagerService extends IUserManager.Stub { @Override public int getManagedProfileBadge(@UserIdInt int userId) { - int callingUserId = UserHandle.getCallingUserId(); - if (callingUserId != userId && !hasManageUsersPermission()) { - if (!isSameProfileGroupNoChecks(callingUserId, userId)) { - throw new SecurityException( - "You need MANAGE_USERS permission to: check if specified user a " + - "managed profile outside your profile group"); - } - } + checkManageOrInteractPermIfCallerInOtherProfileGroup(userId, "getManagedProfileBadge"); synchronized (mUsersLock) { UserInfo userInfo = getUserInfoLU(userId); return userInfo != null ? userInfo.profileBadge : 0; @@ -1125,14 +1118,7 @@ public class UserManagerService extends IUserManager.Stub { @Override public boolean isManagedProfile(int userId) { - int callingUserId = UserHandle.getCallingUserId(); - if (callingUserId != userId && !hasManageUsersPermission()) { - if (!isSameProfileGroupNoChecks(callingUserId, userId)) { - throw new SecurityException( - "You need MANAGE_USERS permission to: check if specified user a " + - "managed profile outside your profile group"); - } - } + checkManageOrInteractPermIfCallerInOtherProfileGroup(userId, "isManagedProfile"); synchronized (mUsersLock) { UserInfo userInfo = getUserInfoLU(userId); return userInfo != null && userInfo.isManagedProfile(); diff --git a/services/core/java/com/android/server/power/AttentionDetector.java b/services/core/java/com/android/server/power/AttentionDetector.java index a2c8dace9510..4186154016e2 100644 --- a/services/core/java/com/android/server/power/AttentionDetector.java +++ b/services/core/java/com/android/server/power/AttentionDetector.java @@ -24,11 +24,13 @@ import android.os.PowerManagerInternal; import android.os.SystemClock; import android.service.attention.AttentionService; import android.util.Slog; +import android.util.StatsLog; import com.android.internal.annotations.VisibleForTesting; import com.android.server.LocalServices; import java.io.PrintWriter; +import java.util.concurrent.atomic.AtomicLong; /** * Class responsible for checking if the user is currently paying attention to the phone and @@ -79,6 +81,11 @@ public class AttentionDetector { */ private int mWakefulness; + /** + * Describes how many times in a row was the timeout extended. + */ + private AtomicLong mConsecutiveTimeoutExtendedCount = new AtomicLong(0); + @VisibleForTesting final AttentionCallbackInternal mCallback = new AttentionCallbackInternal() { @@ -95,6 +102,8 @@ public class AttentionDetector { } if (result == AttentionService.ATTENTION_SUCCESS_PRESENT) { mOnUserAttention.run(); + } else { + resetConsecutiveExtensionCount(); } } } @@ -176,6 +185,7 @@ public class AttentionDetector { public int onUserActivity(long eventTime, int event) { switch (event) { case PowerManager.USER_ACTIVITY_EVENT_ATTENTION: + mConsecutiveTimeoutExtendedCount.incrementAndGet(); return 0; case PowerManager.USER_ACTIVITY_EVENT_OTHER: case PowerManager.USER_ACTIVITY_EVENT_BUTTON: @@ -183,6 +193,7 @@ public class AttentionDetector { case PowerManager.USER_ACTIVITY_EVENT_ACCESSIBILITY: cancelCurrentRequestIfAny(); mLastUserActivityTime = eventTime; + resetConsecutiveExtensionCount(); return 1; default: if (DEBUG) { @@ -196,6 +207,7 @@ public class AttentionDetector { mWakefulness = wakefulness; if (wakefulness != PowerManagerInternal.WAKEFULNESS_AWAKE) { cancelCurrentRequestIfAny(); + resetConsecutiveExtensionCount(); } } @@ -206,6 +218,13 @@ public class AttentionDetector { } } + private void resetConsecutiveExtensionCount() { + final long previousCount = mConsecutiveTimeoutExtendedCount.getAndSet(0); + if (previousCount > 0) { + StatsLog.write(StatsLog.SCREEN_TIMEOUT_EXTENSION_REPORTED, previousCount); + } + } + @VisibleForTesting int getRequestCode() { return (int) (mLastUserActivityTime % Integer.MAX_VALUE); diff --git a/services/core/java/com/android/server/role/RoleManagerService.java b/services/core/java/com/android/server/role/RoleManagerService.java index 03ec57b45acf..d72270e3f36d 100644 --- a/services/core/java/com/android/server/role/RoleManagerService.java +++ b/services/core/java/com/android/server/role/RoleManagerService.java @@ -52,6 +52,7 @@ import android.os.UserManagerInternal; import android.service.sms.FinancialSmsService; import android.telephony.IFinancialSmsCallback; import android.text.TextUtils; +import android.util.ArrayMap; import android.util.ArraySet; import android.util.PackageUtils; import android.util.Slog; @@ -145,6 +146,9 @@ public class RoleManagerService extends SystemService implements RoleUserState.C mUserManagerInternal = LocalServices.getService(UserManagerInternal.class); mAppOpsManager = context.getSystemService(AppOpsManager.class); + LocalServices.addService(RoleManagerServiceInternal.class, + new RoleManagerServiceInternalImpl()); + registerUserRemovedReceiver(); } @@ -382,6 +386,19 @@ public class RoleManagerService extends SystemService implements RoleUserState.C } } + /** + * Get all roles and packages hold them. + * + * @param user The user to query to roles for + * + * @return The roles and their holders + */ + @NonNull + private ArrayMap<String, ArraySet<String>> getRoleHoldersAsUser(@NonNull UserHandle user) { + RoleUserState userState = getOrCreateUserState(user.getIdentifier()); + return userState.getRoleHolders(); + } + private class Stub extends IRoleManager.Stub { @Override @@ -676,4 +693,16 @@ public class RoleManagerService extends SystemService implements RoleUserState.C } } } + + /** + * Entry point for internal calls into role manager + */ + private final class RoleManagerServiceInternalImpl extends RoleManagerServiceInternal { + + @NonNull + @Override + public ArrayMap<String, ArraySet<String>> getRoleHoldersAsUser(@NonNull UserHandle user) { + return RoleManagerService.this.getRoleHoldersAsUser(user); + } + } } diff --git a/services/core/java/com/android/server/role/RoleManagerServiceInternal.java b/services/core/java/com/android/server/role/RoleManagerServiceInternal.java new file mode 100644 index 000000000000..3afc3f731eb9 --- /dev/null +++ b/services/core/java/com/android/server/role/RoleManagerServiceInternal.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.role; + +import android.annotation.NonNull; +import android.os.UserHandle; +import android.util.ArrayMap; +import android.util.ArraySet; + +/** + * Internal calls into {@link RoleManagerService} + */ +public abstract class RoleManagerServiceInternal { + /** + * Get all roles and packages hold them. + * + * @param user The user to query to roles for + * + * @return The roles and their holders + */ + @NonNull + public abstract ArrayMap<String, ArraySet<String>> getRoleHoldersAsUser( + @NonNull UserHandle user); +} diff --git a/services/core/java/com/android/server/role/RoleUserState.java b/services/core/java/com/android/server/role/RoleUserState.java index 02dcc4945664..bc68dded2dfe 100644 --- a/services/core/java/com/android/server/role/RoleUserState.java +++ b/services/core/java/com/android/server/role/RoleUserState.java @@ -376,7 +376,7 @@ public class RoleUserState { version = mVersion; packagesHash = mPackagesHash; - roles = snapshotRolesLocked(); + roles = getRoleHolders(); } AtomicFile atomicFile = new AtomicFile(getFile(mUserId), "roles-" + mUserId); @@ -541,7 +541,7 @@ public class RoleUserState { version = mVersion; packagesHash = mPackagesHash; - roles = snapshotRolesLocked(); + roles = getRoleHolders(); } long fieldToken = dumpOutputStream.start(fieldName, fieldId); @@ -570,17 +570,24 @@ public class RoleUserState { dumpOutputStream.end(fieldToken); } - @GuardedBy("mLock") - private ArrayMap<String, ArraySet<String>> snapshotRolesLocked() { - ArrayMap<String, ArraySet<String>> roles = new ArrayMap<>(); - for (int i = 0, size = CollectionUtils.size(mRoles); i < size; ++i) { - String roleName = mRoles.keyAt(i); - ArraySet<String> roleHolders = mRoles.valueAt(i); - - roleHolders = new ArraySet<>(roleHolders); - roles.put(roleName, roleHolders); + /** + * Get the roles and their holders. + * + * @return A copy of the roles and their holders + */ + @NonNull + public ArrayMap<String, ArraySet<String>> getRoleHolders() { + synchronized (mLock) { + ArrayMap<String, ArraySet<String>> roles = new ArrayMap<>(); + for (int i = 0, size = CollectionUtils.size(mRoles); i < size; ++i) { + String roleName = mRoles.keyAt(i); + ArraySet<String> roleHolders = mRoles.valueAt(i); + + roleHolders = new ArraySet<>(roleHolders); + roles.put(roleName, roleHolders); + } + return roles; } - return roles; } /** diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java index c6d2870a24c9..2be78fe32f68 100644 --- a/services/core/java/com/android/server/stats/StatsCompanionService.java +++ b/services/core/java/com/android/server/stats/StatsCompanionService.java @@ -23,6 +23,7 @@ import static com.android.server.am.MemoryStatUtil.readCmdlineFromProcfs; import static com.android.server.am.MemoryStatUtil.readMemoryStatFromProcfs; import static com.android.server.am.MemoryStatUtil.readRssHighWaterMarkFromProcfs; +import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManagerInternal; import android.app.AlarmManager; @@ -83,6 +84,7 @@ import android.os.storage.StorageManager; import android.telephony.ModemActivityInfo; import android.telephony.TelephonyManager; import android.util.ArrayMap; +import android.util.ArraySet; import android.util.Log; import android.util.Slog; import android.util.StatsLog; @@ -112,6 +114,7 @@ import com.android.server.LocalServices; import com.android.server.SystemService; import com.android.server.SystemServiceManager; import com.android.server.am.MemoryStatUtil.MemoryStat; +import com.android.server.role.RoleManagerServiceInternal; import com.android.server.storage.DiskStatsFileLogger; import com.android.server.storage.DiskStatsLoggingService; @@ -1781,6 +1784,60 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { } /** + * Add a RoleHolder atom for each package that holds a role. + * + * @param elapsedNanos the time since boot + * @param wallClockNanos the time on the clock + * @param pulledData the data sink to write to + */ + private void pullRoleHolders(long elapsedNanos, final long wallClockNanos, + @NonNull List<StatsLogEventWrapper> pulledData) { + long callingToken = Binder.clearCallingIdentity(); + try { + PackageManager pm = mContext.getPackageManager(); + RoleManagerServiceInternal rm = + LocalServices.getService(RoleManagerServiceInternal.class); + + List<UserInfo> users = mContext.getSystemService(UserManager.class).getUsers(); + + int numUsers = users.size(); + for (int userNum = 0; userNum < numUsers; userNum++) { + UserHandle user = users.get(userNum).getUserHandle(); + + ArrayMap<String, ArraySet<String>> roles = rm.getRoleHoldersAsUser(user); + + int numRoles = roles.size(); + for (int roleNum = 0; roleNum < numRoles; roleNum++) { + String roleName = roles.keyAt(roleNum); + ArraySet<String> holders = roles.valueAt(roleNum); + + int numHolders = holders.size(); + for (int holderNum = 0; holderNum < numHolders; holderNum++) { + String holderName = holders.valueAt(holderNum); + + PackageInfo pkg; + try { + pkg = pm.getPackageInfoAsUser(holderName, 0, user.getIdentifier()); + } catch (PackageManager.NameNotFoundException e) { + Log.w(TAG, "Role holder " + holderName + " not found"); + return; + } + + StatsLogEventWrapper e = new StatsLogEventWrapper(StatsLog.ROLE_HOLDER, + elapsedNanos, wallClockNanos); + e.writeInt(pkg.applicationInfo.uid); + e.writeString(holderName); + e.writeString(roleName); + pulledData.add(e); + } + } + } + } finally { + Binder.restoreCallingIdentity(callingToken); + } + } + + /** * Pulls various data. */ @Override // Binder call @@ -1954,6 +2011,10 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { pullDebugFailingElapsedClock(tagId, elapsedNanos, wallClockNanos, ret); break; } + case StatsLog.ROLE_HOLDER: { + pullRoleHolders(elapsedNanos, wallClockNanos, ret); + break; + } default: Slog.w(TAG, "No such tagId data as " + tagId); return null; diff --git a/services/core/jni/com_android_server_security_VerityUtils.cpp b/services/core/jni/com_android_server_security_VerityUtils.cpp index 0d888dc41719..988d75cfb984 100644 --- a/services/core/jni/com_android_server_security_VerityUtils.cpp +++ b/services/core/jni/com_android_server_security_VerityUtils.cpp @@ -32,9 +32,67 @@ // TODO(112037636): Always include once fsverity.h is upstreamed. #if __has_include(<linux/fsverity.h>) #include <linux/fsverity.h> -const int kSha256Bytes = 32; +#else + +// Before fs-verity is upstreamed, use the current snapshot for development. +// https://git.kernel.org/pub/scm/linux/kernel/git/ebiggers/linux.git/tree/include/uapi/linux/fsverity.h?h=fsverity + +#include <linux/limits.h> +#include <linux/ioctl.h> +#include <linux/types.h> + +struct fsverity_digest { + __u16 digest_algorithm; + __u16 digest_size; /* input/output */ + __u8 digest[]; +}; + +#define FS_IOC_ENABLE_VERITY _IO('f', 133) +#define FS_IOC_MEASURE_VERITY _IOWR('f', 134, struct fsverity_digest) + +#define FS_VERITY_MAGIC "FSVerity" + +#define FS_VERITY_ALG_SHA256 1 + +struct fsverity_descriptor { + __u8 magic[8]; /* must be FS_VERITY_MAGIC */ + __u8 major_version; /* must be 1 */ + __u8 minor_version; /* must be 0 */ + __u8 log_data_blocksize;/* log2(data-bytes-per-hash), e.g. 12 for 4KB */ + __u8 log_tree_blocksize;/* log2(tree-bytes-per-hash), e.g. 12 for 4KB */ + __le16 data_algorithm; /* hash algorithm for data blocks */ + __le16 tree_algorithm; /* hash algorithm for tree blocks */ + __le32 flags; /* flags */ + __le32 __reserved1; /* must be 0 */ + __le64 orig_file_size; /* size of the original file data */ + __le16 auth_ext_count; /* number of authenticated extensions */ + __u8 __reserved2[30]; /* must be 0 */ +}; + +#define FS_VERITY_EXT_ROOT_HASH 1 +#define FS_VERITY_EXT_PKCS7_SIGNATURE 3 + +struct fsverity_extension { + __le32 length; + __le16 type; /* Type of this extension (see codes above) */ + __le16 __reserved; /* Reserved, must be 0 */ +}; + +struct fsverity_digest_disk { + __le16 digest_algorithm; + __le16 digest_size; + __u8 digest[]; +}; + +struct fsverity_footer { + __le32 desc_reverse_offset; /* distance to fsverity_descriptor */ + __u8 magic[8]; /* FS_VERITY_MAGIC */ +} __packed; + #endif +const int kSha256Bytes = 32; + namespace android { namespace { @@ -73,7 +131,6 @@ class JavaByteArrayHolder { }; int enableFsverity(JNIEnv* env, jobject /* clazz */, jstring filePath) { -#if __has_include(<linux/fsverity.h>) const char* path = env->GetStringUTFChars(filePath, nullptr); ::android::base::unique_fd rfd(open(path, O_RDONLY | O_CLOEXEC)); if (rfd.get() < 0) { @@ -83,14 +140,9 @@ int enableFsverity(JNIEnv* env, jobject /* clazz */, jstring filePath) { return errno; } return 0; -#else - LOG_ALWAYS_FATAL("fs-verity is used while not enabled"); - return ENOSYS; -#endif } int measureFsverity(JNIEnv* env, jobject /* clazz */, jstring filePath) { -#if __has_include(<linux/fsverity.h>) auto raii = JavaByteArrayHolder::newArray(env, sizeof(fsverity_digest) + kSha256Bytes); fsverity_digest* data = reinterpret_cast<fsverity_digest*>(raii->getRaw()); data->digest_size = kSha256Bytes; // the only input/output parameter @@ -104,14 +156,9 @@ int measureFsverity(JNIEnv* env, jobject /* clazz */, jstring filePath) { return errno; } return 0; -#else - LOG_ALWAYS_FATAL("fs-verity is used while not enabled"); - return ENOSYS; -#endif } jbyteArray constructFsveritySignedData(JNIEnv* env, jobject /* clazz */, jbyteArray digest) { -#if __has_include(<linux/fsverity.h>) auto raii = JavaByteArrayHolder::newArray(env, sizeof(fsverity_digest_disk) + kSha256Bytes); fsverity_digest_disk* data = reinterpret_cast<fsverity_digest_disk*>(raii->getRaw()); @@ -126,15 +173,10 @@ jbyteArray constructFsveritySignedData(JNIEnv* env, jobject /* clazz */, jbyteAr memcpy(data->digest, src, kSha256Bytes); return raii->release(); -#else - LOG_ALWAYS_FATAL("fs-verity is used while not enabled"); - return 0; -#endif } jbyteArray constructFsverityDescriptor(JNIEnv* env, jobject /* clazz */, jlong fileSize) { -#if __has_include(<linux/fsverity.h>) auto raii = JavaByteArrayHolder::newArray(env, sizeof(fsverity_descriptor)); fsverity_descriptor* desc = reinterpret_cast<fsverity_descriptor*>(raii->getRaw()); @@ -150,15 +192,10 @@ jbyteArray constructFsverityDescriptor(JNIEnv* env, jobject /* clazz */, jlong f desc->auth_ext_count = 1; return raii->release(); -#else - LOG_ALWAYS_FATAL("fs-verity is used while not enabled"); - return 0; -#endif } jbyteArray constructFsverityExtension(JNIEnv* env, jobject /* clazz */, jshort extensionId, jint extensionDataSize) { -#if __has_include(<linux/fsverity.h>) auto raii = JavaByteArrayHolder::newArray(env, sizeof(fsverity_extension)); fsverity_extension* ext = reinterpret_cast<fsverity_extension*>(raii->getRaw()); @@ -166,15 +203,10 @@ jbyteArray constructFsverityExtension(JNIEnv* env, jobject /* clazz */, jshort e ext->type = extensionId; return raii->release(); -#else - LOG_ALWAYS_FATAL("fs-verity is used while not enabled"); - return 0; -#endif } jbyteArray constructFsverityFooter(JNIEnv* env, jobject /* clazz */, jint offsetToDescriptorHead) { -#if __has_include(<linux/fsverity.h>) auto raii = JavaByteArrayHolder::newArray(env, sizeof(fsverity_footer)); fsverity_footer* footer = reinterpret_cast<fsverity_footer*>(raii->getRaw()); @@ -182,10 +214,6 @@ jbyteArray constructFsverityFooter(JNIEnv* env, jobject /* clazz */, memcpy(footer->magic, FS_VERITY_MAGIC, sizeof(footer->magic)); return raii->release(); -#else - LOG_ALWAYS_FATAL("fs-verity is used while not enabled"); - return 0; -#endif } const JNINativeMethod sMethods[] = { diff --git a/services/tests/servicestests/src/com/android/server/am/AppCompactorTest.java b/services/tests/servicestests/src/com/android/server/am/AppCompactorTest.java index 1a231cf56921..2f8e5456a695 100644 --- a/services/tests/servicestests/src/com/android/server/am/AppCompactorTest.java +++ b/services/tests/servicestests/src/com/android/server/am/AppCompactorTest.java @@ -18,6 +18,7 @@ package com.android.server.am; import static android.provider.DeviceConfig.ActivityManager.KEY_COMPACT_ACTION_1; import static android.provider.DeviceConfig.ActivityManager.KEY_COMPACT_ACTION_2; +import static android.provider.DeviceConfig.ActivityManager.KEY_COMPACT_STATSD_SAMPLE_RATE; import static android.provider.DeviceConfig.ActivityManager.KEY_COMPACT_THROTTLE_1; import static android.provider.DeviceConfig.ActivityManager.KEY_COMPACT_THROTTLE_2; import static android.provider.DeviceConfig.ActivityManager.KEY_COMPACT_THROTTLE_3; @@ -61,6 +62,9 @@ import java.util.concurrent.TimeUnit; @RunWith(AndroidJUnit4.class) public final class AppCompactorTest { + private static final String CLEAR_DEVICE_CONFIG_KEY_CMD = + "device_config delete activity_manager"; + @Mock private AppOpsService mAppOpsService; private AppCompactor mCompactorUnderTest; private HandlerThread mHandlerThread; @@ -70,19 +74,21 @@ public final class AppCompactorTest { private static void clearDeviceConfig() throws IOException { UiDevice uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()); uiDevice.executeShellCommand( - "device_config delete activity_manager " + KEY_USE_COMPACTION); + CLEAR_DEVICE_CONFIG_KEY_CMD + " " + KEY_USE_COMPACTION); + uiDevice.executeShellCommand( + CLEAR_DEVICE_CONFIG_KEY_CMD + " " + KEY_COMPACT_ACTION_1); uiDevice.executeShellCommand( - "device_config delete activity_manager " + KEY_COMPACT_ACTION_1); + CLEAR_DEVICE_CONFIG_KEY_CMD + " " + KEY_COMPACT_ACTION_2); uiDevice.executeShellCommand( - "device_config delete activity_manager " + KEY_COMPACT_ACTION_2); + CLEAR_DEVICE_CONFIG_KEY_CMD + " " + KEY_COMPACT_THROTTLE_1); uiDevice.executeShellCommand( - "device_config delete activity_manager " + KEY_COMPACT_THROTTLE_1); + CLEAR_DEVICE_CONFIG_KEY_CMD + " " + KEY_COMPACT_THROTTLE_2); uiDevice.executeShellCommand( - "device_config delete activity_manager " + KEY_COMPACT_THROTTLE_2); + CLEAR_DEVICE_CONFIG_KEY_CMD + " " + KEY_COMPACT_THROTTLE_3); uiDevice.executeShellCommand( - "device_config delete activity_manager " + KEY_COMPACT_THROTTLE_3); + CLEAR_DEVICE_CONFIG_KEY_CMD + " " + KEY_COMPACT_THROTTLE_4); uiDevice.executeShellCommand( - "device_config delete activity_manager " + KEY_COMPACT_THROTTLE_4); + CLEAR_DEVICE_CONFIG_KEY_CMD + " " + KEY_COMPACT_STATSD_SAMPLE_RATE); } @Before @@ -128,6 +134,8 @@ public final class AppCompactorTest { is(AppCompactor.DEFAULT_COMPACT_THROTTLE_3)); assertThat(mCompactorUnderTest.mCompactThrottleFullFull, is(AppCompactor.DEFAULT_COMPACT_THROTTLE_4)); + assertThat(mCompactorUnderTest.mStatsdSampleRate, + is(AppCompactor.DEFAULT_STATSD_SAMPLE_RATE)); } @Test @@ -155,6 +163,9 @@ public final class AppCompactorTest { DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE, KEY_COMPACT_THROTTLE_4, Long.toString(AppCompactor.DEFAULT_COMPACT_THROTTLE_4 + 1), false); + DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE, + KEY_COMPACT_STATSD_SAMPLE_RATE, + Float.toString(AppCompactor.DEFAULT_STATSD_SAMPLE_RATE + 0.1f), false); // Then calling init will read and set that flag. mCompactorUnderTest.init(); @@ -173,6 +184,8 @@ public final class AppCompactorTest { is(AppCompactor.DEFAULT_COMPACT_THROTTLE_3 + 1)); assertThat(mCompactorUnderTest.mCompactThrottleFullFull, is(AppCompactor.DEFAULT_COMPACT_THROTTLE_4 + 1)); + assertThat(mCompactorUnderTest.mStatsdSampleRate, + is(AppCompactor.DEFAULT_STATSD_SAMPLE_RATE + 0.1f)); } @Test @@ -365,6 +378,63 @@ public final class AppCompactorTest { is(AppCompactor.DEFAULT_COMPACT_THROTTLE_4)); } + @Test + public void statsdSampleRate_listensToDeviceConfigChanges() throws InterruptedException { + mCompactorUnderTest.init(); + + // When we override mStatsdSampleRate with a reasonable values ... + mCountDown = new CountDownLatch(1); + DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE, + KEY_COMPACT_STATSD_SAMPLE_RATE, + Float.toString(AppCompactor.DEFAULT_STATSD_SAMPLE_RATE + 0.1f), false); + assertThat(mCountDown.await(5, TimeUnit.SECONDS), is(true)); + + // Then that override is reflected in the compactor. + assertThat(mCompactorUnderTest.mStatsdSampleRate, + is(AppCompactor.DEFAULT_STATSD_SAMPLE_RATE + 0.1f)); + } + + @Test + public void statsdSanokeRate_listensToDeviceConfigChangesBadValues() + throws InterruptedException { + mCompactorUnderTest.init(); + + // When we override mStatsdSampleRate with a reasonable values ... + mCountDown = new CountDownLatch(1); + DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE, + KEY_COMPACT_STATSD_SAMPLE_RATE, "foo", false); + assertThat(mCountDown.await(5, TimeUnit.SECONDS), is(true)); + + // Then that override is reflected in the compactor. + assertThat(mCompactorUnderTest.mStatsdSampleRate, + is(AppCompactor.DEFAULT_STATSD_SAMPLE_RATE)); + } + + @Test + public void statsdSanokeRate_listensToDeviceConfigChangesOutOfRangeValues() + throws InterruptedException { + mCompactorUnderTest.init(); + + // When we override mStatsdSampleRate with an value outside of [0..1]... + mCountDown = new CountDownLatch(1); + DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE, + KEY_COMPACT_STATSD_SAMPLE_RATE, + Float.toString(-1.0f), false); + assertThat(mCountDown.await(5, TimeUnit.SECONDS), is(true)); + + // Then the values is capped in the range. + assertThat(mCompactorUnderTest.mStatsdSampleRate, is(0.0f)); + + mCountDown = new CountDownLatch(1); + DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE, + KEY_COMPACT_STATSD_SAMPLE_RATE, + Float.toString(1.01f), false); + assertThat(mCountDown.await(5, TimeUnit.SECONDS), is(true)); + + // Then the values is capped in the range. + assertThat(mCompactorUnderTest.mStatsdSampleRate, is(1.0f)); + } + private class TestInjector extends Injector { @Override public AppOpsService getAppOpsService(File file, Handler handler) { diff --git a/startop/iorap/src/com/google/android/startop/iorap/IorapForwardingService.java b/startop/iorap/src/com/google/android/startop/iorap/IorapForwardingService.java index 9a30b35f02a2..22fc15985b05 100644 --- a/startop/iorap/src/com/google/android/startop/iorap/IorapForwardingService.java +++ b/startop/iorap/src/com/google/android/startop/iorap/IorapForwardingService.java @@ -50,8 +50,8 @@ public class IorapForwardingService extends SystemService { public static final String TAG = "IorapForwardingService"; /** $> adb shell 'setprop log.tag.IorapdForwardingService VERBOSE' */ public static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); - /** $> adb shell 'setprop iorapd.enable true' */ - private static boolean IS_ENABLED = SystemProperties.getBoolean("iorapd.enable", true); + /** $> adb shell 'setprop ro.iorapd.enable true' */ + private static boolean IS_ENABLED = SystemProperties.getBoolean("ro.iorapd.enable", true); /** $> adb shell 'setprop iorapd.forwarding_service.wtf_crash true' */ private static boolean WTF_CRASH = SystemProperties.getBoolean( "iorapd.forwarding_service.wtf_crash", false); diff --git a/telephony/java/android/telephony/NetworkService.java b/telephony/java/android/telephony/NetworkService.java index 4bca404d9444..6c45cc4ef3b8 100644 --- a/telephony/java/android/telephony/NetworkService.java +++ b/telephony/java/android/telephony/NetworkService.java @@ -16,6 +16,7 @@ package android.telephony; +import android.annotation.NonNull; import android.annotation.SystemApi; import android.app.Service; import android.content.Intent; @@ -112,13 +113,13 @@ public abstract class NetworkService extends Service { mSlotId, 0, null).sendToTarget(); } - private void registerForStateChanged(INetworkServiceCallback callback) { + private void registerForStateChanged(@NonNull INetworkServiceCallback callback) { synchronized (mNetworkRegistrationStateChangedCallbacks) { mNetworkRegistrationStateChangedCallbacks.add(callback); } } - private void unregisterForStateChanged(INetworkServiceCallback callback) { + private void unregisterForStateChanged(@NonNull INetworkServiceCallback callback) { synchronized (mNetworkRegistrationStateChangedCallbacks) { mNetworkRegistrationStateChangedCallbacks.remove(callback); } diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java index 869cf1cf9e14..dfe36efcd5d1 100644 --- a/telephony/java/android/telephony/SubscriptionManager.java +++ b/telephony/java/android/telephony/SubscriptionManager.java @@ -2577,8 +2577,14 @@ public class SubscriptionManager { @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setPreferredDataSubscriptionId(int subId) { if (VDBG) logd("[setPreferredDataSubscriptionId]+ subId:" + subId); - setSubscriptionPropertyHelper(DEFAULT_SUBSCRIPTION_ID, "setPreferredDataSubscriptionId", - (iSub)-> iSub.setPreferredDataSubscriptionId(subId)); + try { + ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); + if (iSub != null) { + iSub.setPreferredDataSubscriptionId(subId); + } + } catch (RemoteException ex) { + // ignore it + } } /** diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index dfdec4db0c91..a1fb09017bcd 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -72,6 +72,7 @@ import android.telephony.ims.feature.MmTelFeature; import android.telephony.ims.stub.ImsRegistrationImplBase; import android.text.TextUtils; import android.util.Log; +import android.util.Pair; import com.android.ims.internal.IImsServiceFeatureCallback; import com.android.internal.annotations.VisibleForTesting; @@ -3264,6 +3265,35 @@ public class TelephonyManager { } } + /** + * Get the mapping from logical slots to physical slots. The mapping represent by a pair list. + * The key of the piar is the logical slot id and the value of the pair is the physical + * slots id mapped to this logical slot id. + * + * @return an pair list indicates the mapping from logical slots to physical slots. The size of + * the list should be {@link #getPhoneCount()} if success, otherwise return an empty list. + * + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @NonNull + public List<Pair<Integer, Integer>> getLogicalToPhysicalSlotMapping() { + List<Pair<Integer, Integer>> slotMapping = new ArrayList<>(); + try { + ITelephony telephony = getITelephony(); + if (telephony != null) { + int[] slotMappingArray = telephony.getSlotsMapping(); + for (int i = 0; i < slotMappingArray.length; i++) { + slotMapping.add(new Pair(i, slotMappingArray[i])); + } + } + } catch (RemoteException e) { + Log.e(TAG, "getSlotsMapping RemoteException", e); + } + return slotMapping; + } + // // // Subscriber Info @@ -10239,4 +10269,24 @@ public class TelephonyManager { Rlog.e(TAG, "switchMultiSimConfig RemoteException", ex); } } + + /** + * Get whether reboot is required or not after making changes to modem configurations. + * @Return {@code True} if reboot is required after making changes to modem configurations, + * otherwise return {@code False}. + * + * @hide + */ + @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + public boolean isRebootRequiredForModemConfigChange() { + try { + ITelephony service = getITelephony(); + if (service != null) { + return service.isRebootRequiredForModemConfigChange(); + } + } catch (RemoteException e) { + Log.e(TAG, "isRebootRequiredForModemConfigChange RemoteException", e); + } + return false; + } } diff --git a/telephony/java/android/telephony/data/DataService.java b/telephony/java/android/telephony/data/DataService.java index 74d1e838f186..79572b9706a9 100644 --- a/telephony/java/android/telephony/data/DataService.java +++ b/telephony/java/android/telephony/data/DataService.java @@ -157,7 +157,10 @@ public abstract class DataService extends Service { @Nullable LinkProperties linkProperties, @Nullable DataServiceCallback callback) { // The default implementation is to return unsupported. - callback.onSetupDataCallComplete(DataServiceCallback.RESULT_ERROR_UNSUPPORTED, null); + if (callback != null) { + callback.onSetupDataCallComplete(DataServiceCallback.RESULT_ERROR_UNSUPPORTED, + null); + } } /** @@ -176,7 +179,9 @@ public abstract class DataService extends Service { public void deactivateDataCall(int cid, @DeactivateDataReason int reason, @Nullable DataServiceCallback callback) { // The default implementation is to return unsupported. - callback.onDeactivateDataCallComplete(DataServiceCallback.RESULT_ERROR_UNSUPPORTED); + if (callback != null) { + callback.onDeactivateDataCallComplete(DataServiceCallback.RESULT_ERROR_UNSUPPORTED); + } } /** @@ -190,7 +195,10 @@ public abstract class DataService extends Service { public void setInitialAttachApn(DataProfile dataProfile, boolean isRoaming, @Nullable DataServiceCallback callback) { // The default implementation is to return unsupported. - callback.onSetInitialAttachApnComplete(DataServiceCallback.RESULT_ERROR_UNSUPPORTED); + if (callback != null) { + callback.onSetInitialAttachApnComplete( + DataServiceCallback.RESULT_ERROR_UNSUPPORTED); + } } /** @@ -206,7 +214,9 @@ public abstract class DataService extends Service { public void setDataProfile(List<DataProfile> dps, boolean isRoaming, @Nullable DataServiceCallback callback) { // The default implementation is to return unsupported. - callback.onSetDataProfileComplete(DataServiceCallback.RESULT_ERROR_UNSUPPORTED); + if (callback != null) { + callback.onSetDataProfileComplete(DataServiceCallback.RESULT_ERROR_UNSUPPORTED); + } } /** diff --git a/telephony/java/com/android/internal/telephony/ISub.aidl b/telephony/java/com/android/internal/telephony/ISub.aidl index a49d2d976d16..6ce9de4ca677 100755 --- a/telephony/java/com/android/internal/telephony/ISub.aidl +++ b/telephony/java/com/android/internal/telephony/ISub.aidl @@ -220,7 +220,7 @@ interface ISub { * @hide * */ - int setPreferredDataSubscriptionId(int subId); + void setPreferredDataSubscriptionId(int subId); /** * Get which subscription is preferred for cellular data. diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index 927c676aefe6..762d8860afcd 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -1848,4 +1848,14 @@ interface ITelephony { * @hide */ int getNumOfActiveSims(); + + /** + * Get if reboot is required upon altering modems configurations + */ + boolean isRebootRequiredForModemConfigChange(); + + /** + * Get the mapping from logical slots to physical slots. + */ + int[] getSlotsMapping(); } diff --git a/telephony/java/com/android/internal/telephony/TelephonyProperties.java b/telephony/java/com/android/internal/telephony/TelephonyProperties.java index 6567ea764b50..603c4c2870d7 100644 --- a/telephony/java/com/android/internal/telephony/TelephonyProperties.java +++ b/telephony/java/com/android/internal/telephony/TelephonyProperties.java @@ -194,6 +194,13 @@ public interface TelephonyProperties */ static final String PROPERTY_MULTI_SIM_CONFIG = "persist.radio.multisim.config"; + /** + * Property to indicate if reboot is required when changing modems configurations + * Type: String(true, false) default is false; most devices don't need reboot + */ + String PROPERTY_REBOOT_REQUIRED_ON_MODEM_CHANGE = + "persist.radio.reboot_on_modem_change"; + /** * Property to store default subscription. */ |