diff options
132 files changed, 3952 insertions, 1760 deletions
diff --git a/apex/media/framework/java/android/media/MediaParser.java b/apex/media/framework/java/android/media/MediaParser.java index 0d9cbf0edf03..0ff55dabbaae 100644 --- a/apex/media/framework/java/android/media/MediaParser.java +++ b/apex/media/framework/java/android/media/MediaParser.java @@ -443,60 +443,64 @@ public final class MediaParser { // Public constants. /** - * Sets whether constant bitrate seeking should be enabled for exo.AdtsParser. {@code boolean} + * Sets whether constant bitrate seeking should be enabled for ADTS parsing. {@code boolean} * expected. Default value is {@code false}. */ public static final String PARAMETER_ADTS_ENABLE_CBR_SEEKING = - "exo.AdtsParser.enableCbrSeeking"; + "android.media.mediaparser.adts.enableCbrSeeking"; /** - * Sets whether constant bitrate seeking should be enabled for exo.AmrParser. {@code boolean} - * expected. Default value is {@code false}. + * Sets whether constant bitrate seeking should be enabled for AMR. {@code boolean} expected. + * Default value is {@code false}. */ - public static final String PARAMETER_AMR_ENABLE_CBR_SEEKING = "exo.AmrParser.enableCbrSeeking"; + public static final String PARAMETER_AMR_ENABLE_CBR_SEEKING = + "android.media.mediaparser.amr.enableCbrSeeking"; /** - * Sets whether the ID3 track should be disabled for exo.FlacParser. {@code boolean} expected. - * Default value is {@code false}. + * Sets whether the ID3 track should be disabled for FLAC. {@code boolean} expected. Default + * value is {@code false}. */ - public static final String PARAMETER_FLAC_DISABLE_ID3 = "exo.FlacParser.disableId3"; + public static final String PARAMETER_FLAC_DISABLE_ID3 = + "android.media.mediaparser.flac.disableId3"; /** - * Sets whether exo.FragmentedMp4Parser should ignore edit lists. {@code boolean} expected. - * Default value is {@code false}. + * Sets whether MP4 parsing should ignore edit lists. {@code boolean} expected. Default value is + * {@code false}. */ - public static final String PARAMETER_FMP4_IGNORE_EDIT_LISTS = - "exo.FragmentedMp4Parser.ignoreEditLists"; + public static final String PARAMETER_MP4_IGNORE_EDIT_LISTS = + "android.media.mediaparser.mp4.ignoreEditLists"; /** - * Sets whether exo.FragmentedMp4Parser should ignore the tfdt box. {@code boolean} expected. - * Default value is {@code false}. + * Sets whether MP4 parsing should ignore the tfdt box. {@code boolean} expected. Default value + * is {@code false}. */ - public static final String PARAMETER_FMP4_IGNORE_TFDT_BOX = - "exo.FragmentedMp4Parser.ignoreTfdtBox"; + public static final String PARAMETER_MP4_IGNORE_TFDT_BOX = + "android.media.mediaparser.mp4.ignoreTfdtBox"; /** - * Sets whether exo.FragmentedMp4Parser should treat all video frames as key frames. {@code - * boolean} expected. Default value is {@code false}. + * Sets whether MP4 parsing should treat all video frames as key frames. {@code boolean} + * expected. Default value is {@code false}. */ - public static final String PARAMETER_FMP4_TREAT_VIDEO_FRAMES_AS_KEYFRAMES = - "exo.FragmentedMp4Parser.treatVideoFramesAsKeyframes"; + public static final String PARAMETER_MP4_TREAT_VIDEO_FRAMES_AS_KEYFRAMES = + "android.media.mediaparser.mp4.treatVideoFramesAsKeyframes"; /** - * Sets whether exo.MatroskaParser should avoid seeking to the cues element. {@code boolean} + * Sets whether Matroska parsing should avoid seeking to the cues element. {@code boolean} * expected. Default value is {@code false}. * * <p>If this flag is enabled and the cues element occurs after the first cluster, then the * media is treated as unseekable. */ public static final String PARAMETER_MATROSKA_DISABLE_CUES_SEEKING = - "exo.MatroskaParser.disableCuesSeeking"; + "android.media.mediaparser.matroska.disableCuesSeeking"; /** - * Sets whether the ID3 track should be disabled for exo.Mp3Parser. {@code boolean} expected. - * Default value is {@code false}. + * Sets whether the ID3 track should be disabled for MP3. {@code boolean} expected. Default + * value is {@code false}. */ - public static final String PARAMETER_MP3_DISABLE_ID3 = "exo.Mp3Parser.disableId3"; + public static final String PARAMETER_MP3_DISABLE_ID3 = + "android.media.mediaparser.mp3.disableId3"; /** - * Sets whether constant bitrate seeking should be enabled for exo.Mp3Parser. {@code boolean} - * expected. Default value is {@code false}. + * Sets whether constant bitrate seeking should be enabled for MP3. {@code boolean} expected. + * Default value is {@code false}. */ - public static final String PARAMETER_MP3_ENABLE_CBR_SEEKING = "exo.Mp3Parser.enableCbrSeeking"; + public static final String PARAMETER_MP3_ENABLE_CBR_SEEKING = + "android.media.mediaparser.mp3.enableCbrSeeking"; /** - * Sets whether exo.Mp3Parser should generate a time-to-byte mapping. {@code boolean} expected. + * Sets whether MP3 parsing should generate a time-to-byte mapping. {@code boolean} expected. * Default value is {@code false}. * * <p>Enabling this flag may require to scan a significant portion of the file to compute a seek @@ -509,18 +513,13 @@ public final class MediaParser { * </ul> */ public static final String PARAMETER_MP3_ENABLE_INDEX_SEEKING = - "exo.Mp3Parser.enableIndexSeeking"; + "android.media.mediaparser.mp3.enableIndexSeeking"; /** - * Sets whether exo.Mp4Parser should ignore edit lists. {@code boolean} expected. Default value - * is {@code false}. - */ - public static final String PARAMETER_MP4_IGNORE_EDIT_LISTS = "exo.Mp4Parser.ignoreEditLists"; - /** - * Sets the operation mode for exo.TsParser. {@code String} expected. Valid values are {@code + * Sets the operation mode for TS parsing. {@code String} expected. Valid values are {@code * "single_pmt"}, {@code "multi_pmt"}, and {@code "hls"}. Default value is {@code "single_pmt"}. * - * <p>The operation modes alter the way exo.TsParser behaves so that it can handle certain kinds - * of commonly-occurring malformed media. + * <p>The operation modes alter the way TS behaves so that it can handle certain kinds of + * commonly-occurring malformed media. * * <ul> * <li>{@code "single_pmt"}: Only the first found PMT is parsed. Others are ignored, even if @@ -529,47 +528,48 @@ public final class MediaParser { * <li>{@code "hls"}: Enable {@code "single_pmt"} mode, and ignore continuity counters. * </ul> */ - public static final String PARAMETER_TS_MODE = "exo.TsParser.mode"; + public static final String PARAMETER_TS_MODE = "android.media.mediaparser.ts.mode"; /** - * Sets whether exo.TsParser should treat samples consisting of non-IDR I slices as - * synchronization samples (key-frames). {@code boolean} expected. Default value is {@code - * false}. + * Sets whether TS should treat samples consisting of non-IDR I slices as synchronization + * samples (key-frames). {@code boolean} expected. Default value is {@code false}. */ public static final String PARAMETER_TS_ALLOW_NON_IDR_AVC_KEYFRAMES = - "exo.TsParser.allowNonIdrAvcKeyframes"; + "android.media.mediaparser.ts.allowNonIdrAvcKeyframes"; /** - * Sets whether exo.TsParser should ignore AAC elementary streams. {@code boolean} expected. + * Sets whether TS parsing should ignore AAC elementary streams. {@code boolean} expected. * Default value is {@code false}. */ - public static final String PARAMETER_TS_IGNORE_AAC_STREAM = "exo.TsParser.ignoreAacStream"; + public static final String PARAMETER_TS_IGNORE_AAC_STREAM = + "android.media.mediaparser.ts.ignoreAacStream"; /** - * Sets whether exo.TsParser should ignore AVC elementary streams. {@code boolean} expected. + * Sets whether TS parsing should ignore AVC elementary streams. {@code boolean} expected. * Default value is {@code false}. */ - public static final String PARAMETER_TS_IGNORE_AVC_STREAM = "exo.TsParser.ignoreAvcStream"; + public static final String PARAMETER_TS_IGNORE_AVC_STREAM = + "android.media.mediaparser.ts.ignoreAvcStream"; /** - * Sets whether exo.TsParser should ignore splice information streams. {@code boolean} expected. + * Sets whether TS parsing should ignore splice information streams. {@code boolean} expected. * Default value is {@code false}. */ public static final String PARAMETER_TS_IGNORE_SPLICE_INFO_STREAM = - "exo.TsParser.ignoreSpliceInfoStream"; + "android.media.mediaparser.ts.ignoreSpliceInfoStream"; /** - * Sets whether exo.TsParser should split AVC stream into access units based on slice headers. + * Sets whether TS parsing should split AVC stream into access units based on slice headers. * {@code boolean} expected. Default value is {@code false}. * * <p>This flag should be left disabled if the stream contains access units delimiters in order * to avoid unnecessary computational costs. */ public static final String PARAMETER_TS_DETECT_ACCESS_UNITS = - "exo.TsParser.ignoreDetectAccessUnits"; + "android.media.mediaparser.ts.ignoreDetectAccessUnits"; /** - * Sets whether exo.TsParser should handle HDMV DTS audio streams. {@code boolean} expected. + * Sets whether TS parsing should handle HDMV DTS audio streams. {@code boolean} expected. * Default value is {@code false}. * * <p>Enabling this flag will disable the detection of SCTE subtitles. */ public static final String PARAMETER_TS_ENABLE_HDMV_DTS_AUDIO_STREAMS = - "exo.TsParser.enableHdmvDtsAudioStreams"; + "android.media.mediaparser.ts.enableHdmvDtsAudioStreams"; // Private constants. @@ -1185,15 +1185,14 @@ public final class MediaParser { expectedTypeByParameterName.put(PARAMETER_ADTS_ENABLE_CBR_SEEKING, Boolean.class); expectedTypeByParameterName.put(PARAMETER_AMR_ENABLE_CBR_SEEKING, Boolean.class); expectedTypeByParameterName.put(PARAMETER_FLAC_DISABLE_ID3, Boolean.class); - expectedTypeByParameterName.put(PARAMETER_FMP4_IGNORE_EDIT_LISTS, Boolean.class); - expectedTypeByParameterName.put(PARAMETER_FMP4_IGNORE_TFDT_BOX, Boolean.class); + expectedTypeByParameterName.put(PARAMETER_MP4_IGNORE_EDIT_LISTS, Boolean.class); + expectedTypeByParameterName.put(PARAMETER_MP4_IGNORE_TFDT_BOX, Boolean.class); expectedTypeByParameterName.put( - PARAMETER_FMP4_TREAT_VIDEO_FRAMES_AS_KEYFRAMES, Boolean.class); + PARAMETER_MP4_TREAT_VIDEO_FRAMES_AS_KEYFRAMES, Boolean.class); expectedTypeByParameterName.put(PARAMETER_MATROSKA_DISABLE_CUES_SEEKING, Boolean.class); expectedTypeByParameterName.put(PARAMETER_MP3_DISABLE_ID3, Boolean.class); expectedTypeByParameterName.put(PARAMETER_MP3_ENABLE_CBR_SEEKING, Boolean.class); expectedTypeByParameterName.put(PARAMETER_MP3_ENABLE_INDEX_SEEKING, Boolean.class); - expectedTypeByParameterName.put(PARAMETER_MP4_IGNORE_EDIT_LISTS, Boolean.class); expectedTypeByParameterName.put(PARAMETER_TS_MODE, String.class); expectedTypeByParameterName.put(PARAMETER_TS_ALLOW_NON_IDR_AVC_KEYFRAMES, Boolean.class); expectedTypeByParameterName.put(PARAMETER_TS_IGNORE_AAC_STREAM, Boolean.class); diff --git a/apex/statsd/framework/Android.bp b/apex/statsd/framework/Android.bp index 8185bb036b22..986682e6a8c9 100644 --- a/apex/statsd/framework/Android.bp +++ b/apex/statsd/framework/Android.bp @@ -166,10 +166,8 @@ java_library { android_test { name: "FrameworkStatsdTest", - platform_apis: true, + sdk_version: "module_current", srcs: [ - // TODO(b/147705194): Use framework-statsd as a lib dependency instead. - ":framework-statsd-sources", "test/**/*.java", ], manifest: "test/AndroidManifest.xml", @@ -180,6 +178,7 @@ android_test { libs: [ "android.test.runner.stubs", "android.test.base.stubs", + "framework-statsd", ], test_suites: [ "device-tests", diff --git a/api/current.txt b/api/current.txt index 90f1c81fccab..fb73238ec305 100644 --- a/api/current.txt +++ b/api/current.txt @@ -5995,7 +5995,7 @@ package android.app { method public android.service.notification.StatusBarNotification[] getActiveNotifications(); method public android.app.AutomaticZenRule getAutomaticZenRule(String); method public java.util.Map<java.lang.String,android.app.AutomaticZenRule> getAutomaticZenRules(); - method @Nullable public android.app.NotificationManager.Policy getConsolidatedNotificationPolicy(); + method @NonNull public android.app.NotificationManager.Policy getConsolidatedNotificationPolicy(); method public final int getCurrentInterruptionFilter(); method public int getImportance(); method public android.app.NotificationChannel getNotificationChannel(String); @@ -26428,24 +26428,23 @@ package android.media { method public void seek(@NonNull android.media.MediaParser.SeekPoint); method @NonNull public android.media.MediaParser setParameter(@NonNull String, @NonNull Object); method public boolean supportsParameter(@NonNull String); - field public static final String PARAMETER_ADTS_ENABLE_CBR_SEEKING = "exo.AdtsParser.enableCbrSeeking"; - field public static final String PARAMETER_AMR_ENABLE_CBR_SEEKING = "exo.AmrParser.enableCbrSeeking"; - field public static final String PARAMETER_FLAC_DISABLE_ID3 = "exo.FlacParser.disableId3"; - field public static final String PARAMETER_FMP4_IGNORE_EDIT_LISTS = "exo.FragmentedMp4Parser.ignoreEditLists"; - field public static final String PARAMETER_FMP4_IGNORE_TFDT_BOX = "exo.FragmentedMp4Parser.ignoreTfdtBox"; - field public static final String PARAMETER_FMP4_TREAT_VIDEO_FRAMES_AS_KEYFRAMES = "exo.FragmentedMp4Parser.treatVideoFramesAsKeyframes"; - field public static final String PARAMETER_MATROSKA_DISABLE_CUES_SEEKING = "exo.MatroskaParser.disableCuesSeeking"; - field public static final String PARAMETER_MP3_DISABLE_ID3 = "exo.Mp3Parser.disableId3"; - field public static final String PARAMETER_MP3_ENABLE_CBR_SEEKING = "exo.Mp3Parser.enableCbrSeeking"; - field public static final String PARAMETER_MP3_ENABLE_INDEX_SEEKING = "exo.Mp3Parser.enableIndexSeeking"; - field public static final String PARAMETER_MP4_IGNORE_EDIT_LISTS = "exo.Mp4Parser.ignoreEditLists"; - field public static final String PARAMETER_TS_ALLOW_NON_IDR_AVC_KEYFRAMES = "exo.TsParser.allowNonIdrAvcKeyframes"; - field public static final String PARAMETER_TS_DETECT_ACCESS_UNITS = "exo.TsParser.ignoreDetectAccessUnits"; - field public static final String PARAMETER_TS_ENABLE_HDMV_DTS_AUDIO_STREAMS = "exo.TsParser.enableHdmvDtsAudioStreams"; - field public static final String PARAMETER_TS_IGNORE_AAC_STREAM = "exo.TsParser.ignoreAacStream"; - field public static final String PARAMETER_TS_IGNORE_AVC_STREAM = "exo.TsParser.ignoreAvcStream"; - field public static final String PARAMETER_TS_IGNORE_SPLICE_INFO_STREAM = "exo.TsParser.ignoreSpliceInfoStream"; - field public static final String PARAMETER_TS_MODE = "exo.TsParser.mode"; + field public static final String PARAMETER_ADTS_ENABLE_CBR_SEEKING = "android.media.mediaparser.adts.enableCbrSeeking"; + field public static final String PARAMETER_AMR_ENABLE_CBR_SEEKING = "android.media.mediaparser.amr.enableCbrSeeking"; + field public static final String PARAMETER_FLAC_DISABLE_ID3 = "android.media.mediaparser.flac.disableId3"; + field public static final String PARAMETER_MATROSKA_DISABLE_CUES_SEEKING = "android.media.mediaparser.matroska.disableCuesSeeking"; + field public static final String PARAMETER_MP3_DISABLE_ID3 = "android.media.mediaparser.mp3.disableId3"; + field public static final String PARAMETER_MP3_ENABLE_CBR_SEEKING = "android.media.mediaparser.mp3.enableCbrSeeking"; + field public static final String PARAMETER_MP3_ENABLE_INDEX_SEEKING = "android.media.mediaparser.mp3.enableIndexSeeking"; + field public static final String PARAMETER_MP4_IGNORE_EDIT_LISTS = "android.media.mediaparser.mp4.ignoreEditLists"; + field public static final String PARAMETER_MP4_IGNORE_TFDT_BOX = "android.media.mediaparser.mp4.ignoreTfdtBox"; + field public static final String PARAMETER_MP4_TREAT_VIDEO_FRAMES_AS_KEYFRAMES = "android.media.mediaparser.mp4.treatVideoFramesAsKeyframes"; + field public static final String PARAMETER_TS_ALLOW_NON_IDR_AVC_KEYFRAMES = "android.media.mediaparser.ts.allowNonIdrAvcKeyframes"; + field public static final String PARAMETER_TS_DETECT_ACCESS_UNITS = "android.media.mediaparser.ts.ignoreDetectAccessUnits"; + field public static final String PARAMETER_TS_ENABLE_HDMV_DTS_AUDIO_STREAMS = "android.media.mediaparser.ts.enableHdmvDtsAudioStreams"; + field public static final String PARAMETER_TS_IGNORE_AAC_STREAM = "android.media.mediaparser.ts.ignoreAacStream"; + field public static final String PARAMETER_TS_IGNORE_AVC_STREAM = "android.media.mediaparser.ts.ignoreAvcStream"; + field public static final String PARAMETER_TS_IGNORE_SPLICE_INFO_STREAM = "android.media.mediaparser.ts.ignoreSpliceInfoStream"; + field public static final String PARAMETER_TS_MODE = "android.media.mediaparser.ts.mode"; } public static interface MediaParser.InputReader { @@ -32454,7 +32453,7 @@ package android.nfc.cardemulation { method public boolean categoryAllowsForegroundPreference(String); method @Nullable @RequiresPermission(android.Manifest.permission.NFC_PREFERRED_PAYMENT_INFO) public java.util.List<java.lang.String> getAidsForPreferredPaymentService(); method public java.util.List<java.lang.String> getAidsForService(android.content.ComponentName, String); - method @Nullable @RequiresPermission(android.Manifest.permission.NFC_PREFERRED_PAYMENT_INFO) public String getDescriptionForPreferredPaymentService(); + method @Nullable @RequiresPermission(android.Manifest.permission.NFC_PREFERRED_PAYMENT_INFO) public CharSequence getDescriptionForPreferredPaymentService(); method public static android.nfc.cardemulation.CardEmulation getInstance(android.nfc.NfcAdapter); method @Nullable @RequiresPermission(android.Manifest.permission.NFC_PREFERRED_PAYMENT_INFO) public String getRouteDestinationForPreferredPaymentService(); method public int getSelectionModeForCategory(String); diff --git a/api/system-current.txt b/api/system-current.txt index e84449054130..0fb80a205248 100755 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -148,6 +148,7 @@ package android { field public static final String NETWORK_SETUP_WIZARD = "android.permission.NETWORK_SETUP_WIZARD"; field public static final String NETWORK_SIGNAL_STRENGTH_WAKEUP = "android.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP"; field public static final String NETWORK_STACK = "android.permission.NETWORK_STACK"; + field public static final String NETWORK_STATS_PROVIDER = "android.permission.NETWORK_STATS_PROVIDER"; field public static final String NOTIFICATION_DURING_SETUP = "android.permission.NOTIFICATION_DURING_SETUP"; field public static final String NOTIFY_TV_INPUTS = "android.permission.NOTIFY_TV_INPUTS"; field public static final String OBSERVE_APP_USAGE = "android.permission.OBSERVE_APP_USAGE"; @@ -205,7 +206,7 @@ package android { field public static final String REVIEW_ACCESSIBILITY_SERVICES = "android.permission.REVIEW_ACCESSIBILITY_SERVICES"; field public static final String REVOKE_RUNTIME_PERMISSIONS = "android.permission.REVOKE_RUNTIME_PERMISSIONS"; field public static final String SCORE_NETWORKS = "android.permission.SCORE_NETWORKS"; - field public static final String SECURE_ELEMENT_PRIVILEGED = "android.permission.SECURE_ELEMENT_PRIVILEGED"; + field public static final String SECURE_ELEMENT_PRIVILEGED_OPERATION = "android.permission.SECURE_ELEMENT_PRIVILEGED_OPERATION"; field public static final String SEND_DEVICE_CUSTOMIZATION_READY = "android.permission.SEND_DEVICE_CUSTOMIZATION_READY"; field public static final String SEND_SHOW_SUSPENDED_APP_DETAILS = "android.permission.SEND_SHOW_SUSPENDED_APP_DETAILS"; field public static final String SEND_SMS_NO_CONFIRMATION = "android.permission.SEND_SMS_NO_CONFIRMATION"; @@ -350,7 +351,6 @@ package android.app { method @RequiresPermission(android.Manifest.permission.RESTRICTED_VR_ACCESS) public static void setPersistentVrThread(int); method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean switchUser(@NonNull android.os.UserHandle); method public void unregisterHomeVisibilityObserver(@NonNull android.app.HomeVisibilityObserver); - method @RequiresPermission(android.Manifest.permission.CHANGE_CONFIGURATION) public boolean updateMccMncConfiguration(@NonNull String, @NonNull String); } public static interface ActivityManager.OnUidImportanceListener { @@ -1410,7 +1410,8 @@ package android.app.usage { } public class NetworkStatsManager { - method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public android.net.netstats.provider.NetworkStatsProviderCallback registerNetworkStatsProvider(@NonNull String, @NonNull android.net.netstats.provider.AbstractNetworkStatsProvider); + method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_STATS_PROVIDER, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void registerNetworkStatsProvider(@NonNull String, @NonNull android.net.netstats.provider.NetworkStatsProvider); + method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_STATS_PROVIDER, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void unregisterNetworkStatsProvider(@NonNull android.net.netstats.provider.NetworkStatsProvider); } public static final class UsageEvents.Event { @@ -6407,14 +6408,13 @@ package android.net { public final class NetworkStats implements android.os.Parcelable { ctor public NetworkStats(long, int); method @NonNull public android.net.NetworkStats add(@NonNull android.net.NetworkStats); - method @NonNull public android.net.NetworkStats addValues(@NonNull android.net.NetworkStats.Entry); + method @NonNull public android.net.NetworkStats addEntry(@NonNull android.net.NetworkStats.Entry); method public int describeContents(); method @NonNull public android.net.NetworkStats subtract(@NonNull android.net.NetworkStats); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkStats> CREATOR; field public static final int DEFAULT_NETWORK_NO = 0; // 0x0 field public static final int DEFAULT_NETWORK_YES = 1; // 0x1 - field @Nullable public static final String IFACE_ALL; field public static final String IFACE_VT = "vt_data0"; field public static final int METERED_NO = 0; // 0x0 field public static final int METERED_YES = 1; // 0x1 @@ -6814,21 +6814,17 @@ package android.net.metrics { package android.net.netstats.provider { - public abstract class AbstractNetworkStatsProvider { - ctor public AbstractNetworkStatsProvider(); - method public abstract void requestStatsUpdate(int); - method public abstract void setAlert(long); - method public abstract void setLimit(@NonNull String, long); + public abstract class NetworkStatsProvider { + ctor public NetworkStatsProvider(); + method public void notifyAlertReached(); + method public void notifyLimitReached(); + method public void notifyStatsUpdated(int, @NonNull android.net.NetworkStats, @NonNull android.net.NetworkStats); + method public abstract void onRequestStatsUpdate(int); + method public abstract void onSetAlert(long); + method public abstract void onSetLimit(@NonNull String, long); field public static final int QUOTA_UNLIMITED = -1; // 0xffffffff } - public class NetworkStatsProviderCallback { - method public void onAlertReached(); - method public void onLimitReached(); - method public void onStatsUpdated(int, @NonNull android.net.NetworkStats, @NonNull android.net.NetworkStats); - method public void unregister(); - } - } package android.net.sip { @@ -7452,7 +7448,15 @@ package android.net.wifi { } public final class WifiMigration { + method @Nullable public static java.io.InputStream convertAndRetrieveSharedConfigStoreFile(int); + method @Nullable public static java.io.InputStream convertAndRetrieveUserConfigStoreFile(int, @NonNull android.os.UserHandle); method @NonNull public static android.net.wifi.WifiMigration.SettingsMigrationData loadFromSettings(@NonNull android.content.Context); + method public static void removeSharedConfigStoreFile(int); + method public static void removeUserConfigStoreFile(int, @NonNull android.os.UserHandle); + field public static final int STORE_FILE_SHARED_GENERAL = 0; // 0x0 + field public static final int STORE_FILE_SHARED_SOFTAP = 1; // 0x1 + field public static final int STORE_FILE_USER_GENERAL = 2; // 0x2 + field public static final int STORE_FILE_USER_NETWORK_SUGGESTIONS = 3; // 0x3 } public static final class WifiMigration.SettingsMigrationData implements android.os.Parcelable { @@ -9345,32 +9349,6 @@ package android.provider { method @RequiresPermission(android.Manifest.permission.MODIFY_SETTINGS_OVERRIDEABLE_BY_RESTORE) public static boolean putString(@NonNull android.content.ContentResolver, @NonNull String, @Nullable String, boolean); } - public static interface Telephony.CarrierColumns extends android.provider.BaseColumns { - field @NonNull public static final android.net.Uri CONTENT_URI; - field public static final String EXPIRATION_TIME = "expiration_time"; - field public static final String KEY_IDENTIFIER = "key_identifier"; - field public static final String KEY_TYPE = "key_type"; - field public static final String LAST_MODIFIED = "last_modified"; - field public static final String MCC = "mcc"; - field public static final String MNC = "mnc"; - field public static final String MVNO_MATCH_DATA = "mvno_match_data"; - field public static final String MVNO_TYPE = "mvno_type"; - field public static final String PUBLIC_KEY = "public_key"; - } - - public static final class Telephony.CarrierId.All implements android.provider.BaseColumns { - field public static final String APN = "apn"; - field @NonNull public static final android.net.Uri CONTENT_URI; - field public static final String GID1 = "gid1"; - field public static final String GID2 = "gid2"; - field public static final String ICCID_PREFIX = "iccid_prefix"; - field public static final String IMSI_PREFIX_XPATTERN = "imsi_prefix_xpattern"; - field public static final String MCCMNC = "mccmnc"; - field public static final String PLMN = "plmn"; - field public static final String PRIVILEGE_ACCESS_RULE = "privilege_access_rule"; - field public static final String SPN = "spn"; - } - public static final class Telephony.Carriers implements android.provider.BaseColumns { field public static final String APN_SET_ID = "apn_set_id"; field public static final int CARRIER_EDITED = 4; // 0x4 @@ -9534,7 +9512,7 @@ package android.provider { package android.se.omapi { public final class Reader { - method @RequiresPermission(android.Manifest.permission.SECURE_ELEMENT_PRIVILEGED) public boolean reset(); + method @RequiresPermission(android.Manifest.permission.SECURE_ELEMENT_PRIVILEGED_OPERATION) public boolean reset(); } } @@ -10711,27 +10689,6 @@ package android.telephony { field @NonNull public static final android.os.Parcelable.Creator<android.telephony.CallAttributes> CREATOR; } - public final class CallForwardingInfo implements android.os.Parcelable { - ctor public CallForwardingInfo(int, int, @Nullable String, int); - method public int describeContents(); - method @Nullable public String getNumber(); - method public int getReason(); - method public int getStatus(); - method public int getTimeoutSeconds(); - field @NonNull public static final android.os.Parcelable.Creator<android.telephony.CallForwardingInfo> CREATOR; - field public static final int REASON_ALL = 4; // 0x4 - field public static final int REASON_ALL_CONDITIONAL = 5; // 0x5 - field public static final int REASON_BUSY = 1; // 0x1 - field public static final int REASON_NOT_REACHABLE = 3; // 0x3 - field public static final int REASON_NO_REPLY = 2; // 0x2 - field public static final int REASON_UNCONDITIONAL = 0; // 0x0 - field public static final int STATUS_ACTIVE = 1; // 0x1 - field public static final int STATUS_FDN_CHECK_FAILURE = 2; // 0x2 - field public static final int STATUS_INACTIVE = 0; // 0x0 - field public static final int STATUS_NOT_SUPPORTED = 4; // 0x4 - field public static final int STATUS_UNKNOWN_ERROR = 3; // 0x3 - } - public final class CallQuality implements android.os.Parcelable { ctor public CallQuality(int, int, int, int, int, int, int, int, int, int, int); ctor public CallQuality(int, int, int, int, int, int, int, int, int, int, int, boolean, boolean, boolean); @@ -11112,7 +11069,6 @@ package android.telephony { method public void onRadioPowerStateChanged(int); method public void onSrvccStateChanged(int); method public void onVoiceActivationStateChanged(int); - field @RequiresPermission(android.Manifest.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH) public static final int LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH = 512; // 0x200 field @RequiresPermission("android.permission.READ_PRECISE_PHONE_STATE") public static final int LISTEN_CALL_ATTRIBUTES_CHANGED = 67108864; // 0x4000000 field @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public static final int LISTEN_OUTGOING_EMERGENCY_CALL = 268435456; // 0x10000000 field @RequiresPermission(android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION) public static final int LISTEN_OUTGOING_EMERGENCY_SMS = 536870912; // 0x20000000 @@ -11143,7 +11099,6 @@ package android.telephony { } public final class PreciseDataConnectionState implements android.os.Parcelable { - ctor public PreciseDataConnectionState(int, int, int, @NonNull String, @Nullable android.net.LinkProperties, int, @Nullable android.telephony.data.ApnSetting); method @Deprecated @NonNull public String getDataConnectionApn(); method @Deprecated public int getDataConnectionApnTypeBitMask(); method @Deprecated public int getDataConnectionFailCause(); @@ -11495,8 +11450,6 @@ package android.telephony { method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.List<android.service.carrier.CarrierIdentifier> getAllowedCarriers(int); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public long getAllowedNetworkTypes(); method @Nullable @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public android.content.ComponentName getAndUpdateDefaultRespondViaMessageApplication(); - method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public android.telephony.CallForwardingInfo getCallForwarding(int); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getCallWaitingStatus(); method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public android.telephony.ImsiEncryptionInfo getCarrierInfoForImsiEncryption(int); method public java.util.List<java.lang.String> getCarrierPackageNamesForIntent(android.content.Intent); method public java.util.List<java.lang.String> getCarrierPackageNamesForIntentAndPhone(android.content.Intent, int); @@ -11577,8 +11530,6 @@ package android.telephony { method @Deprecated @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int setAllowedCarriers(int, java.util.List<android.service.carrier.CarrierIdentifier>); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setAllowedNetworkTypes(long); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setAlwaysAllowMmsData(boolean); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setCallForwarding(@NonNull android.telephony.CallForwardingInfo); - method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setCallWaitingStatus(boolean); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setCarrierDataEnabled(boolean); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int setCarrierRestrictionRules(@NonNull android.telephony.CarrierRestrictionRules); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setDataActivationState(int); @@ -11622,10 +11573,6 @@ package android.telephony { field public static final String ACTION_SIM_APPLICATION_STATE_CHANGED = "android.telephony.action.SIM_APPLICATION_STATE_CHANGED"; field public static final String ACTION_SIM_CARD_STATE_CHANGED = "android.telephony.action.SIM_CARD_STATE_CHANGED"; field public static final String ACTION_SIM_SLOT_STATUS_CHANGED = "android.telephony.action.SIM_SLOT_STATUS_CHANGED"; - field public static final int CALL_WAITING_STATUS_ACTIVE = 1; // 0x1 - field public static final int CALL_WAITING_STATUS_INACTIVE = 2; // 0x2 - field public static final int CALL_WAITING_STATUS_NOT_SUPPORTED = 4; // 0x4 - field public static final int CALL_WAITING_STATUS_UNKNOWN_ERROR = 3; // 0x3 field public static final int CARD_POWER_DOWN = 0; // 0x0 field public static final int CARD_POWER_UP = 1; // 0x1 field public static final int CARD_POWER_UP_PASS_THROUGH = 2; // 0x2 diff --git a/api/test-current.txt b/api/test-current.txt index a1a652fcea9f..5bd1f89ec081 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -83,7 +83,6 @@ package android.app { method public static void resumeAppSwitches() throws android.os.RemoteException; method @RequiresPermission(android.Manifest.permission.CHANGE_CONFIGURATION) public void scheduleApplicationInfoChanged(java.util.List<java.lang.String>, int); method @RequiresPermission("android.permission.MANAGE_USERS") public boolean switchUser(@NonNull android.os.UserHandle); - method @RequiresPermission(android.Manifest.permission.CHANGE_CONFIGURATION) public boolean updateMccMncConfiguration(@NonNull String, @NonNull String); field public static final int PROCESS_CAPABILITY_ALL = 7; // 0x7 field public static final int PROCESS_CAPABILITY_ALL_EXPLICIT = 1; // 0x1 field public static final int PROCESS_CAPABILITY_ALL_IMPLICIT = 6; // 0x6 diff --git a/config/hiddenapi-greylist-max-q.txt b/config/hiddenapi-greylist-max-q.txt index a895a44f4023..4832dd184ec5 100644 --- a/config/hiddenapi-greylist-max-q.txt +++ b/config/hiddenapi-greylist-max-q.txt @@ -406,7 +406,6 @@ Lcom/android/internal/R$string;->cancel:I Lcom/android/internal/R$string;->enable_explore_by_touch_warning_title:I Lcom/android/internal/R$string;->gigabyteShort:I Lcom/android/internal/R$string;->kilobyteShort:I -Lcom/android/internal/R$string;->map:I Lcom/android/internal/R$string;->megabyteShort:I Lcom/android/internal/R$string;->notification_title:I Lcom/android/internal/R$string;->no_matches:I diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index 1a92b758ab9f..f4ee8faaf9bf 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -1315,7 +1315,8 @@ public class ActivityManager { /** * @return The in-memory or loaded icon that represents the current state of this task. - * @deprecated This call is no longer supported. + * @deprecated This call is no longer supported. The caller should keep track of any icons + * it sets for the task descriptions internally. */ @Deprecated public Bitmap getIcon() { @@ -4242,8 +4243,6 @@ public class ActivityManager { * {@code false} otherwise. * @hide */ - @SystemApi - @TestApi @RequiresPermission(android.Manifest.permission.CHANGE_CONFIGURATION) public boolean updateMccMncConfiguration(@NonNull String mcc, @NonNull String mnc) { if (mcc == null || mnc == null) { diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java index cbbdf639d036..811b9c082be2 100644 --- a/core/java/android/app/NotificationManager.java +++ b/core/java/android/app/NotificationManager.java @@ -1015,14 +1015,15 @@ public class NotificationManager { } /** + * Returns the currently applied notification policy. + * * <p> - * Gets the currently applied notification policy. If {@link #getCurrentInterruptionFilter} - * is equal to {@link #INTERRUPTION_FILTER_ALL}, then the consolidated notification policy - * will match the default notification policy returned by {@link #getNotificationPolicy}. + * If {@link #getCurrentInterruptionFilter} is equal to {@link #INTERRUPTION_FILTER_ALL}, + * then the consolidated notification policy will match the default notification policy + * returned by {@link #getNotificationPolicy}. * </p> */ - @Nullable - public NotificationManager.Policy getConsolidatedNotificationPolicy() { + public @NonNull NotificationManager.Policy getConsolidatedNotificationPolicy() { INotificationManager service = getService(); try { return service.getConsolidatedNotificationPolicy(); diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java index 81671c349cbd..9f5dee98acb7 100644 --- a/core/java/android/app/ResourcesManager.java +++ b/core/java/android/app/ResourcesManager.java @@ -250,28 +250,6 @@ public class ResourcesManager { return dm; } - private static void applyNonDefaultDisplayMetricsToConfiguration( - @NonNull DisplayMetrics dm, @NonNull Configuration config) { - config.touchscreen = Configuration.TOUCHSCREEN_NOTOUCH; - config.densityDpi = dm.densityDpi; - config.screenWidthDp = (int) (dm.widthPixels / dm.density); - config.screenHeightDp = (int) (dm.heightPixels / dm.density); - int sl = Configuration.resetScreenLayout(config.screenLayout); - if (dm.widthPixels > dm.heightPixels) { - config.orientation = Configuration.ORIENTATION_LANDSCAPE; - config.screenLayout = Configuration.reduceScreenLayout(sl, - config.screenWidthDp, config.screenHeightDp); - } else { - config.orientation = Configuration.ORIENTATION_PORTRAIT; - config.screenLayout = Configuration.reduceScreenLayout(sl, - config.screenHeightDp, config.screenWidthDp); - } - config.smallestScreenWidthDp = Math.min(config.screenWidthDp, config.screenHeightDp); - config.compatScreenWidthDp = config.screenWidthDp; - config.compatScreenHeightDp = config.screenHeightDp; - config.compatSmallestScreenWidthDp = config.smallestScreenWidthDp; - } - public boolean applyCompatConfigurationLocked(int displayDensity, @NonNull Configuration compatConfiguration) { if (mResCompatibilityInfo != null && !mResCompatibilityInfo.supportsScreen()) { @@ -519,17 +497,11 @@ public class ResourcesManager { private Configuration generateConfig(@NonNull ResourcesKey key, @NonNull DisplayMetrics dm) { Configuration config; - final boolean isDefaultDisplay = (key.mDisplayId == Display.DEFAULT_DISPLAY); final boolean hasOverrideConfig = key.hasOverrideConfiguration(); - if (!isDefaultDisplay || hasOverrideConfig) { + if (hasOverrideConfig) { config = new Configuration(getConfiguration()); - if (!isDefaultDisplay) { - applyNonDefaultDisplayMetricsToConfiguration(dm, config); - } - if (hasOverrideConfig) { - config.updateFrom(key.mOverrideConfiguration); - if (DEBUG) Slog.v(TAG, "Applied overrideConfig=" + key.mOverrideConfiguration); - } + config.updateFrom(key.mOverrideConfiguration); + if (DEBUG) Slog.v(TAG, "Applied overrideConfig=" + key.mOverrideConfiguration); } else { config = getConfiguration(); } @@ -1110,8 +1082,6 @@ public class ResourcesManager { + resourcesImpl + " config to: " + config); } int displayId = key.mDisplayId; - final boolean hasOverrideConfiguration = key.hasOverrideConfiguration(); - tmpConfig.setTo(config); // Get new DisplayMetrics based on the DisplayAdjustments given to the ResourcesImpl. Update // a copy if the CompatibilityInfo changed, because the ResourcesImpl object will handle the @@ -1121,15 +1091,12 @@ public class ResourcesManager { daj = new DisplayAdjustments(daj); daj.setCompatibilityInfo(compat); } - daj.setConfiguration(config); - DisplayMetrics dm = getDisplayMetrics(displayId, daj); - if (displayId != Display.DEFAULT_DISPLAY) { - applyNonDefaultDisplayMetricsToConfiguration(dm, tmpConfig); - } - - if (hasOverrideConfiguration) { + tmpConfig.setTo(config); + if (key.hasOverrideConfiguration()) { tmpConfig.updateFrom(key.mOverrideConfiguration); } + daj.setConfiguration(tmpConfig); + DisplayMetrics dm = getDisplayMetrics(displayId, daj); resourcesImpl.updateConfiguration(tmpConfig, dm, compat); } diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java index 5b98188300c9..d6e77624a967 100644 --- a/core/java/android/app/usage/NetworkStatsManager.java +++ b/core/java/android/app/usage/NetworkStatsManager.java @@ -29,10 +29,10 @@ import android.net.ConnectivityManager; import android.net.DataUsageRequest; import android.net.INetworkStatsService; import android.net.NetworkIdentity; +import android.net.NetworkStack; import android.net.NetworkTemplate; -import android.net.netstats.provider.AbstractNetworkStatsProvider; -import android.net.netstats.provider.NetworkStatsProviderCallback; -import android.net.netstats.provider.NetworkStatsProviderWrapper; +import android.net.netstats.provider.INetworkStatsProviderCallback; +import android.net.netstats.provider.NetworkStatsProvider; import android.os.Binder; import android.os.Handler; import android.os.Looper; @@ -527,32 +527,53 @@ public class NetworkStatsManager { /** * Registers a custom provider of {@link android.net.NetworkStats} to provide network statistics - * to the system. To unregister, invoke {@link NetworkStatsProviderCallback#unregister()}. + * to the system. To unregister, invoke {@link #unregisterNetworkStatsProvider}. * Note that no de-duplication of statistics between providers is performed, so each provider - * must only report network traffic that is not being reported by any other provider. + * must only report network traffic that is not being reported by any other provider. Also note + * that the provider cannot be re-registered after unregistering. * * @param tag a human readable identifier of the custom network stats provider. This is only * used for debugging. - * @param provider the subclass of {@link AbstractNetworkStatsProvider} that needs to be + * @param provider the subclass of {@link NetworkStatsProvider} that needs to be * registered to the system. - * @return a {@link NetworkStatsProviderCallback}, which can be used to report events to the - * system or unregister the provider. * @hide */ @SystemApi - @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) - @NonNull public NetworkStatsProviderCallback registerNetworkStatsProvider( + @RequiresPermission(anyOf = { + android.Manifest.permission.NETWORK_STATS_PROVIDER, + NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) + @NonNull public void registerNetworkStatsProvider( @NonNull String tag, - @NonNull AbstractNetworkStatsProvider provider) { + @NonNull NetworkStatsProvider provider) { try { - final NetworkStatsProviderWrapper wrapper = new NetworkStatsProviderWrapper(provider); - return new NetworkStatsProviderCallback( - mService.registerNetworkStatsProvider(tag, wrapper)); + if (provider.getProviderCallbackBinder() != null) { + throw new IllegalArgumentException("provider is already registered"); + } + final INetworkStatsProviderCallback cbBinder = + mService.registerNetworkStatsProvider(tag, provider.getProviderBinder()); + provider.setProviderCallbackBinder(cbBinder); + } catch (RemoteException e) { + e.rethrowAsRuntimeException(); + } + } + + /** + * Unregisters an instance of {@link NetworkStatsProvider}. + * + * @param provider the subclass of {@link NetworkStatsProvider} that needs to be + * unregistered to the system. + * @hide + */ + @SystemApi + @RequiresPermission(anyOf = { + android.Manifest.permission.NETWORK_STATS_PROVIDER, + NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) + @NonNull public void unregisterNetworkStatsProvider(@NonNull NetworkStatsProvider provider) { + try { + provider.getProviderCallbackBinderOrThrow().unregister(); } catch (RemoteException e) { e.rethrowAsRuntimeException(); } - // Unreachable code, but compiler doesn't know about it. - return null; } private static NetworkTemplate createTemplate(int networkType, String subscriberId) { diff --git a/core/java/android/companion/CompanionDeviceManager.java b/core/java/android/companion/CompanionDeviceManager.java index d4b5b1aab532..4bd7b059dfaa 100644 --- a/core/java/android/companion/CompanionDeviceManager.java +++ b/core/java/android/companion/CompanionDeviceManager.java @@ -257,11 +257,22 @@ public final class CompanionDeviceManager { /** * Check if a given package was {@link #associate associated} with a device with given - * mac address by given user. + * Wi-Fi MAC address for a given user. * - * @param packageName the package to check for - * @param macAddress the mac address or BSSID of the device to check for - * @param user the user to check for + * <p>This is a system API protected by the + * {@link andrioid.Manifest.permission#MANAGE_COMPANION_DEVICES} permission, that’s currently + * called by the Android Wi-Fi stack to determine whether user consent is required to connect + * to a Wi-Fi network. Devices that have been pre-registered as companion devices will not + * require user consent to connect.</p> + * + * <p>Note if the caller has the + * {@link android.Manifest.permission#COMPANION_APPROVE_WIFI_CONNECTIONS} permission, this + * method will return true by default.</p> + * + * @param packageName the name of the package that has the association with the companion device + * @param macAddress the Wi-Fi MAC address or BSSID of the companion device to check for + * @param user the user handle that currently hosts the package being queried for a companion + * device association * @return whether a corresponding association record exists * * @hide diff --git a/core/java/android/content/pm/ILauncherApps.aidl b/core/java/android/content/pm/ILauncherApps.aidl index 8a89840876d9..27c9cfcdd05b 100644 --- a/core/java/android/content/pm/ILauncherApps.aidl +++ b/core/java/android/content/pm/ILauncherApps.aidl @@ -103,4 +103,7 @@ interface ILauncherApps { in UserHandle user); void uncacheShortcuts(String callingPackage, String packageName, in List<String> shortcutIds, in UserHandle user); + + String getShortcutIconUri(String callingPackage, String packageName, String shortcutId, + int userId); } diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java index 22516f069e83..e73fd03e34b6 100644 --- a/core/java/android/content/pm/LauncherApps.java +++ b/core/java/android/content/pm/LauncherApps.java @@ -51,6 +51,7 @@ import android.graphics.drawable.AdaptiveIconDrawable; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.Icon; +import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.os.Handler; @@ -67,8 +68,10 @@ import android.util.DisplayMetrics; import android.util.Log; import android.util.Pair; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.function.pooled.PooledLambda; +import java.io.FileNotFoundException; import java.io.IOException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -1198,6 +1201,35 @@ public class LauncherApps { } /** + * @hide internal/unit tests only + */ + @VisibleForTesting + public ParcelFileDescriptor getUriShortcutIconFd(@NonNull ShortcutInfo shortcut) { + return getUriShortcutIconFd(shortcut.getPackage(), shortcut.getId(), shortcut.getUserId()); + } + + private ParcelFileDescriptor getUriShortcutIconFd(@NonNull String packageName, + @NonNull String shortcutId, int userId) { + String uri = null; + try { + uri = mService.getShortcutIconUri(mContext.getPackageName(), packageName, shortcutId, + userId); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + + if (uri == null) { + return null; + } + try { + return mContext.getContentResolver().openFileDescriptor(Uri.parse(uri), "r"); + } catch (FileNotFoundException e) { + Log.e(TAG, "Icon file not found: " + uri); + return null; + } + } + + /** * Returns the icon for this shortcut, without any badging for the profile. * * <p>The calling launcher application must be allowed to access the shortcut information, @@ -1217,26 +1249,10 @@ public class LauncherApps { public Drawable getShortcutIconDrawable(@NonNull ShortcutInfo shortcut, int density) { if (shortcut.hasIconFile()) { final ParcelFileDescriptor pfd = getShortcutIconFd(shortcut); - if (pfd == null) { - return null; - } - try { - final Bitmap bmp = BitmapFactory.decodeFileDescriptor(pfd.getFileDescriptor()); - if (bmp != null) { - BitmapDrawable dr = new BitmapDrawable(mContext.getResources(), bmp); - if (shortcut.hasAdaptiveBitmap()) { - return new AdaptiveIconDrawable(null, dr); - } else { - return dr; - } - } - return null; - } finally { - try { - pfd.close(); - } catch (IOException ignore) { - } - } + return loadDrawableFromFileDescriptor(pfd, shortcut.hasAdaptiveBitmap()); + } else if (shortcut.hasIconUri()) { + final ParcelFileDescriptor pfd = getUriShortcutIconFd(shortcut); + return loadDrawableFromFileDescriptor(pfd, shortcut.hasAdaptiveBitmap()); } else if (shortcut.hasIconResource()) { return loadDrawableResourceFromPackage(shortcut.getPackage(), shortcut.getIconResourceId(), shortcut.getUserHandle(), density); @@ -1260,6 +1276,29 @@ public class LauncherApps { } } + private Drawable loadDrawableFromFileDescriptor(ParcelFileDescriptor pfd, boolean adaptive) { + if (pfd == null) { + return null; + } + try { + final Bitmap bmp = BitmapFactory.decodeFileDescriptor(pfd.getFileDescriptor()); + if (bmp != null) { + BitmapDrawable dr = new BitmapDrawable(mContext.getResources(), bmp); + if (adaptive) { + return new AdaptiveIconDrawable(null, dr); + } else { + return dr; + } + } + return null; + } finally { + try { + pfd.close(); + } catch (IOException ignore) { + } + } + } + private Drawable loadDrawableResourceFromPackage(String packageName, int resId, UserHandle user, int density) { try { diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java index af875787bba6..8d8776f1bc23 100644 --- a/core/java/android/content/pm/ShortcutInfo.java +++ b/core/java/android/content/pm/ShortcutInfo.java @@ -123,6 +123,9 @@ public final class ShortcutInfo implements Parcelable { public static final int FLAG_CACHED = 1 << 14; /** @hide */ + public static final int FLAG_HAS_ICON_URI = 1 << 15; + + /** @hide */ @IntDef(flag = true, prefix = { "FLAG_" }, value = { FLAG_DYNAMIC, FLAG_PINNED, @@ -139,6 +142,7 @@ public final class ShortcutInfo implements Parcelable { FLAG_SHADOW, FLAG_LONG_LIVED, FLAG_CACHED, + FLAG_HAS_ICON_URI, }) @Retention(RetentionPolicy.SOURCE) public @interface ShortcutFlags {} @@ -401,6 +405,9 @@ public final class ShortcutInfo implements Parcelable { private String mIconResName; // Internal use only. + private String mIconUri; + + // Internal use only. @Nullable private String mBitmapPath; @@ -554,6 +561,7 @@ public final class ShortcutInfo implements Parcelable { if ((cloneFlags & CLONE_REMOVE_ICON) == 0) { mIcon = source.mIcon; mBitmapPath = source.mBitmapPath; + mIconUri = source.mIconUri; } mTitle = source.mTitle; @@ -856,6 +864,7 @@ public final class ShortcutInfo implements Parcelable { mIconResId = 0; mIconResName = null; mBitmapPath = null; + mIconUri = null; } if (source.mTitle != null) { mTitle = source.mTitle; @@ -916,6 +925,8 @@ public final class ShortcutInfo implements Parcelable { case Icon.TYPE_RESOURCE: case Icon.TYPE_BITMAP: case Icon.TYPE_ADAPTIVE_BITMAP: + case Icon.TYPE_URI: + case Icon.TYPE_URI_ADAPTIVE_BITMAP: break; // OK default: throw getInvalidIconException(); @@ -1792,6 +1803,15 @@ public final class ShortcutInfo implements Parcelable { return hasFlags(FLAG_HAS_ICON_RES); } + /** + * Return whether a shortcut's icon is provided via a URI. + * + * @hide internal/unit tests only + */ + public boolean hasIconUri() { + return hasFlags(FLAG_HAS_ICON_URI); + } + /** @hide */ public boolean hasStringResources() { return (mTitleResId != 0) || (mTextResId != 0) || (mDisabledMessageResId != 0); @@ -1911,6 +1931,19 @@ public final class ShortcutInfo implements Parcelable { return mIconResId; } + /** @hide */ + public void setIconUri(String iconUri) { + mIconUri = iconUri; + } + + /** + * Get the Uri for the icon, valid only when {@link #hasIconUri()} } is true. + * @hide internal / tests only. + */ + public String getIconUri() { + return mIconUri; + } + /** * Bitmap path. Note this will be null even if {@link #hasIconFile()} is set when the save * is pending. Use {@link #isIconPendingSave()} to check it. @@ -2062,6 +2095,7 @@ public final class ShortcutInfo implements Parcelable { mPersons = source.readParcelableArray(cl, Person.class); mLocusId = source.readParcelable(cl); + mIconUri = source.readString(); } @Override @@ -2112,6 +2146,7 @@ public final class ShortcutInfo implements Parcelable { dest.writeParcelableArray(mPersons, flags); dest.writeParcelable(mLocusId, flags); + dest.writeString(mIconUri); } public static final @android.annotation.NonNull Creator<ShortcutInfo> CREATOR = @@ -2203,6 +2238,12 @@ public final class ShortcutInfo implements Parcelable { if (hasIconResource()) { sb.append("Ic-r"); } + if (hasIconUri()) { + sb.append("Ic-u"); + } + if (hasAdaptiveBitmap()) { + sb.append("Ic-a"); + } if (hasKeyFieldsOnly()) { sb.append("Key"); } @@ -2325,6 +2366,9 @@ public final class ShortcutInfo implements Parcelable { sb.append(", bitmapPath="); sb.append(mBitmapPath); + + sb.append(", iconUri="); + sb.append(mIconUri); } if (mLocusId != null) { @@ -2343,8 +2387,8 @@ public final class ShortcutInfo implements Parcelable { CharSequence disabledMessage, int disabledMessageResId, String disabledMessageResName, Set<String> categories, Intent[] intentsWithExtras, int rank, PersistableBundle extras, long lastChangedTimestamp, - int flags, int iconResId, String iconResName, String bitmapPath, int disabledReason, - Person[] persons, LocusId locusId) { + int flags, int iconResId, String iconResName, String bitmapPath, String iconUri, + int disabledReason, Person[] persons, LocusId locusId) { mUserId = userId; mId = id; mPackageName = packageName; @@ -2369,6 +2413,7 @@ public final class ShortcutInfo implements Parcelable { mIconResId = iconResId; mIconResName = iconResName; mBitmapPath = bitmapPath; + mIconUri = iconUri; mDisabledReason = disabledReason; mPersons = persons; mLocusId = locusId; diff --git a/core/java/android/content/pm/ShortcutServiceInternal.java b/core/java/android/content/pm/ShortcutServiceInternal.java index a50ce92a70bf..435c70ae999b 100644 --- a/core/java/android/content/pm/ShortcutServiceInternal.java +++ b/core/java/android/content/pm/ShortcutServiceInternal.java @@ -103,4 +103,10 @@ public abstract class ShortcutServiceInternal { */ public abstract List<ShortcutManager.ShareShortcutInfo> getShareTargets( @NonNull String callingPackage, @NonNull IntentFilter intentFilter, int userId); + + /** + * Returns the icon Uri of the shortcut, and grants Uri read permission to the caller. + */ + public abstract String getShortcutIconUri(int launcherUserId, @NonNull String launcherPackage, + @NonNull String packageName, @NonNull String shortcutId, int userId); } diff --git a/core/java/android/net/NattKeepalivePacketData.java b/core/java/android/net/NattKeepalivePacketData.java index bd39c13ba092..29da4952daa5 100644 --- a/core/java/android/net/NattKeepalivePacketData.java +++ b/core/java/android/net/NattKeepalivePacketData.java @@ -20,6 +20,7 @@ import static android.net.InvalidPacketException.ERROR_INVALID_IP_ADDRESS; import static android.net.InvalidPacketException.ERROR_INVALID_PORT; import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.SystemApi; import android.net.util.IpUtils; import android.os.Parcel; @@ -30,6 +31,7 @@ import java.net.Inet4Address; import java.net.InetAddress; import java.nio.ByteBuffer; import java.nio.ByteOrder; +import java.util.Objects; /** @hide */ @SystemApi @@ -121,4 +123,19 @@ public final class NattKeepalivePacketData extends KeepalivePacketData implement return new NattKeepalivePacketData[size]; } }; + + @Override + public boolean equals(@Nullable final Object o) { + if (!(o instanceof NattKeepalivePacketData)) return false; + final NattKeepalivePacketData other = (NattKeepalivePacketData) o; + return this.srcAddress.equals(other.srcAddress) + && this.dstAddress.equals(other.dstAddress) + && this.srcPort == other.srcPort + && this.dstPort == other.dstPort; + } + + @Override + public int hashCode() { + return Objects.hash(srcAddress, dstAddress, srcPort, dstPort); + } } diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index 2f536ffd8ca6..9c1fb41ecc96 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -21,7 +21,6 @@ import static android.os.Process.CLAT_UID; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; @@ -58,9 +57,12 @@ import java.util.function.Predicate; public final class NetworkStats implements Parcelable { private static final String TAG = "NetworkStats"; - /** {@link #iface} value when interface details unavailable. */ - @SuppressLint("CompileTimeConstant") + /** + * {@link #iface} value when interface details unavailable. + * @hide + */ @Nullable public static final String IFACE_ALL = null; + /** * Virtual network interface for video telephony. This is for VT data usage counting * purpose. @@ -248,7 +250,13 @@ public final class NetworkStats implements Parcelable { @UnsupportedAppUsage private long[] operations; - /** @hide */ + /** + * Basic element of network statistics. Contains the number of packets and number of bytes + * transferred on both directions in a given set of conditions. See + * {@link Entry#Entry(String, int, int, int, int, int, int, long, long, long, long, long)}. + * + * @hide + */ @SystemApi public static class Entry { /** @hide */ @@ -319,6 +327,35 @@ public final class NetworkStats implements Parcelable { rxBytes, rxPackets, txBytes, txPackets, operations); } + /** + * Construct a {@link Entry} object by giving statistics of packet and byte transferred on + * both direction, and associated with a set of given conditions. + * + * @param iface interface name of this {@link Entry}. Or null if not specified. + * @param uid uid of this {@link Entry}. {@link #UID_TETHERING} if this {@link Entry} is + * for tethering. Or {@link #UID_ALL} if this {@link NetworkStats} is only + * counting iface stats. + * @param set usage state of this {@link Entry}. Should be one of the following + * values: {@link #SET_DEFAULT}, {@link #SET_FOREGROUND}. + * @param tag tag of this {@link Entry}. + * @param metered metered state of this {@link Entry}. Should be one of the following + * values: {link #METERED_YES}, {link #METERED_NO}. + * @param roaming roaming state of this {@link Entry}. Should be one of the following + * values: {link #ROAMING_YES}, {link #ROAMING_NO}. + * @param defaultNetwork default network status of this {@link Entry}. Should be one + * of the following values: {link #DEFAULT_NETWORK_YES}, + * {link #DEFAULT_NETWORK_NO}. + * @param rxBytes Number of bytes received for this {@link Entry}. Statistics should + * represent the contents of IP packets, including IP headers. + * @param rxPackets Number of packets received for this {@link Entry}. Statistics should + * represent the contents of IP packets, including IP headers. + * @param txBytes Number of bytes transmitted for this {@link Entry}. Statistics should + * represent the contents of IP packets, including IP headers. + * @param txPackets Number of bytes transmitted for this {@link Entry}. Statistics should + * represent the contents of IP packets, including IP headers. + * @param operations count of network operations performed for this {@link Entry}. This can + * be used to derive bytes-per-operation. + */ public Entry(@Nullable String iface, int uid, @State int set, int tag, @Meteredness int metered, @Roaming int roaming, @DefaultNetwork int defaultNetwork, long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) { @@ -466,7 +503,7 @@ public final class NetworkStats implements Parcelable { NetworkStats.Entry entry = null; for (int i = 0; i < size; i++) { entry = getValues(i, entry); - clone.addEntry(entry); + clone.insertEntry(entry); } return clone; } @@ -493,26 +530,26 @@ public final class NetworkStats implements Parcelable { /** @hide */ @VisibleForTesting - public NetworkStats addIfaceValues( + public NetworkStats insertEntry( String iface, long rxBytes, long rxPackets, long txBytes, long txPackets) { - return addEntry( + return insertEntry( iface, UID_ALL, SET_DEFAULT, TAG_NONE, rxBytes, rxPackets, txBytes, txPackets, 0L); } /** @hide */ @VisibleForTesting - public NetworkStats addEntry(String iface, int uid, int set, int tag, long rxBytes, + public NetworkStats insertEntry(String iface, int uid, int set, int tag, long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) { - return addEntry(new Entry( + return insertEntry(new Entry( iface, uid, set, tag, rxBytes, rxPackets, txBytes, txPackets, operations)); } /** @hide */ @VisibleForTesting - public NetworkStats addEntry(String iface, int uid, int set, int tag, int metered, int roaming, - int defaultNetwork, long rxBytes, long rxPackets, long txBytes, long txPackets, - long operations) { - return addEntry(new Entry( + public NetworkStats insertEntry(String iface, int uid, int set, int tag, int metered, + int roaming, int defaultNetwork, long rxBytes, long rxPackets, long txBytes, + long txPackets, long operations) { + return insertEntry(new Entry( iface, uid, set, tag, metered, roaming, defaultNetwork, rxBytes, rxPackets, txBytes, txPackets, operations)); } @@ -522,7 +559,7 @@ public final class NetworkStats implements Parcelable { * object can be recycled across multiple calls. * @hide */ - public NetworkStats addEntry(Entry entry) { + public NetworkStats insertEntry(Entry entry) { if (size >= capacity) { final int newLength = Math.max(size, 10) * 3 / 2; iface = Arrays.copyOf(iface, newLength); @@ -665,7 +702,7 @@ public final class NetworkStats implements Parcelable { entry.roaming, entry.defaultNetwork); if (i == -1) { // only create new entry when positive contribution - addEntry(entry); + insertEntry(entry); } else { rxBytes[i] += entry.rxBytes; rxPackets[i] += entry.rxPackets; @@ -684,7 +721,7 @@ public final class NetworkStats implements Parcelable { * @param entry the {@link Entry} to add. * @return a new constructed {@link NetworkStats} object that contains the result. */ - public @NonNull NetworkStats addValues(@NonNull Entry entry) { + public @NonNull NetworkStats addEntry(@NonNull Entry entry) { return this.clone().combineValues(entry); } @@ -1003,7 +1040,7 @@ public final class NetworkStats implements Parcelable { entry.operations = Math.max(entry.operations, 0); } - result.addEntry(entry); + result.insertEntry(entry); } return result; diff --git a/core/java/android/net/netstats/provider/AbstractNetworkStatsProvider.java b/core/java/android/net/netstats/provider/AbstractNetworkStatsProvider.java deleted file mode 100644 index 740aa92ad484..000000000000 --- a/core/java/android/net/netstats/provider/AbstractNetworkStatsProvider.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net.netstats.provider; - -import android.annotation.NonNull; -import android.annotation.SystemApi; -import android.net.NetworkStats; - -/** - * A base class that allows external modules to implement a custom network statistics provider. - * @hide - */ -@SystemApi -public abstract class AbstractNetworkStatsProvider { - /** - * A value used by {@link #setLimit} and {@link #setAlert} indicates there is no limit. - */ - public static final int QUOTA_UNLIMITED = -1; - - /** - * Called by {@code NetworkStatsService} when global polling is needed. Custom - * implementation of providers MUST respond to it by calling - * {@link NetworkStatsProviderCallback#onStatsUpdated} within one minute. Responding - * later than this may cause the stats to be dropped. - * - * @param token a positive number identifying the new state of the system under which - * {@link NetworkStats} have to be gathered from now on. When this is called, - * custom implementations of providers MUST report the latest stats with the - * previous token, under which stats were being gathered so far. - */ - public abstract void requestStatsUpdate(int token); - - /** - * Called by {@code NetworkStatsService} when setting the interface quota for the specified - * upstream interface. When this is called, the custom implementation should block all egress - * packets on the {@code iface} associated with the provider when {@code quotaBytes} bytes have - * been reached, and MUST respond to it by calling - * {@link NetworkStatsProviderCallback#onLimitReached()}. - * - * @param iface the interface requiring the operation. - * @param quotaBytes the quota defined as the number of bytes, starting from zero and counting - * from now. A value of {@link #QUOTA_UNLIMITED} indicates there is no limit. - */ - public abstract void setLimit(@NonNull String iface, long quotaBytes); - - /** - * Called by {@code NetworkStatsService} when setting the alert bytes. Custom implementations - * MUST call {@link NetworkStatsProviderCallback#onAlertReached()} when {@code quotaBytes} bytes - * have been reached. Unlike {@link #setLimit(String, long)}, the custom implementation should - * not block all egress packets. - * - * @param quotaBytes the quota defined as the number of bytes, starting from zero and counting - * from now. A value of {@link #QUOTA_UNLIMITED} indicates there is no alert. - */ - public abstract void setAlert(long quotaBytes); -} diff --git a/core/java/android/net/netstats/provider/INetworkStatsProvider.aidl b/core/java/android/net/netstats/provider/INetworkStatsProvider.aidl index 55b3d4edb157..4078b249218c 100644 --- a/core/java/android/net/netstats/provider/INetworkStatsProvider.aidl +++ b/core/java/android/net/netstats/provider/INetworkStatsProvider.aidl @@ -22,7 +22,7 @@ package android.net.netstats.provider; * @hide */ oneway interface INetworkStatsProvider { - void requestStatsUpdate(int token); - void setLimit(String iface, long quotaBytes); - void setAlert(long quotaBytes); + void onRequestStatsUpdate(int token); + void onSetLimit(String iface, long quotaBytes); + void onSetAlert(long quotaBytes); } diff --git a/core/java/android/net/netstats/provider/INetworkStatsProviderCallback.aidl b/core/java/android/net/netstats/provider/INetworkStatsProviderCallback.aidl index 3ea9318f10d4..bd336dd348fe 100644 --- a/core/java/android/net/netstats/provider/INetworkStatsProviderCallback.aidl +++ b/core/java/android/net/netstats/provider/INetworkStatsProviderCallback.aidl @@ -24,8 +24,8 @@ import android.net.NetworkStats; * @hide */ oneway interface INetworkStatsProviderCallback { - void onStatsUpdated(int token, in NetworkStats ifaceStats, in NetworkStats uidStats); - void onAlertReached(); - void onLimitReached(); + void notifyStatsUpdated(int token, in NetworkStats ifaceStats, in NetworkStats uidStats); + void notifyAlertReached(); + void notifyLimitReached(); void unregister(); } diff --git a/core/java/android/net/netstats/provider/NetworkStatsProvider.java b/core/java/android/net/netstats/provider/NetworkStatsProvider.java new file mode 100644 index 000000000000..7639d2244cfe --- /dev/null +++ b/core/java/android/net/netstats/provider/NetworkStatsProvider.java @@ -0,0 +1,195 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.netstats.provider; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.net.NetworkStats; +import android.os.RemoteException; + +/** + * A base class that allows external modules to implement a custom network statistics provider. + * @hide + */ +@SystemApi +public abstract class NetworkStatsProvider { + /** + * A value used by {@link #onSetLimit} and {@link #onSetAlert} indicates there is no limit. + */ + public static final int QUOTA_UNLIMITED = -1; + + @NonNull private final INetworkStatsProvider mProviderBinder = + new INetworkStatsProvider.Stub() { + + @Override + public void onRequestStatsUpdate(int token) { + NetworkStatsProvider.this.onRequestStatsUpdate(token); + } + + @Override + public void onSetLimit(String iface, long quotaBytes) { + NetworkStatsProvider.this.onSetLimit(iface, quotaBytes); + } + + @Override + public void onSetAlert(long quotaBytes) { + NetworkStatsProvider.this.onSetAlert(quotaBytes); + } + }; + + // The binder given by the service when successfully registering. Only null before registering, + // never null once non-null. + @Nullable + private INetworkStatsProviderCallback mProviderCbBinder; + + /** + * Return the binder invoked by the service and redirect function calls to the overridden + * methods. + * @hide + */ + @NonNull + public INetworkStatsProvider getProviderBinder() { + return mProviderBinder; + } + + /** + * Store the binder that was returned by the service when successfully registering. Note that + * the provider cannot be re-registered. Hence this method can only be called once per provider. + * + * @hide + */ + public void setProviderCallbackBinder(@NonNull INetworkStatsProviderCallback binder) { + if (mProviderCbBinder != null) { + throw new IllegalArgumentException("provider is already registered"); + } + mProviderCbBinder = binder; + } + + /** + * Get the binder that was returned by the service when successfully registering. Or null if the + * provider was never registered. + * + * @hide + */ + @Nullable + public INetworkStatsProviderCallback getProviderCallbackBinder() { + return mProviderCbBinder; + } + + /** + * Get the binder that was returned by the service when successfully registering. Throw an + * {@link IllegalStateException} if the provider is not registered. + * + * @hide + */ + @NonNull + public INetworkStatsProviderCallback getProviderCallbackBinderOrThrow() { + if (mProviderCbBinder == null) { + throw new IllegalStateException("the provider is not registered"); + } + return mProviderCbBinder; + } + + /** + * Notify the system of new network statistics. + * + * Send the network statistics recorded since the last call to {@link #notifyStatsUpdated}. Must + * be called as soon as possible after {@link NetworkStatsProvider#onRequestStatsUpdate(int)} + * being called. Responding later increases the probability stats will be dropped. The + * provider can also call this whenever it wants to reports new stats for any reason. + * Note that the system will not necessarily immediately propagate the statistics to + * reflect the update. + * + * @param token the token under which these stats were gathered. Providers can call this method + * with the current token as often as they want, until the token changes. + * {@see NetworkStatsProvider#onRequestStatsUpdate()} + * @param ifaceStats the {@link NetworkStats} per interface to be reported. + * The provider should not include any traffic that is already counted by + * kernel interface counters. + * @param uidStats the same stats as above, but counts {@link NetworkStats} + * per uid. + */ + public void notifyStatsUpdated(int token, @NonNull NetworkStats ifaceStats, + @NonNull NetworkStats uidStats) { + try { + getProviderCallbackBinderOrThrow().notifyStatsUpdated(token, ifaceStats, uidStats); + } catch (RemoteException e) { + e.rethrowAsRuntimeException(); + } + } + + /** + * Notify system that the quota set by {@code onSetAlert} has been reached. + */ + public void notifyAlertReached() { + try { + getProviderCallbackBinderOrThrow().notifyAlertReached(); + } catch (RemoteException e) { + e.rethrowAsRuntimeException(); + } + } + + /** + * Notify system that the quota set by {@code onSetLimit} has been reached. + */ + public void notifyLimitReached() { + try { + getProviderCallbackBinderOrThrow().notifyLimitReached(); + } catch (RemoteException e) { + e.rethrowAsRuntimeException(); + } + } + + /** + * Called by {@code NetworkStatsService} when it requires to know updated stats. + * The provider MUST respond by calling {@link #notifyStatsUpdated} as soon as possible. + * Responding later increases the probability stats will be dropped. Memory allowing, the + * system will try to take stats into account up to one minute after calling + * {@link #onRequestStatsUpdate}. + * + * @param token a positive number identifying the new state of the system under which + * {@link NetworkStats} have to be gathered from now on. When this is called, + * custom implementations of providers MUST tally and report the latest stats with + * the previous token, under which stats were being gathered so far. + */ + public abstract void onRequestStatsUpdate(int token); + + /** + * Called by {@code NetworkStatsService} when setting the interface quota for the specified + * upstream interface. When this is called, the custom implementation should block all egress + * packets on the {@code iface} associated with the provider when {@code quotaBytes} bytes have + * been reached, and MUST respond to it by calling + * {@link NetworkStatsProvider#notifyLimitReached()}. + * + * @param iface the interface requiring the operation. + * @param quotaBytes the quota defined as the number of bytes, starting from zero and counting + * from now. A value of {@link #QUOTA_UNLIMITED} indicates there is no limit. + */ + public abstract void onSetLimit(@NonNull String iface, long quotaBytes); + + /** + * Called by {@code NetworkStatsService} when setting the alert bytes. Custom implementations + * MUST call {@link NetworkStatsProvider#notifyAlertReached()} when {@code quotaBytes} bytes + * have been reached. Unlike {@link #onSetLimit(String, long)}, the custom implementation should + * not block all egress packets. + * + * @param quotaBytes the quota defined as the number of bytes, starting from zero and counting + * from now. A value of {@link #QUOTA_UNLIMITED} indicates there is no alert. + */ + public abstract void onSetAlert(long quotaBytes); +} diff --git a/core/java/android/net/netstats/provider/NetworkStatsProviderCallback.java b/core/java/android/net/netstats/provider/NetworkStatsProviderCallback.java deleted file mode 100644 index e17a8eee7ff0..000000000000 --- a/core/java/android/net/netstats/provider/NetworkStatsProviderCallback.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net.netstats.provider; - -import android.annotation.NonNull; -import android.annotation.SuppressLint; -import android.annotation.SystemApi; -import android.net.NetworkStats; -import android.os.RemoteException; - -/** - * A callback class that allows callers to report events to the system. - * @hide - */ -@SystemApi -@SuppressLint("CallbackMethodName") -public class NetworkStatsProviderCallback { - @NonNull private final INetworkStatsProviderCallback mBinder; - - /** @hide */ - public NetworkStatsProviderCallback(@NonNull INetworkStatsProviderCallback binder) { - mBinder = binder; - } - - /** - * Notify the system of new network statistics. - * - * Send the network statistics recorded since the last call to {@link #onStatsUpdated}. Must be - * called within one minute of {@link AbstractNetworkStatsProvider#requestStatsUpdate(int)} - * being called. The provider can also call this whenever it wants to reports new stats for any - * reason. Note that the system will not necessarily immediately propagate the statistics to - * reflect the update. - * - * @param token the token under which these stats were gathered. Providers can call this method - * with the current token as often as they want, until the token changes. - * {@see AbstractNetworkStatsProvider#requestStatsUpdate()} - * @param ifaceStats the {@link NetworkStats} per interface to be reported. - * The provider should not include any traffic that is already counted by - * kernel interface counters. - * @param uidStats the same stats as above, but counts {@link NetworkStats} - * per uid. - */ - public void onStatsUpdated(int token, @NonNull NetworkStats ifaceStats, - @NonNull NetworkStats uidStats) { - try { - mBinder.onStatsUpdated(token, ifaceStats, uidStats); - } catch (RemoteException e) { - e.rethrowAsRuntimeException(); - } - } - - /** - * Notify system that the quota set by {@code setAlert} has been reached. - */ - public void onAlertReached() { - try { - mBinder.onAlertReached(); - } catch (RemoteException e) { - e.rethrowAsRuntimeException(); - } - } - - /** - * Notify system that the quota set by {@code setLimit} has been reached. - */ - public void onLimitReached() { - try { - mBinder.onLimitReached(); - } catch (RemoteException e) { - e.rethrowAsRuntimeException(); - } - } - - /** - * Unregister the provider and the referencing callback. - */ - public void unregister() { - try { - mBinder.unregister(); - } catch (RemoteException e) { - // Ignore error. - } - } -} diff --git a/core/java/android/net/netstats/provider/NetworkStatsProviderWrapper.java b/core/java/android/net/netstats/provider/NetworkStatsProviderWrapper.java deleted file mode 100644 index 4bf7c9bc086e..000000000000 --- a/core/java/android/net/netstats/provider/NetworkStatsProviderWrapper.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net.netstats.provider; - -import android.annotation.NonNull; - -/** - * A wrapper class of {@link INetworkStatsProvider} that hides the binder interface from exposing - * to outer world. - * - * @hide - */ -public class NetworkStatsProviderWrapper extends INetworkStatsProvider.Stub { - @NonNull final AbstractNetworkStatsProvider mProvider; - - public NetworkStatsProviderWrapper(AbstractNetworkStatsProvider provider) { - mProvider = provider; - } - - @Override - public void requestStatsUpdate(int token) { - mProvider.requestStatsUpdate(token); - } - - @Override - public void setLimit(@NonNull String iface, long quotaBytes) { - mProvider.setLimit(iface, quotaBytes); - } - - @Override - public void setAlert(long quotaBytes) { - mProvider.setAlert(quotaBytes); - } -} diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java index d320f61a3657..c61f10f50c93 100644 --- a/core/java/android/nfc/NfcAdapter.java +++ b/core/java/android/nfc/NfcAdapter.java @@ -245,13 +245,25 @@ public final class NfcAdapter { /** * Mandatory String extra field in {@link #ACTION_PREFERRED_PAYMENT_CHANGED} - * Indicates the condition when trigger this event. + * Indicates the condition when trigger this event. Possible values are: + * {@link #PREFERRED_PAYMENT_LOADED}, + * {@link #PREFERRED_PAYMENT_CHANGED}, + * {@link #PREFERRED_PAYMENT_UPDATED}, */ public static final String EXTRA_PREFERRED_PAYMENT_CHANGED_REASON = "android.nfc.extra.PREFERRED_PAYMENT_CHANGED_REASON"; - + /** + * Nfc is enabled and the preferred payment aids are registered. + */ public static final int PREFERRED_PAYMENT_LOADED = 1; + /** + * User selected another payment application as the preferred payment. + */ public static final int PREFERRED_PAYMENT_CHANGED = 2; + /** + * Current preferred payment has issued an update (registered/unregistered new aids or has been + * updated itself). + */ public static final int PREFERRED_PAYMENT_UPDATED = 3; public static final int STATE_OFF = 1; diff --git a/core/java/android/nfc/cardemulation/CardEmulation.java b/core/java/android/nfc/cardemulation/CardEmulation.java index f1c74a6331c4..7bf82e84927f 100644 --- a/core/java/android/nfc/cardemulation/CardEmulation.java +++ b/core/java/android/nfc/cardemulation/CardEmulation.java @@ -672,7 +672,7 @@ public final class CardEmulation { recoverService(); if (sService == null) { Log.e(TAG, "Failed to recover CardEmulationService."); - return null; + throw e.rethrowFromSystemServer(); } try { ApduServiceInfo serviceInfo = @@ -680,7 +680,7 @@ public final class CardEmulation { return (serviceInfo != null ? serviceInfo.getAids() : null); } catch (RemoteException ee) { Log.e(TAG, "Failed to recover CardEmulationService."); - return null; + throw e.rethrowFromSystemServer(); } } } @@ -690,9 +690,16 @@ public final class CardEmulation { * * @return The route destination secure element name of the preferred payment service. * HCE payment: "Host" - * OffHost payment: prefix SIM or prefix eSE string. - * "OffHost" if the payment service does not specify secure element - * name. + * OffHost payment: 1. String with prefix SIM or prefix eSE string. + * Ref: GSMA TS.26 - NFC Handset Requirements + * TS26_NFC_REQ_069: For UICC, Secure Element Name SHALL be + * SIM[smartcard slot] + * (e.g. SIM/SIM1, SIM2… SIMn). + * TS26_NFC_REQ_070: For embedded SE, Secure Element Name SHALL be + * eSE[number] + * (e.g. eSE/eSE1, eSE2, etc.). + * 2. "OffHost" if the payment service does not specify secure element + * name. */ @RequiresPermission(android.Manifest.permission.NFC_PREFERRED_PAYMENT_INFO) @Nullable @@ -711,7 +718,7 @@ public final class CardEmulation { recoverService(); if (sService == null) { Log.e(TAG, "Failed to recover CardEmulationService."); - return null; + throw e.rethrowFromSystemServer(); } try { ApduServiceInfo serviceInfo = @@ -727,7 +734,7 @@ public final class CardEmulation { } catch (RemoteException ee) { Log.e(TAG, "Failed to recover CardEmulationService."); - return null; + throw e.rethrowFromSystemServer(); } } } @@ -739,7 +746,7 @@ public final class CardEmulation { */ @RequiresPermission(android.Manifest.permission.NFC_PREFERRED_PAYMENT_INFO) @Nullable - public String getDescriptionForPreferredPaymentService() { + public CharSequence getDescriptionForPreferredPaymentService() { try { ApduServiceInfo serviceInfo = sService.getPreferredPaymentService(mContext.getUserId()); return (serviceInfo != null ? serviceInfo.getDescription() : null); @@ -747,7 +754,7 @@ public final class CardEmulation { recoverService(); if (sService == null) { Log.e(TAG, "Failed to recover CardEmulationService."); - return null; + throw e.rethrowFromSystemServer(); } try { ApduServiceInfo serviceInfo = @@ -755,7 +762,7 @@ public final class CardEmulation { return (serviceInfo != null ? serviceInfo.getDescription() : null); } catch (RemoteException ee) { Log.e(TAG, "Failed to recover CardEmulationService."); - return null; + throw e.rethrowFromSystemServer(); } } } diff --git a/core/java/android/permission/Permissions.md b/core/java/android/permission/Permissions.md index e62bd0a88bf6..e116dc6f37a1 100644 --- a/core/java/android/permission/Permissions.md +++ b/core/java/android/permission/Permissions.md @@ -49,6 +49,10 @@ The purpose of install time permissions is to control access to APIs where it do to involve the user. This can be either because the API is not sensitive, or because additional checks exist. +Another benefit of install time permissions is that is becomes very easy to monitor which apps can +access certain APIs. E.g. by checking which apps have the `android.permission.INTERNET` permission +you can list all apps that are allowed to use APIs that can send data to the internet. + #### Defining a permission Any package can define a permission. For that it simply adds an entry in the manifest file @@ -591,8 +595,9 @@ User 0: ### Permission restricted components As [publicly documented](https://developer.android.com/guide/topics/permissions/overview#permission_enforcement) -it is possible to restrict starting an activity/binding to a service by using permission. It is -a common pattern to +it is possible to restrict starting an activity/binding to a service by using permission. + +It is a common pattern to - define a permission in the platform as `signature` - protect a service in an app by this permission using the `android:permission` attribute of the @@ -605,6 +610,75 @@ accessibility services. This does not work for app-op or runtime permissions as the way to check these permissions is more complex than install time permissions. +#### End-to-end A service only the system can bind to + +Make sure to set the `android:permission` flag for this service. As developers can forget this it is +a good habit to check this before binding to the service. This makes sure that the services are +implemented correctly and no random app can bind to the service. + +The result is that the permission is granted only to the system. It is not granted to the service's +package, but this has no negative side-effects. + +##### Permission definition + +frameworks/base/core/res/AndroidManifest.xml: + +```xml +<manifest> +[...] + <permission android:name="android.permission.BIND_MY_SERVICE" + android:label="@string/permlab_bindMyService" + android:description="@string/permdesc_bindMyService" + android:protectionLevel="signature" /> +[...] +</manifest> +``` + +##### Service definition + +Manifest of the service providing the functionality: + +```xml +<manifest> + <service android:name="com.my.ServiceImpl" + android:permission="android.permission.BIND_MY_SERVICE"> + <!-- add an intent filter so that the system can find this package --> + <intent-filter> + <action android:name="android.my.Service" /> + </intent-filter> + </service> +</manifest> +``` + +##### System server code binding to service + +```kotlin +val serviceConnections = mutableListOf<ServiceConnection>() + +val potentialServices = context.packageManager.queryIntentServicesAsUser( + Intent("android.my.Service"), GET_SERVICES or GET_META_DATA, userId) + +for (val ri in potentialServices) { + val serviceComponent = ComponentName(ri.serviceInfo.packageName, ri.serviceInfo.name) + + if (android.Manifest.permission.BIND_MY_SERVICE != ri.serviceInfo.permission) { + Slog.w(TAG, "$serviceComponent is not protected by " + + "${android.Manifest.permission.BIND_MY_SERVICE}") + continue + } + + val newConnection = object : ServiceConnection { + ... + } + + val wasBound = context.bindServiceAsUser(Intent().setComponent(serviceComponent), + serviceConnection, BIND_AUTO_CREATE, UserHandle.of(userId)) + if (wasBound) { + serviceConnections.add(newConnection) + } +} +``` + ## Permissions for system apps System apps need to integrate deeper with the system than regular apps. Hence they need to be diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java index e7b360da47b8..17e3748f15d8 100644 --- a/core/java/android/provider/Telephony.java +++ b/core/java/android/provider/Telephony.java @@ -1391,7 +1391,6 @@ public final class Telephony { * Base column for the table that contain Carrier Public key. * @hide */ - @SystemApi public interface CarrierColumns extends BaseColumns { /** @@ -4704,7 +4703,6 @@ public final class Telephony { * Contains mappings between matching rules with carrier id for all carriers. * @hide */ - @SystemApi public static final class All implements BaseColumns { /** diff --git a/core/java/android/se/omapi/Reader.java b/core/java/android/se/omapi/Reader.java index 7f68d9188650..90c934d189fa 100644 --- a/core/java/android/se/omapi/Reader.java +++ b/core/java/android/se/omapi/Reader.java @@ -160,7 +160,7 @@ public final class Reader { * @hide */ @SystemApi - @RequiresPermission(android.Manifest.permission.SECURE_ELEMENT_PRIVILEGED) + @RequiresPermission(android.Manifest.permission.SECURE_ELEMENT_PRIVILEGED_OPERATION) public boolean reset() { if (!mService.isConnected()) { Log.e(TAG, "service is not connected"); diff --git a/core/java/android/telephony/PhoneStateListener.java b/core/java/android/telephony/PhoneStateListener.java index d2735008611c..28db2708988e 100644 --- a/core/java/android/telephony/PhoneStateListener.java +++ b/core/java/android/telephony/PhoneStateListener.java @@ -176,7 +176,6 @@ public class PhoneStateListener { * @hide */ @RequiresPermission(android.Manifest.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH) - @SystemApi public static final int LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH = 0x00000200; /** diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java index cfbe393bfcc8..4dafc0df2013 100644 --- a/core/java/android/util/FeatureFlagUtils.java +++ b/core/java/android/util/FeatureFlagUtils.java @@ -67,9 +67,9 @@ public class FeatureFlagUtils { DEFAULT_FLAGS.put("settings_controller_loading_enhancement", "false"); DEFAULT_FLAGS.put("settings_conditionals", "false"); DEFAULT_FLAGS.put(NOTIF_CONVO_BYPASS_SHORTCUT_REQ, "true"); - // Disabled by default until b/148278926 is resolved. This flags guards a feature - // introduced in R and will be removed in the next release (b/148367230). - DEFAULT_FLAGS.put(SETTINGS_DO_NOT_RESTORE_PRESERVED, "false"); + // This flags guards a feature introduced in R and will be removed in the next release + // (b/148367230). + DEFAULT_FLAGS.put(SETTINGS_DO_NOT_RESTORE_PRESERVED, "true"); DEFAULT_FLAGS.put("settings_tether_all_in_one", "false"); DEFAULT_FLAGS.put(SETTINGS_SCHEDULES_FLAG, "false"); diff --git a/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java b/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java index 79eb9f6e749c..2437af26770b 100644 --- a/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java +++ b/core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java @@ -213,15 +213,24 @@ public class ApkSignatureSchemeV3Verifier { verityDigest, apk.length(), signatureInfo); } - if (contentDigests.containsKey(CONTENT_DIGEST_CHUNKED_SHA512)) { - result.digest = contentDigests.get(CONTENT_DIGEST_CHUNKED_SHA512); - } else if (contentDigests.containsKey(CONTENT_DIGEST_CHUNKED_SHA256)) { - result.digest = contentDigests.get(CONTENT_DIGEST_CHUNKED_SHA256); - } + result.digest = pickBestV3DigestForV4(contentDigests); return result; } + // Keep in sync with pickBestV3DigestForV4 in apksigner.V3SchemeVerifier. + private static byte[] pickBestV3DigestForV4(Map<Integer, byte[]> contentDigests) { + final int[] orderedContentDigestTypes = + {CONTENT_DIGEST_CHUNKED_SHA512, CONTENT_DIGEST_VERITY_CHUNKED_SHA256, + CONTENT_DIGEST_CHUNKED_SHA256}; + for (int contentDigestType : orderedContentDigestTypes) { + if (contentDigests.containsKey(contentDigestType)) { + return contentDigests.get(contentDigestType); + } + } + return null; + } + private static VerifiedSigner verifySigner( ByteBuffer signerBlock, Map<Integer, byte[]> contentDigests, diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java index 0dcb9cc5256e..dffcafe1de0e 100644 --- a/core/java/android/view/Display.java +++ b/core/java/android/view/Display.java @@ -1307,6 +1307,15 @@ public final class Display { } /** + * Returns true if the display is in active state such as {@link #STATE_ON} + * or {@link #STATE_VR}. + * @hide + */ + public static boolean isActiveState(int state) { + return state == STATE_ON || state == STATE_VR; + } + + /** * A mode supported by a given display. * * @see Display#getSupportedModes() diff --git a/core/java/android/view/textclassifier/TextClassificationContext.java b/core/java/android/view/textclassifier/TextClassificationContext.java index f2323c625d15..5d5683f7110e 100644 --- a/core/java/android/view/textclassifier/TextClassificationContext.java +++ b/core/java/android/view/textclassifier/TextClassificationContext.java @@ -31,7 +31,6 @@ import java.util.Objects; */ public final class TextClassificationContext implements Parcelable { - // NOTE: Modify packageName only in the constructor or in setSystemTextClassifierMetadata() private String mPackageName; private final String mWidgetType; @Nullable private final String mWidgetVersion; @@ -47,7 +46,7 @@ public final class TextClassificationContext implements Parcelable { } /** - * Returns the package name for the calling package. + * Returns the package name of the app that this context originated in. */ @NonNull public String getPackageName() { @@ -57,14 +56,10 @@ public final class TextClassificationContext implements Parcelable { /** * Sets the information about the {@link SystemTextClassifier} that sent this request. * - * <p><b>NOTE: </b>This will override the value returned in {@link getPackageName()}. * @hide */ void setSystemTextClassifierMetadata(@Nullable SystemTextClassifierMetadata systemTcMetadata) { mSystemTcMetadata = systemTcMetadata; - if (mSystemTcMetadata != null) { - mPackageName = mSystemTcMetadata.getCallingPackageName(); - } } /** diff --git a/core/java/com/android/internal/os/KernelCpuThreadReaderDiff.java b/core/java/com/android/internal/os/KernelCpuThreadReaderDiff.java index ffdc33c64f69..c11b939098c4 100644 --- a/core/java/com/android/internal/os/KernelCpuThreadReaderDiff.java +++ b/core/java/com/android/internal/os/KernelCpuThreadReaderDiff.java @@ -16,6 +16,8 @@ package com.android.internal.os; +import static com.android.internal.util.Preconditions.checkNotNull; + import android.annotation.Nullable; import android.util.ArrayMap; import android.util.Slog; @@ -99,7 +101,7 @@ public class KernelCpuThreadReaderDiff { @VisibleForTesting public KernelCpuThreadReaderDiff(KernelCpuThreadReader reader, int minimumTotalCpuUsageMillis) { - mReader = reader; + mReader = checkNotNull(reader); mMinimumTotalCpuUsageMillis = minimumTotalCpuUsageMillis; mPreviousCpuUsage = null; } diff --git a/core/java/com/android/internal/os/KernelCpuThreadReaderSettingsObserver.java b/core/java/com/android/internal/os/KernelCpuThreadReaderSettingsObserver.java index fdcc8a8c9cbf..c908b8cb7264 100644 --- a/core/java/com/android/internal/os/KernelCpuThreadReaderSettingsObserver.java +++ b/core/java/com/android/internal/os/KernelCpuThreadReaderSettingsObserver.java @@ -95,8 +95,10 @@ public class KernelCpuThreadReaderSettingsObserver extends ContentObserver { KernelCpuThreadReader.create( NUM_BUCKETS_DEFAULT, UidPredicate.fromString(COLLECTED_UIDS_DEFAULT)); mKernelCpuThreadReaderDiff = - new KernelCpuThreadReaderDiff( - mKernelCpuThreadReader, MINIMUM_TOTAL_CPU_USAGE_MILLIS_DEFAULT); + mKernelCpuThreadReader == null + ? null + : new KernelCpuThreadReaderDiff( + mKernelCpuThreadReader, MINIMUM_TOTAL_CPU_USAGE_MILLIS_DEFAULT); } @Override diff --git a/core/proto/android/os/incident.proto b/core/proto/android/os/incident.proto index d6687f08b542..64cf75d51c3d 100644 --- a/core/proto/android/os/incident.proto +++ b/core/proto/android/os/incident.proto @@ -376,8 +376,7 @@ message IncidentProto { optional bytes system_trace = 3026 [ (section).type = SECTION_FILE, (section).args = "/data/misc/perfetto-traces/incident-trace", - (privacy).dest = DEST_AUTOMATIC, - (section).userdebug_and_eng_only = true + (privacy).dest = DEST_AUTOMATIC ]; // Dropbox entries split by tags. diff --git a/core/proto/android/util/quotatracker.proto b/core/proto/android/util/quotatracker.proto index 5d022ed6327b..d98e5eea30d2 100644 --- a/core/proto/android/util/quotatracker.proto +++ b/core/proto/android/util/quotatracker.proto @@ -131,93 +131,3 @@ message CountQuotaTrackerProto { // Next tag: 4 } - -// A com.android.util.quota.DurationQuotaTracker object. -message DurationQuotaTrackerProto { - option (.android.msg_privacy).dest = DEST_AUTOMATIC; - - optional QuotaTrackerProto base_quota_data = 1; - - message DurationLimit { - option (.android.msg_privacy).dest = DEST_AUTOMATIC; - - optional CategoryProto category = 1; - optional int64 limit_ms = 2; - optional int64 window_size_ms = 3; - } - repeated DurationLimit duration_limit = 2; - - message ExecutionStats { - option (.android.msg_privacy).dest = DEST_AUTOMATIC; - - // The time after which this record should be considered invalid (out of date), in the - // elapsed realtime timebase. - optional int64 expiration_time_elapsed = 1; - - optional int32 window_size_ms = 2; - optional int64 duration_limit_ms = 3; - - // The overall session duration in the window. - optional int64 session_duration_in_window_ms = 4; - // The number of individual long-running events in the window. - optional int32 event_count_in_window = 5; - - // The time after which the app will be under the bucket quota. This is only valid if - // session_duration_in_window_ms >= duration_limit_ms. - optional int64 in_quota_time_elapsed = 6; - } - - message Timer { - option (.android.msg_privacy).dest = DEST_AUTOMATIC; - - // True if the Timer is actively tracking long-running events. - optional bool is_active = 1; - // The time this timer last became active. Only valid if is_active is true. - optional int64 start_time_elapsed = 2; - // How many long-running events are currently running. Valid only if is_active is true. - optional int32 event_count = 3; - } - - message TimingSession { - option (.android.msg_privacy).dest = DEST_AUTOMATIC; - - optional int64 start_time_elapsed = 1; - optional int64 end_time_elapsed = 2; - // How many events started during this session. This only count long-running events, not - // instantaneous events. - optional int32 event_count = 3; - } - - message UptcStats { - option (.android.msg_privacy).dest = DEST_AUTOMATIC; - - optional UptcProto uptc = 1; - - // True if the UPTC has been given free quota. - optional bool is_quota_free = 2; - - optional Timer timer = 3; - - repeated TimingSession saved_sessions = 4; - - repeated ExecutionStats execution_stats = 5; - } - repeated UptcStats uptc_stats = 3; - - message ReachedQuotaAlarmListener { - option (.android.msg_privacy).dest = DEST_AUTOMATIC; - - optional int64 trigger_time_elapsed = 1; - - message UptcTimes { - option (.android.msg_privacy).dest = DEST_AUTOMATIC; - - optional UptcProto uptc = 1; - optional int64 out_of_quota_time_elapsed = 2; - } - repeated UptcTimes uptc_times = 2; - } - optional ReachedQuotaAlarmListener reached_quota_alarm_listener = 4; - - // Next tag: 5 -} diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 7a3ec9555f7c..f7400bd79a92 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -1689,6 +1689,10 @@ <permission android:name="android.permission.NETWORK_FACTORY" android:protectionLevel="signature" /> + <!-- @SystemApi @hide Allows applications to access network stats provider --> + <permission android:name="android.permission.NETWORK_STATS_PROVIDER" + android:protectionLevel="signature" /> + <!-- Allows Settings and SystemUI to call methods in Networking services <p>Not for use by third-party or privileged applications. @SystemApi @TestApi @@ -1841,7 +1845,7 @@ and bypass OMAPI AccessControlEnforcer. <p>Not for use by third-party applications. @hide --> - <permission android:name="android.permission.SECURE_ELEMENT_PRIVILEGED" + <permission android:name="android.permission.SECURE_ELEMENT_PRIVILEGED_OPERATION" android:protectionLevel="signature|privileged" /> <!-- @deprecated This permission used to allow too broad access to sensitive methods and all its diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index ff49c45b965b..26024ed34bc3 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -2985,72 +2985,6 @@ <!-- Title for EditText context menu [CHAR LIMIT=20] --> <string name="editTextMenuTitle">Text actions</string> - <!-- Label for item in the text selection menu to trigger an Email app. Should be a verb. [CHAR LIMIT=30] --> - <string name="email">Email</string> - - <!-- Accessibility description for an item in the text selection menu to trigger an Email app [CHAR LIMIT=NONE] --> - <string name="email_desc">Email selected address</string> - - <!-- Label for item in the text selection menu to trigger a Dialer app. Should be a verb. [CHAR LIMIT=30] --> - <string name="dial">Call</string> - - <!-- Accessibility description for an item in the text selection menu to call a phone number [CHAR LIMIT=NONE] --> - <string name="dial_desc">Call selected phone number</string> - - <!-- Label for item in the text selection menu to trigger a Map app. Should be a verb. [CHAR LIMIT=30] --> - <string name="map">Map</string> - - <!-- Accessibility description for an item in the text selection menu to open maps for an address [CHAR LIMIT=NONE] --> - <string name="map_desc">Locate selected address</string> - - <!-- Label for item in the text selection menu to trigger a Browser app. Should be a verb. [CHAR LIMIT=30] --> - <string name="browse">Open</string> - - <!-- Accessibility description for an item in the text selection menu to open a URL in a browser [CHAR LIMIT=NONE] --> - <string name="browse_desc">Open selected URL</string> - - <!-- Label for item in the text selection menu to trigger an SMS app. Should be a verb. [CHAR LIMIT=30] --> - <string name="sms">Message</string> - - <!-- Accessibility description for an item in the text selection menu to send an SMS to a phone number [CHAR LIMIT=NONE] --> - <string name="sms_desc">Message selected phone number</string> - - <!-- Label for item in the text selection menu to trigger adding a contact. Should be a verb. [CHAR LIMIT=30] --> - <string name="add_contact">Add</string> - - <!-- Accessibility description for an item in the text selection menu to add the selected detail to contacts [CHAR LIMIT=NONE] --> - <string name="add_contact_desc">Add to contacts</string> - - <!-- Label for item in the text selection menu to view the calendar for the selected time/date. Should be a verb. [CHAR LIMIT=30] --> - <string name="view_calendar">View</string> - - <!-- Accessibility description for an item in the text selection menu to view the calendar for a date [CHAR LIMIT=NONE]--> - <string name="view_calendar_desc">View selected time in calendar</string> - - <!-- Label for item in the text selection menu to create a calendar event at the selected time/date. Should be a verb. [CHAR LIMIT=30] --> - <string name="add_calendar_event">Schedule</string> - - <!-- Accessibility description for an item in the text selection menu to schedule an event for a date [CHAR LIMIT=NONE] --> - <string name="add_calendar_event_desc">Schedule event for selected time</string> - - <!-- Label for item in the text selection menu to track a selected flight number. Should be a verb. [CHAR LIMIT=30] --> - <string name="view_flight">Track</string> - - <!-- Accessibility description for an item in the text selection menu to track a flight [CHAR LIMIT=NONE] --> - <string name="view_flight_desc">Track selected flight</string> - - <!-- Label for item in the text selection menu to translate selected text with a translation app. Should be a verb. [CHAR LIMIT=30] --> - <string name="translate">Translate</string> - - <!-- Accessibility description for an item in the text selection menu to translate selected text with a translation app. [CHAR LIMIT=NONE] --> - <string name="translate_desc">Translate selected text</string> - - <!-- Label for item in the text selection menu to define selected text with a dictionary app. Should be a verb. [CHAR LIMIT=30] --> - <string name="define">Define</string> - - <!-- Accessibility description for an item in the text selection menu to define selected text with a dictionary app. Should be a verb. [CHAR LIMIT=NONE] --> - <string name="define_desc">Define selected text</string> - <!-- If the device is getting low on internal storage, a notification is shown to the user. This is the title of that notification. --> <string name="low_internal_storage_view_title">Storage space running out</string> <!-- If the device is getting low on internal storage, a notification is shown to the user. This is the message of that notification. --> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 9e3e864a0d18..8919c028a011 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -551,28 +551,6 @@ <java-symbol type="string" name="replace" /> <java-symbol type="string" name="undo" /> <java-symbol type="string" name="redo" /> - <java-symbol type="string" name="email" /> - <java-symbol type="string" name="email_desc" /> - <java-symbol type="string" name="dial" /> - <java-symbol type="string" name="dial_desc" /> - <java-symbol type="string" name="map" /> - <java-symbol type="string" name="map_desc" /> - <java-symbol type="string" name="browse" /> - <java-symbol type="string" name="browse_desc" /> - <java-symbol type="string" name="sms" /> - <java-symbol type="string" name="sms_desc" /> - <java-symbol type="string" name="add_contact" /> - <java-symbol type="string" name="add_contact_desc" /> - <java-symbol type="string" name="view_calendar" /> - <java-symbol type="string" name="view_calendar_desc" /> - <java-symbol type="string" name="add_calendar_event" /> - <java-symbol type="string" name="add_calendar_event_desc" /> - <java-symbol type="string" name="view_flight" /> - <java-symbol type="string" name="view_flight_desc" /> - <java-symbol type="string" name="translate" /> - <java-symbol type="string" name="translate_desc" /> - <java-symbol type="string" name="define" /> - <java-symbol type="string" name="define_desc" /> <java-symbol type="string" name="textSelectionCABTitle" /> <java-symbol type="string" name="BaMmi" /> <java-symbol type="string" name="CLIRDefaultOffNextCallOff" /> diff --git a/core/tests/bandwidthtests/src/com/android/bandwidthtest/BandwidthTest.java b/core/tests/bandwidthtests/src/com/android/bandwidthtest/BandwidthTest.java index 5d42915fc82b..4b42f4ae9888 100644 --- a/core/tests/bandwidthtests/src/com/android/bandwidthtest/BandwidthTest.java +++ b/core/tests/bandwidthtests/src/com/android/bandwidthtest/BandwidthTest.java @@ -268,7 +268,7 @@ public class BandwidthTest extends InstrumentationTestCase { File snd_stat = new File (root_filepath + "tcp_snd"); int tx = BandwidthTestUtil.parseIntValueFromFile(snd_stat); NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 1); - stats.addEntry(NetworkStats.IFACE_ALL, uid, NetworkStats.SET_DEFAULT, + stats.insertEntry(NetworkStats.IFACE_ALL, uid, NetworkStats.SET_DEFAULT, NetworkStats.TAG_NONE, rx, 0, tx, 0, 0); return stats; } diff --git a/core/tests/benchmarks/src/android/net/NetworkStatsBenchmark.java b/core/tests/benchmarks/src/android/net/NetworkStatsBenchmark.java index 239f971664e9..3ebe1039d975 100644 --- a/core/tests/benchmarks/src/android/net/NetworkStatsBenchmark.java +++ b/core/tests/benchmarks/src/android/net/NetworkStatsBenchmark.java @@ -54,7 +54,7 @@ public class NetworkStatsBenchmark { recycle.txBytes = 150000; recycle.txPackets = 1500; recycle.operations = 0; - mNetworkStats.addEntry(recycle); + mNetworkStats.insertEntry(recycle); if (recycle.set == 1) { uid++; } @@ -70,7 +70,7 @@ public class NetworkStatsBenchmark { recycle.txBytes = 180000 * mSize; recycle.txPackets = 1200 * mSize; recycle.operations = 0; - mNetworkStats.addEntry(recycle); + mNetworkStats.insertEntry(recycle); } } diff --git a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java index c328d720426d..90d8bab84258 100644 --- a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java +++ b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java @@ -40,7 +40,10 @@ import android.app.servertransaction.ResumeActivityItem; import android.app.servertransaction.StopActivityItem; import android.content.Intent; import android.content.res.Configuration; +import android.content.res.Resources; +import android.graphics.Rect; import android.os.IBinder; +import android.util.DisplayMetrics; import android.util.MergedConfiguration; import android.view.Display; import android.view.View; @@ -307,6 +310,58 @@ public class ActivityThreadTest { } @Test + public void testHandleConfigurationChangedDoesntOverrideActivityConfig() { + final TestActivity activity = mActivityTestRule.launchActivity(new Intent()); + + InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> { + final Configuration oldActivityConfig = + new Configuration(activity.getResources().getConfiguration()); + final DisplayMetrics oldActivityMetrics = new DisplayMetrics(); + activity.getDisplay().getMetrics(oldActivityMetrics); + final Resources oldAppResources = activity.getApplication().getResources(); + final Configuration oldAppConfig = + new Configuration(oldAppResources.getConfiguration()); + final DisplayMetrics oldApplicationMetrics = new DisplayMetrics(); + oldApplicationMetrics.setTo(oldAppResources.getDisplayMetrics()); + assertEquals("Process config must match the top activity config by default", + 0, oldActivityConfig.diffPublicOnly(oldAppConfig)); + assertEquals("Process config must match the top activity config by default", + oldActivityMetrics, oldApplicationMetrics); + + // Update the application configuration separately from activity config + final Configuration newAppConfig = new Configuration(oldAppConfig); + newAppConfig.densityDpi += 100; + newAppConfig.screenHeightDp += 100; + final Rect newBounds = new Rect(newAppConfig.windowConfiguration.getAppBounds()); + newBounds.bottom += 100; + newAppConfig.windowConfiguration.setAppBounds(newBounds); + newAppConfig.windowConfiguration.setBounds(newBounds); + newAppConfig.seq++; + + final ActivityThread activityThread = activity.getActivityThread(); + activityThread.handleConfigurationChanged(newAppConfig); + + // Verify that application config update was applied, but didn't change activity config. + assertEquals("Activity config must not change if the process config changes", + oldActivityConfig, activity.getResources().getConfiguration()); + + final DisplayMetrics newActivityMetrics = new DisplayMetrics(); + activity.getDisplay().getMetrics(newActivityMetrics); + assertEquals("Activity display size must not change if the process config changes", + oldActivityMetrics, newActivityMetrics); + final Resources newAppResources = activity.getApplication().getResources(); + assertEquals("Application config must be updated", + newAppConfig, newAppResources.getConfiguration()); + final DisplayMetrics newApplicationMetrics = new DisplayMetrics(); + newApplicationMetrics.setTo(newAppResources.getDisplayMetrics()); + assertNotEquals("Application display size must be updated after config update", + oldApplicationMetrics, newApplicationMetrics); + assertNotEquals("Application display size must be updated after config update", + newActivityMetrics, newApplicationMetrics); + }); + } + + @Test public void testResumeAfterNewIntent() { final Activity activity = mActivityTestRule.launchActivity(new Intent()); final ActivityThread activityThread = activity.getActivityThread(); diff --git a/data/etc/com.android.launcher3.xml b/data/etc/com.android.launcher3.xml index 337e153722ac..17d614e3409c 100644 --- a/data/etc/com.android.launcher3.xml +++ b/data/etc/com.android.launcher3.xml @@ -19,5 +19,6 @@ <permission name="android.permission.BIND_APPWIDGET"/> <permission name="android.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS"/> <permission name="android.permission.GET_ACCOUNTS_PRIVILEGED"/> + <permission name="android.permission.WRITE_SECURE_SETTINGS"/> </privapp-permissions> </permissions> diff --git a/media/java/android/media/MediaCas.java b/media/java/android/media/MediaCas.java index 3a771bba03b9..ad9486cc6597 100644 --- a/media/java/android/media/MediaCas.java +++ b/media/java/android/media/MediaCas.java @@ -870,16 +870,17 @@ public final class MediaCas implements AutoCloseable { private int getSessionResourceId() throws MediaCasException { validateInternalStates(); - int[] sessionResourceId = new int[1]; - sessionResourceId[0] = -1; + int[] sessionResourceHandle = new int[1]; + sessionResourceHandle[0] = -1; if (mTunerResourceManager != null) { CasSessionRequest casSessionRequest = new CasSessionRequest(mClientId, mCasSystemId); - if (!mTunerResourceManager.requestCasSession(casSessionRequest, sessionResourceId)) { - throw new MediaCasException.ResourceBusyException( + if (!mTunerResourceManager + .requestCasSession(casSessionRequest, sessionResourceHandle)) { + throw new MediaCasException.InsufficientResourceException( "insufficient resource to Open Session"); } } - return sessionResourceId[0]; + return sessionResourceHandle[0]; } private void addSessionToResourceMap(Session session, int sessionResourceId) { @@ -905,6 +906,10 @@ public final class MediaCas implements AutoCloseable { * Open a session to descramble one or more streams scrambled by the * conditional access system. * + * <p>Tuner resource manager (TRM) uses the client priority value to decide whether it is able + * to get cas session resource if cas session resources is limited. If the client can't get the + * resource, this call returns {@link MediaCasException.InsufficientResourceException }. + * * @return session the newly opened session. * * @throws IllegalStateException if the MediaCas instance is not valid. @@ -930,6 +935,10 @@ public final class MediaCas implements AutoCloseable { * Open a session with usage and scrambling information, so that descrambler can be configured * to descramble one or more streams scrambled by the conditional access system. * + * <p>Tuner resource manager (TRM) uses the client priority value to decide whether it is able + * to get cas session resource if cas session resources is limited. If the client can't get the + * resource, this call returns {@link MediaCasException.InsufficientResourceException}. + * * @param sessionUsage used for the created session. * @param scramblingMode used for the created session. * diff --git a/media/java/android/media/audiofx/Visualizer.java b/media/java/android/media/audiofx/Visualizer.java index 392e8fe7543f..a5da648cf14a 100644 --- a/media/java/android/media/audiofx/Visualizer.java +++ b/media/java/android/media/audiofx/Visualizer.java @@ -20,9 +20,10 @@ import android.app.ActivityThread; import android.compat.annotation.UnsupportedAppUsage; import android.os.Handler; import android.os.Looper; -import android.os.Message; import android.util.Log; +import com.android.internal.annotations.GuardedBy; + import java.lang.ref.WeakReference; /** @@ -158,6 +159,7 @@ public class Visualizer { /** * Indicates the state of the Visualizer instance */ + @GuardedBy("mStateLock") private int mState = STATE_UNINITIALIZED; /** * Lock to synchronize access to mState @@ -166,6 +168,7 @@ public class Visualizer { /** * System wide unique Identifier of the visualizer engine used by this Visualizer instance */ + @GuardedBy("mStateLock") @UnsupportedAppUsage private int mId; @@ -176,19 +179,24 @@ public class Visualizer { /** * Handler for events coming from the native code */ - private NativeEventHandler mNativeEventHandler = null; + @GuardedBy("mListenerLock") + private Handler mNativeEventHandler = null; /** * PCM and FFT capture listener registered by client */ + @GuardedBy("mListenerLock") private OnDataCaptureListener mCaptureListener = null; /** * Server Died listener registered by client */ + @GuardedBy("mListenerLock") private OnServerDiedListener mServerDiedListener = null; // accessed by native methods - private long mNativeVisualizer; - private long mJniData; + private long mNativeVisualizer; // guarded by a static lock in native code + private long mJniData; // set in native_setup, _release; + // get in native_release, _setEnabled, _setPeriodicCapture + // thus, effectively guarded by mStateLock //-------------------------------------------------------------------------- // Constructor, Finalize @@ -244,7 +252,9 @@ public class Visualizer { @Override protected void finalize() { - native_finalize(); + synchronized (mStateLock) { + native_finalize(); + } } /** @@ -601,25 +611,28 @@ public class Visualizer { */ public int setDataCaptureListener(OnDataCaptureListener listener, int rate, boolean waveform, boolean fft) { - synchronized (mListenerLock) { - mCaptureListener = listener; - } if (listener == null) { // make sure capture callback is stopped in native code waveform = false; fft = false; } - int status = native_setPeriodicCapture(rate, waveform, fft); + int status; + synchronized (mStateLock) { + status = native_setPeriodicCapture(rate, waveform, fft); + } if (status == SUCCESS) { - if ((listener != null) && (mNativeEventHandler == null)) { - Looper looper; - if ((looper = Looper.myLooper()) != null) { - mNativeEventHandler = new NativeEventHandler(this, looper); - } else if ((looper = Looper.getMainLooper()) != null) { - mNativeEventHandler = new NativeEventHandler(this, looper); - } else { - mNativeEventHandler = null; - status = ERROR_NO_INIT; + synchronized (mListenerLock) { + mCaptureListener = listener; + if ((listener != null) && (mNativeEventHandler == null)) { + Looper looper; + if ((looper = Looper.myLooper()) != null) { + mNativeEventHandler = new Handler(looper); + } else if ((looper = Looper.getMainLooper()) != null) { + mNativeEventHandler = new Handler(looper); + } else { + mNativeEventHandler = null; + status = ERROR_NO_INIT; + } } } } @@ -663,112 +676,61 @@ public class Visualizer { return SUCCESS; } - /** - * Helper class to handle the forwarding of native events to the appropriate listeners - */ - private class NativeEventHandler extends Handler - { - private Visualizer mVisualizer; - - public NativeEventHandler(Visualizer v, Looper looper) { - super(looper); - mVisualizer = v; - } - - private void handleCaptureMessage(Message msg) { - OnDataCaptureListener l = null; - synchronized (mListenerLock) { - l = mVisualizer.mCaptureListener; - } - - if (l != null) { - byte[] data = (byte[])msg.obj; - int samplingRate = msg.arg1; - - switch(msg.what) { - case NATIVE_EVENT_PCM_CAPTURE: - l.onWaveFormDataCapture(mVisualizer, data, samplingRate); - break; - case NATIVE_EVENT_FFT_CAPTURE: - l.onFftDataCapture(mVisualizer, data, samplingRate); - break; - default: - Log.e(TAG,"Unknown native event in handleCaptureMessge: "+msg.what); - break; - } - } - } - - private void handleServerDiedMessage(Message msg) { - OnServerDiedListener l = null; - synchronized (mListenerLock) { - l = mVisualizer.mServerDiedListener; - } - - if (l != null) - l.onServerDied(); - } - - @Override - public void handleMessage(Message msg) { - if (mVisualizer == null) { - return; - } - - switch(msg.what) { - case NATIVE_EVENT_PCM_CAPTURE: - case NATIVE_EVENT_FFT_CAPTURE: - handleCaptureMessage(msg); - break; - case NATIVE_EVENT_SERVER_DIED: - handleServerDiedMessage(msg); - break; - default: - Log.e(TAG,"Unknown native event: "+msg.what); - break; - } - } - } - //--------------------------------------------------------- // Interface definitions //-------------------- private static native final void native_init(); + @GuardedBy("mStateLock") private native final int native_setup(Object audioeffect_this, int audioSession, int[] id, String opPackageName); + @GuardedBy("mStateLock") private native final void native_finalize(); + @GuardedBy("mStateLock") private native final void native_release(); + @GuardedBy("mStateLock") private native final int native_setEnabled(boolean enabled); + @GuardedBy("mStateLock") private native final boolean native_getEnabled(); + @GuardedBy("mStateLock") private native final int native_setCaptureSize(int size); + @GuardedBy("mStateLock") private native final int native_getCaptureSize(); + @GuardedBy("mStateLock") private native final int native_setScalingMode(int mode); + @GuardedBy("mStateLock") private native final int native_getScalingMode(); + @GuardedBy("mStateLock") private native final int native_setMeasurementMode(int mode); + @GuardedBy("mStateLock") private native final int native_getMeasurementMode(); + @GuardedBy("mStateLock") private native final int native_getSamplingRate(); + @GuardedBy("mStateLock") private native final int native_getWaveForm(byte[] waveform); + @GuardedBy("mStateLock") private native final int native_getFft(byte[] fft); + @GuardedBy("mStateLock") private native final int native_getPeakRms(MeasurementPeakRms measurement); + @GuardedBy("mStateLock") private native final int native_setPeriodicCapture(int rate, boolean waveForm, boolean fft); //--------------------------------------------------------- @@ -776,17 +738,47 @@ public class Visualizer { //-------------------- @SuppressWarnings("unused") private static void postEventFromNative(Object effect_ref, - int what, int arg1, int arg2, Object obj) { - Visualizer visu = (Visualizer)((WeakReference)effect_ref).get(); - if (visu == null) { - return; - } + int what, int samplingRate, byte[] data) { + final Visualizer visualizer = (Visualizer) ((WeakReference) effect_ref).get(); + if (visualizer == null) return; - if (visu.mNativeEventHandler != null) { - Message m = visu.mNativeEventHandler.obtainMessage(what, arg1, arg2, obj); - visu.mNativeEventHandler.sendMessage(m); + final Handler handler; + synchronized (visualizer.mListenerLock) { + handler = visualizer.mNativeEventHandler; } + if (handler == null) return; + switch (what) { + case NATIVE_EVENT_PCM_CAPTURE: + case NATIVE_EVENT_FFT_CAPTURE: + handler.post(() -> { + final OnDataCaptureListener l; + synchronized (visualizer.mListenerLock) { + l = visualizer.mCaptureListener; + } + if (l != null) { + if (what == NATIVE_EVENT_PCM_CAPTURE) { + l.onWaveFormDataCapture(visualizer, data, samplingRate); + } else { // what == NATIVE_EVENT_FFT_CAPTURE + l.onFftDataCapture(visualizer, data, samplingRate); + } + } + }); + break; + case NATIVE_EVENT_SERVER_DIED: + handler.post(() -> { + final OnServerDiedListener l; + synchronized (visualizer.mListenerLock) { + l = visualizer.mServerDiedListener; + } + if (l != null) { + l.onServerDied(); + } + }); + break; + default: + Log.e(TAG, "Unknown native event in postEventFromNative: " + what); + break; + } } } - diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java index 824255995de0..d24d75260395 100644 --- a/media/java/android/media/tv/tuner/Tuner.java +++ b/media/java/android/media/tv/tuner/Tuner.java @@ -43,6 +43,7 @@ import android.media.tv.tuner.frontend.FrontendStatus.FrontendStatusType; import android.media.tv.tuner.frontend.OnTuneEventListener; import android.media.tv.tuner.frontend.ScanCallback; import android.media.tv.tunerresourcemanager.ResourceClientProfile; +import android.media.tv.tunerresourcemanager.TunerFrontendRequest; import android.media.tv.tunerresourcemanager.TunerLnbRequest; import android.media.tv.tunerresourcemanager.TunerResourceManager; import android.os.Handler; @@ -195,15 +196,15 @@ public class Tuner implements AutoCloseable { private final TunerResourceManager mTunerResourceManager; private final int mClientId; - private List<Integer> mFrontendIds; private Frontend mFrontend; private EventHandler mHandler; @Nullable private FrontendInfo mFrontendInfo; + private Integer mFrontendHandle; + private int mFrontendType = FrontendSettings.TYPE_UNDEFINED; - private List<Integer> mLnbIds; private Lnb mLnb; - private Integer mLnbId; + private Integer mLnbHandle; @Nullable private OnTuneEventListener mOnTuneEventListener; @Nullable @@ -327,7 +328,7 @@ public class Tuner implements AutoCloseable { /** * Native method to open frontend of the given ID. */ - private native Frontend nativeOpenFrontendById(int id); + private native Frontend nativeOpenFrontendByHandle(int handle); private native int nativeTune(int type, FrontendSettings settings); private native int nativeStopTune(); private native int nativeScan(int settingsType, FrontendSettings settings, int scanType); @@ -344,7 +345,7 @@ public class Tuner implements AutoCloseable { private native TimeFilter nativeOpenTimeFilter(); private native List<Integer> nativeGetLnbIds(); - private native Lnb nativeOpenLnbById(int id); + private native Lnb nativeOpenLnbByHandle(int handle); private native Lnb nativeOpenLnbByName(String name); private native Descrambler nativeOpenDescrambler(); @@ -453,6 +454,10 @@ public class Tuner implements AutoCloseable { /** * Tunes the frontend to using the settings given. * + * <p>Tuner resource manager (TRM) uses the client priority value to decide whether it is able + * to get frontend resource. If the client can't get the resource, this call returns {@link + * Result#RESULT_UNAVAILABLE}. + * * <p> * This locks the frontend to a frequency by providing signal * delivery information. If previous tuning isn't completed, this stop the previous tuning, and @@ -472,7 +477,8 @@ public class Tuner implements AutoCloseable { @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) @Result public int tune(@NonNull FrontendSettings settings) { - TunerUtils.checkTunerPermission(mContext); + mFrontendType = settings.getType(); + checkResource(TunerResourceManager.TUNER_RESOURCE_TYPE_FRONTEND); mFrontendInfo = null; return nativeTune(settings.getType(), settings); } @@ -507,12 +513,13 @@ public class Tuner implements AutoCloseable { @Result public int scan(@NonNull FrontendSettings settings, @ScanType int scanType, @NonNull @CallbackExecutor Executor executor, @NonNull ScanCallback scanCallback) { - TunerUtils.checkTunerPermission(mContext); if (mScanCallback != null || mScanCallbackExecutor != null) { throw new IllegalStateException( "Scan already in progress. stopScan must be called before a new scan can be " + "started."); } + mFrontendType = settings.getType(); + checkResource(TunerResourceManager.TUNER_RESOURCE_TYPE_FRONTEND); mScanCallback = scanCallback; mScanCallbackExecutor = executor; mFrontendInfo = null; @@ -540,6 +547,16 @@ public class Tuner implements AutoCloseable { return retVal; } + private boolean requestFrontend() { + int[] feId = new int[1]; + TunerFrontendRequest request = new TunerFrontendRequest(mClientId, mFrontendType); + boolean granted = mTunerResourceManager.requestFrontend(request, feId); + if (granted) { + mFrontendHandle = feId[0]; + } + return granted; + } + /** * Sets Low-Noise Block downconverter (LNB) for satellite frontend. * @@ -673,22 +690,6 @@ public class Tuner implements AutoCloseable { return nativeGetDemuxCapabilities(); } - private List<Integer> getFrontendIds() { - mFrontendIds = nativeGetFrontendIds(); - return mFrontendIds; - } - - private Frontend openFrontendById(int id) { - if (mFrontendIds == null) { - mFrontendIds = getFrontendIds(); - } - if (!mFrontendIds.contains(id)) { - return null; - } - mFrontend = nativeOpenFrontendById(id); - return mFrontend; - } - private void onFrontendEvent(int eventType) { if (mOnTunerEventExecutor != null && mOnTuneEventListener != null) { mOnTunerEventExecutor.execute(() -> mOnTuneEventListener.onTuneEvent(eventType)); @@ -825,11 +826,9 @@ public class Tuner implements AutoCloseable { public Lnb openLnb(@CallbackExecutor @NonNull Executor executor, @NonNull LnbCallback cb) { Objects.requireNonNull(executor, "executor must not be null"); Objects.requireNonNull(cb, "LnbCallback must not be null"); - TunerUtils.checkTunerPermission(mContext); - if (mLnbId == null && !requestLnb()) { - return null; - } - return nativeOpenLnbById(mLnbId); + checkResource(TunerResourceManager.TUNER_RESOURCE_TYPE_LNB); + // TODO: update JNI code for LNB handle, + return nativeOpenLnbByHandle(mLnbHandle); } /** @@ -857,7 +856,7 @@ public class Tuner implements AutoCloseable { TunerLnbRequest request = new TunerLnbRequest(mClientId); boolean granted = mTunerResourceManager.requestLnb(request, lnbId); if (granted) { - mLnbId = lnbId[0]; + mLnbHandle = lnbId[0]; } return granted; } @@ -872,22 +871,6 @@ public class Tuner implements AutoCloseable { return nativeOpenTimeFilter(); } - private List<Integer> getLnbIds() { - mLnbIds = nativeGetLnbIds(); - return mLnbIds; - } - - private Lnb openLnbById(int id) { - if (mLnbIds == null) { - mLnbIds = getLnbIds(); - } - if (!mLnbIds.contains(id)) { - return null; - } - mLnb = nativeOpenLnbById(id); - return mLnb; - } - private void onLnbEvent(int eventType) { if (mHandler != null) { mHandler.sendMessage(mHandler.obtainMessage(MSG_ON_LNB_EVENT, eventType, 0)); @@ -951,4 +934,23 @@ public class Tuner implements AutoCloseable { DvrPlayback dvr = nativeOpenDvrPlayback(bufferSize); return dvr; } + + private boolean checkResource(int resourceType) { + // TODO: demux and descrambler + switch (resourceType) { + case TunerResourceManager.TUNER_RESOURCE_TYPE_FRONTEND: { + if (mFrontendHandle == null && !requestFrontend()) { + return false; + } + break; + } + case TunerResourceManager.TUNER_RESOURCE_TYPE_LNB: { + if (mLnbHandle == null && !requestLnb()) { + return false; + } + break; + } + } + return true; + } } diff --git a/media/java/android/media/tv/tunerresourcemanager/TunerResourceManager.java b/media/java/android/media/tv/tunerresourcemanager/TunerResourceManager.java index 9dddcd4eaa3b..63a71e272e53 100644 --- a/media/java/android/media/tv/tunerresourcemanager/TunerResourceManager.java +++ b/media/java/android/media/tv/tunerresourcemanager/TunerResourceManager.java @@ -17,6 +17,7 @@ package android.media.tv.tunerresourcemanager; import android.annotation.CallbackExecutor; +import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresFeature; @@ -27,6 +28,8 @@ import android.os.Binder; import android.os.RemoteException; import android.util.Log; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.concurrent.Executor; /** @@ -61,6 +64,24 @@ public class TunerResourceManager { private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); public static final int INVALID_RESOURCE_HANDLE = -1; + /** + * Tuner resource type to help generate resource handle + */ + @IntDef({ + TUNER_RESOURCE_TYPE_FRONTEND, + TUNER_RESOURCE_TYPE_DEMUX, + TUNER_RESOURCE_TYPE_DESCRAMBLER, + TUNER_RESOURCE_TYPE_LNB, + TUNER_RESOURCE_TYPE_CAS_SESSION, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface TunerResourceType {} + + public static final int TUNER_RESOURCE_TYPE_FRONTEND = 0; + public static final int TUNER_RESOURCE_TYPE_DEMUX = 1; + public static final int TUNER_RESOURCE_TYPE_DESCRAMBLER = 2; + public static final int TUNER_RESOURCE_TYPE_LNB = 3; + public static final int TUNER_RESOURCE_TYPE_CAS_SESSION = 4; private final ITunerResourceManager mService; private final int mUserId; diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp index a37c9e52f5dd..bbeb45179c78 100644 --- a/media/jni/android_media_tv_Tuner.cpp +++ b/media/jni/android_media_tv_Tuner.cpp @@ -1410,6 +1410,10 @@ static sp<IDescrambler> getDescrambler(JNIEnv *env, jobject descrambler) { return (IDescrambler *)env->GetLongField(descrambler, gFields.descramblerContext); } +static uint32_t getResourceIdFromHandle(jint handle) { + return (handle & 0x00ff0000) >> 16; +} + static DemuxPid getDemuxPid(int pidType, int pid) { DemuxPid demuxPid; if ((int)pidType == 1) { @@ -1968,8 +1972,10 @@ static jobject android_media_tv_Tuner_get_frontend_ids(JNIEnv *env, jobject thiz return tuner->getFrontendIds(); } -static jobject android_media_tv_Tuner_open_frontend_by_id(JNIEnv *env, jobject thiz, jint id) { +static jobject android_media_tv_Tuner_open_frontend_by_handle( + JNIEnv *env, jobject thiz, jint handle) { sp<JTuner> tuner = getTuner(env, thiz); + uint32_t id = getResourceIdFromHandle(handle); return tuner->openFrontendById(id); } @@ -2045,8 +2051,9 @@ static jobject android_media_tv_Tuner_get_lnb_ids(JNIEnv *env, jobject thiz) { return tuner->getLnbIds(); } -static jobject android_media_tv_Tuner_open_lnb_by_id(JNIEnv *env, jobject thiz, jint id) { +static jobject android_media_tv_Tuner_open_lnb_by_handle(JNIEnv *env, jobject thiz, jint handle) { sp<JTuner> tuner = getTuner(env, thiz); + uint32_t id = getResourceIdFromHandle(handle); return tuner->openLnbById(id); } @@ -2924,8 +2931,8 @@ static const JNINativeMethod gTunerMethods[] = { { "nativeSetup", "()V", (void *)android_media_tv_Tuner_native_setup }, { "nativeGetFrontendIds", "()Ljava/util/List;", (void *)android_media_tv_Tuner_get_frontend_ids }, - { "nativeOpenFrontendById", "(I)Landroid/media/tv/tuner/Tuner$Frontend;", - (void *)android_media_tv_Tuner_open_frontend_by_id }, + { "nativeOpenFrontendByHandle", "(I)Landroid/media/tv/tuner/Tuner$Frontend;", + (void *)android_media_tv_Tuner_open_frontend_by_handle }, { "nativeTune", "(ILandroid/media/tv/tuner/frontend/FrontendSettings;)I", (void *)android_media_tv_Tuner_tune }, { "nativeStopTune", "()I", (void *)android_media_tv_Tuner_stop_tune }, @@ -2950,8 +2957,8 @@ static const JNINativeMethod gTunerMethods[] = { (void *)android_media_tv_Tuner_open_time_filter }, { "nativeGetLnbIds", "()Ljava/util/List;", (void *)android_media_tv_Tuner_get_lnb_ids }, - { "nativeOpenLnbById", "(I)Landroid/media/tv/tuner/Lnb;", - (void *)android_media_tv_Tuner_open_lnb_by_id }, + { "nativeOpenLnbByHandle", "(I)Landroid/media/tv/tuner/Lnb;", + (void *)android_media_tv_Tuner_open_lnb_by_handle }, { "nativeOpenLnbByName", "(Ljava/lang/String;)Landroid/media/tv/tuner/Lnb;", (void *)android_media_tv_Tuner_open_lnb_by_name }, { "nativeOpenDescrambler", "()Landroid/media/tv/tuner/Descrambler;", diff --git a/media/jni/audioeffect/android_media_Visualizer.cpp b/media/jni/audioeffect/android_media_Visualizer.cpp index 1362433bb26e..f9a77f474c50 100644 --- a/media/jni/audioeffect/android_media_Visualizer.cpp +++ b/media/jni/audioeffect/android_media_Visualizer.cpp @@ -196,7 +196,6 @@ static void captureCallback(void* user, callbackInfo->visualizer_ref, NATIVE_EVENT_PCM_CAPTURE, samplingrate, - 0, jArray); } } @@ -217,7 +216,6 @@ static void captureCallback(void* user, callbackInfo->visualizer_ref, NATIVE_EVENT_FFT_CAPTURE, samplingrate, - 0, jArray); } } @@ -286,7 +284,7 @@ android_media_visualizer_native_init(JNIEnv *env) // Get the postEvent method fields.midPostNativeEvent = env->GetStaticMethodID( fields.clazzEffect, - "postEventFromNative", "(Ljava/lang/Object;IIILjava/lang/Object;)V"); + "postEventFromNative", "(Ljava/lang/Object;II[B)V"); if (fields.midPostNativeEvent == NULL) { ALOGE("Can't find Visualizer.%s", "postEventFromNative"); return; @@ -343,7 +341,7 @@ static void android_media_visualizer_effect_callback(int32_t event, fields.midPostNativeEvent, callbackInfo->visualizer_ref, NATIVE_EVENT_SERVER_DIED, - 0, 0, NULL); + 0, NULL); } } diff --git a/packages/SettingsLib/res/drawable/ic_media_group_device.xml b/packages/SettingsLib/res/drawable/ic_media_group_device.xml new file mode 100644 index 000000000000..ba5e65119ead --- /dev/null +++ b/packages/SettingsLib/res/drawable/ic_media_group_device.xml @@ -0,0 +1,32 @@ +<!-- + Copyright (C) 2020 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License + --> + +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24" + android:tint="?android:attr/colorControlNormal"> + <path + android:pathData="M18.2,1L9.8,1C8.81,1 8,1.81 8,2.8v14.4c0,0.99 0.81,1.79 1.8,1.79l8.4,0.01c0.99,0 1.8,-0.81 1.8,-1.8L20,2.8c0,-0.99 -0.81,-1.8 -1.8,-1.8zM14,3c1.1,0 2,0.89 2,2s-0.9,2 -2,2 -2,-0.89 -2,-2 0.9,-2 2,-2zM14,16.5c-2.21,0 -4,-1.79 -4,-4s1.79,-4 4,-4 4,1.79 4,4 -1.79,4 -4,4z" + android:fillColor="#000000"/> + <path + android:pathData="M14,12.5m-2.5,0a2.5,2.5 0,1 1,5 0a2.5,2.5 0,1 1,-5 0" + android:fillColor="#000000"/> + <path + android:pathData="M6,5H4v16c0,1.1 0.89,2 2,2h10v-2H6V5z" + android:fillColor="#000000"/> +</vector>
\ No newline at end of file diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml index 00f6bcb6c548..a7970668124b 100644 --- a/packages/SettingsLib/res/values/strings.xml +++ b/packages/SettingsLib/res/values/strings.xml @@ -1039,7 +1039,7 @@ <!-- Title for the accessibility preference to configure display color space correction. [CHAR LIMIT=NONE] --> <string name="accessibility_display_daltonizer_preference_title">Color correction</string> <!-- Subtitle for the accessibility preference to configure display color space correction. [CHAR LIMIT=NONE] --> - <string name="accessibility_display_daltonizer_preference_subtitle">Color correction helps the device display more accurate colors. Color correction may be helpful for people with colorblindness.</string> + <string name="accessibility_display_daltonizer_preference_subtitle"><![CDATA[Color correction allows you to adjust how colors are displayed on your device]]></string> <!-- Summary shown for color space correction preference when its value is overridden by another preference [CHAR LIMIT=35] --> <string name="daltonizer_type_overridden">Overridden by <xliff:g id="title" example="Simulate color space">%1$s</xliff:g></string> diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java index b725ba5b8748..85fa988a866e 100644 --- a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java +++ b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java @@ -15,11 +15,17 @@ */ package com.android.settingslib.media; +import static android.media.MediaRoute2Info.TYPE_GROUP; +import static android.media.MediaRoute2Info.TYPE_REMOTE_SPEAKER; +import static android.media.MediaRoute2Info.TYPE_REMOTE_TV; + import android.content.Context; import android.graphics.drawable.Drawable; import android.media.MediaRoute2Info; import android.media.MediaRouter2Manager; +import androidx.annotation.VisibleForTesting; + import com.android.settingslib.R; import com.android.settingslib.bluetooth.BluetoothUtils; @@ -51,7 +57,23 @@ public class InfoMediaDevice extends MediaDevice { public Drawable getIcon() { //TODO(b/120669861): Return remote device icon uri once api is ready. return BluetoothUtils.buildBtRainbowDrawable(mContext, - mContext.getDrawable(R.drawable.ic_media_device), getId().hashCode()); + mContext.getDrawable(getDrawableResId()), getId().hashCode()); + } + + @VisibleForTesting + int getDrawableResId() { + int resId; + switch (mRouteInfo.getType()) { + case TYPE_GROUP: + resId = R.drawable.ic_media_group_device; + break; + case TYPE_REMOTE_TV: + case TYPE_REMOTE_SPEAKER: + default: + resId = R.drawable.ic_media_device; + break; + } + return resId; } @Override diff --git a/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java index 166fbaa2a337..af88723c6249 100644 --- a/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java +++ b/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java @@ -15,11 +15,17 @@ */ package com.android.settingslib.media; +import static android.media.MediaRoute2Info.TYPE_BUILTIN_SPEAKER; +import static android.media.MediaRoute2Info.TYPE_WIRED_HEADPHONES; +import static android.media.MediaRoute2Info.TYPE_WIRED_HEADSET; + import android.content.Context; import android.graphics.drawable.Drawable; import android.media.MediaRoute2Info; import android.media.MediaRouter2Manager; +import androidx.annotation.VisibleForTesting; + import com.android.settingslib.R; import com.android.settingslib.bluetooth.BluetoothUtils; @@ -43,7 +49,18 @@ public class PhoneMediaDevice extends MediaDevice { @Override public String getName() { - return mContext.getString(R.string.media_transfer_this_device_name); + CharSequence name; + switch (mRouteInfo.getType()) { + case TYPE_WIRED_HEADSET: + case TYPE_WIRED_HEADPHONES: + name = mRouteInfo.getName(); + break; + case TYPE_BUILTIN_SPEAKER: + default: + name = mContext.getString(R.string.media_transfer_this_device_name); + break; + } + return name.toString(); } @Override @@ -54,7 +71,23 @@ public class PhoneMediaDevice extends MediaDevice { @Override public Drawable getIcon() { return BluetoothUtils.buildBtRainbowDrawable(mContext, - mContext.getDrawable(R.drawable.ic_smartphone), getId().hashCode()); + mContext.getDrawable(getDrawableResId()), getId().hashCode()); + } + + @VisibleForTesting + int getDrawableResId() { + int resId; + switch (mRouteInfo.getType()) { + case TYPE_WIRED_HEADSET: + case TYPE_WIRED_HEADPHONES: + resId = com.android.internal.R.drawable.ic_bt_headphones_a2dp; + break; + case TYPE_BUILTIN_SPEAKER: + default: + resId = R.drawable.ic_smartphone; + break; + } + return resId; } @Override diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaDeviceTest.java index 77a67c286989..685c834ff328 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaDeviceTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaDeviceTest.java @@ -16,6 +16,10 @@ package com.android.settingslib.media; +import static android.media.MediaRoute2Info.TYPE_GROUP; +import static android.media.MediaRoute2Info.TYPE_REMOTE_SPEAKER; +import static android.media.MediaRoute2Info.TYPE_REMOTE_TV; + import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.when; @@ -86,4 +90,19 @@ public class InfoMediaDeviceTest { assertThat(mInfoMediaDevice.getId()).isEqualTo(TEST_ID); } + + @Test + public void getDrawableResId_returnCorrectResId() { + when(mRouteInfo.getType()).thenReturn(TYPE_REMOTE_TV); + + assertThat(mInfoMediaDevice.getDrawableResId()).isEqualTo(R.drawable.ic_media_device); + + when(mRouteInfo.getType()).thenReturn(TYPE_REMOTE_SPEAKER); + + assertThat(mInfoMediaDevice.getDrawableResId()).isEqualTo(R.drawable.ic_media_device); + + when(mRouteInfo.getType()).thenReturn(TYPE_GROUP); + + assertThat(mInfoMediaDevice.getDrawableResId()).isEqualTo(R.drawable.ic_media_group_device); + } } diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/PhoneMediaDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/PhoneMediaDeviceTest.java index db984fb8dc26..4c5cd9682b0f 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/PhoneMediaDeviceTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/PhoneMediaDeviceTest.java @@ -16,15 +16,23 @@ package com.android.settingslib.media; +import static android.media.MediaRoute2Info.TYPE_BUILTIN_SPEAKER; +import static android.media.MediaRoute2Info.TYPE_WIRED_HEADPHONES; +import static android.media.MediaRoute2Info.TYPE_WIRED_HEADSET; + import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.when; + import android.content.Context; +import android.media.MediaRoute2Info; import com.android.settingslib.R; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; @@ -32,6 +40,9 @@ import org.robolectric.RuntimeEnvironment; @RunWith(RobolectricTestRunner.class) public class PhoneMediaDeviceTest { + @Mock + private MediaRoute2Info mInfo; + private Context mContext; private PhoneMediaDevice mPhoneMediaDevice; @@ -41,7 +52,7 @@ public class PhoneMediaDeviceTest { mContext = RuntimeEnvironment.application; mPhoneMediaDevice = - new PhoneMediaDevice(mContext, null, null, null); + new PhoneMediaDevice(mContext, null, mInfo, null); } @Test @@ -58,4 +69,42 @@ public class PhoneMediaDeviceTest { assertThat(mPhoneMediaDevice.getSummary()).isEmpty(); } + + @Test + public void getDrawableResId_returnCorrectResId() { + when(mInfo.getType()).thenReturn(TYPE_WIRED_HEADPHONES); + + assertThat(mPhoneMediaDevice.getDrawableResId()) + .isEqualTo(com.android.internal.R.drawable.ic_bt_headphones_a2dp); + + when(mInfo.getType()).thenReturn(TYPE_WIRED_HEADSET); + + assertThat(mPhoneMediaDevice.getDrawableResId()) + .isEqualTo(com.android.internal.R.drawable.ic_bt_headphones_a2dp); + + when(mInfo.getType()).thenReturn(TYPE_BUILTIN_SPEAKER); + + assertThat(mPhoneMediaDevice.getDrawableResId()).isEqualTo(R.drawable.ic_smartphone); + } + + @Test + public void getName_returnCorrectName() { + final String deviceName = "test_name"; + + when(mInfo.getType()).thenReturn(TYPE_WIRED_HEADPHONES); + when(mInfo.getName()).thenReturn(deviceName); + + assertThat(mPhoneMediaDevice.getName()) + .isEqualTo(deviceName); + + when(mInfo.getType()).thenReturn(TYPE_WIRED_HEADSET); + + assertThat(mPhoneMediaDevice.getName()) + .isEqualTo(deviceName); + + when(mInfo.getType()).thenReturn(TYPE_BUILTIN_SPEAKER); + + assertThat(mPhoneMediaDevice.getName()) + .isEqualTo(mContext.getString(R.string.media_transfer_this_device_name)); + } } diff --git a/packages/SystemUI/res/layout/global_screenshot.xml b/packages/SystemUI/res/layout/global_screenshot.xml index a76f96115fa9..d506e7e8e700 100644 --- a/packages/SystemUI/res/layout/global_screenshot.xml +++ b/packages/SystemUI/res/layout/global_screenshot.xml @@ -58,13 +58,15 @@ android:elevation="@dimen/screenshot_preview_elevation" android:visibility="gone" android:background="@drawable/screenshot_rounded_corners" - android:adjustViewBounds="true"/> + android:adjustViewBounds="true" + android:contentDescription="@string/screenshot_preview_description"/> <FrameLayout android:id="@+id/global_screenshot_dismiss_button" android:layout_width="@dimen/screenshot_dismiss_button_tappable_size" android:layout_height="@dimen/screenshot_dismiss_button_tappable_size" android:elevation="7dp" - android:visibility="gone"> + android:visibility="gone" + android:contentDescription="@string/screenshot_dismiss_ui_description"> <ImageView android:layout_width="match_parent" android:layout_height="match_parent" diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 35430733a118..93bafdbee91d 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -233,6 +233,10 @@ <!-- Notification text displayed when we fail to take a screenshot. [CHAR LIMIT=100] --> <string name="screenshot_failed_to_capture_text">Taking screenshots isn\'t allowed by the app or your organization</string> + <!-- Content description indicating that tapping a button will dismiss the screenshots UI [CHAR LIMIT=NONE] --> + <string name="screenshot_dismiss_ui_description">Dismiss screenshot</string> + <!-- Content description indicating that tapping will open an app to view/edit the screenshot. [CHAR LIMIT=NONE] --> + <string name="screenshot_preview_description">Open screenshot</string> <!-- Notification title displayed for screen recording [CHAR LIMIT=50]--> <string name="screenrecord_name">Screen Recorder</string> diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java index 431c4519bd81..90df124c85ca 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -2740,6 +2740,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab mBroadcastDispatcher.unregisterReceiver(mBroadcastReceiver); mBroadcastDispatcher.unregisterReceiver(mBroadcastAllReceiver); + + mHandler.removeCallbacksAndMessages(null); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java index a161d037fb50..e208ee2b4ab7 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java +++ b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java @@ -33,7 +33,6 @@ import android.media.MediaMetadata; import android.media.session.MediaController; import android.media.session.MediaSession; import android.media.session.PlaybackState; -import android.os.Handler; import android.util.Log; import android.view.KeyEvent; import android.view.LayoutInflater; @@ -64,6 +63,7 @@ import java.util.concurrent.Executor; public class MediaControlPanel implements NotificationMediaManager.MediaListener { private static final String TAG = "MediaControlPanel"; private final NotificationMediaManager mMediaManager; + private final Executor mForegroundExecutor; private final Executor mBackgroundExecutor; private Context mContext; @@ -102,15 +102,18 @@ public class MediaControlPanel implements NotificationMediaManager.MediaListener * @param manager * @param layoutId layout resource to use for this control panel * @param actionIds resource IDs for action buttons in the layout + * @param foregroundExecutor foreground executor * @param backgroundExecutor background executor, used for processing artwork */ public MediaControlPanel(Context context, ViewGroup parent, NotificationMediaManager manager, - @LayoutRes int layoutId, int[] actionIds, Executor backgroundExecutor) { + @LayoutRes int layoutId, int[] actionIds, Executor foregroundExecutor, + Executor backgroundExecutor) { mContext = context; LayoutInflater inflater = LayoutInflater.from(mContext); mMediaNotifView = (LinearLayout) inflater.inflate(layoutId, parent, false); mMediaManager = manager; mActionIds = actionIds; + mForegroundExecutor = foregroundExecutor; mBackgroundExecutor = backgroundExecutor; } @@ -176,15 +179,17 @@ public class MediaControlPanel implements NotificationMediaManager.MediaListener mMediaNotifView.setBackgroundTintList(ColorStateList.valueOf(mBackgroundColor)); // Click action - mMediaNotifView.setOnClickListener(v -> { - try { - contentIntent.send(); - // Also close shade - mContext.sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)); - } catch (PendingIntent.CanceledException e) { - Log.e(TAG, "Pending intent was canceled", e); - } - }); + if (contentIntent != null) { + mMediaNotifView.setOnClickListener(v -> { + try { + contentIntent.send(); + // Also close shade + mContext.sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)); + } catch (PendingIntent.CanceledException e) { + Log.e(TAG, "Pending intent was canceled", e); + } + }); + } // App icon ImageView appIcon = mMediaNotifView.findViewById(R.id.icon); @@ -316,7 +321,7 @@ public class MediaControlPanel implements NotificationMediaManager.MediaListener // Now that it's resized, update the UI final RoundedBitmapDrawable result = roundedDrawable; - albumView.getHandler().post(() -> { + mForegroundExecutor.execute(() -> { if (result != null) { albumView.setImageDrawable(result); albumView.setVisibility(View.VISIBLE); @@ -335,8 +340,7 @@ public class MediaControlPanel implements NotificationMediaManager.MediaListener if (mSeamless == null) { return; } - Handler handler = mSeamless.getHandler(); - handler.post(() -> { + mForegroundExecutor.execute(() -> { updateChipInternal(device); }); } @@ -401,12 +405,15 @@ public class MediaControlPanel implements NotificationMediaManager.MediaListener new KeyEvent(KeyEvent.ACTION_DOWN, keyCode)); mContext.sendBroadcast(intent); } else { - Log.d(TAG, "No receiver to restart"); // If we don't have a receiver, try relaunching the activity instead - try { - mController.getSessionActivity().send(); - } catch (PendingIntent.CanceledException e) { - Log.e(TAG, "Pending intent was canceled", e); + if (mController.getSessionActivity() != null) { + try { + mController.getSessionActivity().send(); + } catch (PendingIntent.CanceledException e) { + Log.e(TAG, "Pending intent was canceled", e); + } + } else { + Log.e(TAG, "No receiver or activity to restart"); } } }); diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSMediaPlayer.java b/packages/SystemUI/src/com/android/systemui/qs/QSMediaPlayer.java index 837256bf4052..d5e5b10d603c 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSMediaPlayer.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSMediaPlayer.java @@ -55,11 +55,13 @@ public class QSMediaPlayer extends MediaControlPanel { * @param context * @param parent * @param manager + * @param foregroundExecutor * @param backgroundExecutor */ public QSMediaPlayer(Context context, ViewGroup parent, NotificationMediaManager manager, - Executor backgroundExecutor) { - super(context, parent, manager, R.layout.qs_media_panel, QS_ACTION_IDS, backgroundExecutor); + Executor foregroundExecutor, Executor backgroundExecutor) { + super(context, parent, manager, R.layout.qs_media_panel, QS_ACTION_IDS, foregroundExecutor, + backgroundExecutor); } /** diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java index bf72b33ada42..5ccf8c7e9212 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java @@ -53,6 +53,7 @@ import com.android.systemui.Dumpable; import com.android.systemui.R; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.dagger.qualifiers.Background; +import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dump.DumpManager; import com.android.systemui.plugins.qs.DetailAdapter; import com.android.systemui.plugins.qs.QSTile; @@ -101,6 +102,7 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne private final ArrayList<QSMediaPlayer> mMediaPlayers = new ArrayList<>(); private final NotificationMediaManager mNotificationMediaManager; private final LocalBluetoothManager mLocalBluetoothManager; + private final Executor mForegroundExecutor; private final Executor mBackgroundExecutor; private LocalMediaManager mLocalMediaManager; private MediaDevice mDevice; @@ -160,6 +162,7 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne BroadcastDispatcher broadcastDispatcher, QSLogger qsLogger, NotificationMediaManager notificationMediaManager, + @Main Executor foregroundExecutor, @Background Executor backgroundExecutor, @Nullable LocalBluetoothManager localBluetoothManager ) { @@ -168,6 +171,7 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne mQSLogger = qsLogger; mDumpManager = dumpManager; mNotificationMediaManager = notificationMediaManager; + mForegroundExecutor = foregroundExecutor; mBackgroundExecutor = backgroundExecutor; mLocalBluetoothManager = localBluetoothManager; @@ -270,7 +274,7 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne if (player == null) { Log.d(TAG, "creating new player"); player = new QSMediaPlayer(mContext, this, mNotificationMediaManager, - mBackgroundExecutor); + mForegroundExecutor, mBackgroundExecutor); if (player.isPlaying()) { mMediaCarousel.addView(player.getView(), 0, lp); // add in front diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSMediaPlayer.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSMediaPlayer.java index 4512afb3c178..0c5019491a59 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSMediaPlayer.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSMediaPlayer.java @@ -48,12 +48,13 @@ public class QuickQSMediaPlayer extends MediaControlPanel { * @param context * @param parent * @param manager + * @param foregroundExecutor * @param backgroundExecutor */ public QuickQSMediaPlayer(Context context, ViewGroup parent, NotificationMediaManager manager, - Executor backgroundExecutor) { + Executor foregroundExecutor, Executor backgroundExecutor) { super(context, parent, manager, R.layout.qqs_media_panel, QQS_ACTION_IDS, - backgroundExecutor); + foregroundExecutor, backgroundExecutor); } /** diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java index 6654b7ab0749..be01d75552de 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java @@ -32,6 +32,7 @@ import com.android.systemui.Dependency; import com.android.systemui.R; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.dagger.qualifiers.Background; +import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dump.DumpManager; import com.android.systemui.plugins.qs.QSTile; import com.android.systemui.plugins.qs.QSTile.SignalState; @@ -79,11 +80,12 @@ public class QuickQSPanel extends QSPanel { BroadcastDispatcher broadcastDispatcher, QSLogger qsLogger, NotificationMediaManager notificationMediaManager, + @Main Executor foregroundExecutor, @Background Executor backgroundExecutor, @Nullable LocalBluetoothManager localBluetoothManager ) { super(context, attrs, dumpManager, broadcastDispatcher, qsLogger, notificationMediaManager, - backgroundExecutor, localBluetoothManager); + foregroundExecutor, backgroundExecutor, localBluetoothManager); if (mFooter != null) { removeView(mFooter.getView()); } @@ -103,7 +105,7 @@ public class QuickQSPanel extends QSPanel { int marginSize = (int) mContext.getResources().getDimension(R.dimen.qqs_media_spacing); mMediaPlayer = new QuickQSMediaPlayer(mContext, mHorizontalLinearLayout, - notificationMediaManager, backgroundExecutor); + notificationMediaManager, foregroundExecutor, backgroundExecutor); LayoutParams lp2 = new LayoutParams(0, LayoutParams.MATCH_PARENT, 1); lp2.setMarginEnd(marginSize); lp2.setMarginStart(0); diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java index d422dd7f4175..11b625f41737 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java @@ -436,6 +436,10 @@ public class QuickStatusBarHeader extends RelativeLayout implements @Override public WindowInsets onApplyWindowInsets(WindowInsets insets) { + // Handle padding of QuickStatusBarHeader + setPadding(mRoundedCornerPadding, getPaddingTop(), mRoundedCornerPadding, + getPaddingBottom()); + // Handle padding of SystemIconsView DisplayCutout cutout = insets.getDisplayCutout(); Pair<Integer, Integer> cornerCutoutPadding = StatusBarWindowView.cornerCutoutMargins( @@ -450,8 +454,11 @@ public class QuickStatusBarHeader extends RelativeLayout implements int statusBarPaddingRight = isLayoutRtl() ? getResources().getDimensionPixelSize(R.dimen.status_bar_padding_start) : getResources().getDimensionPixelSize(R.dimen.status_bar_padding_end); - mSystemIconsView.setPadding(padding.first + statusBarPaddingLeft, waterfallTopInset, - padding.second + statusBarPaddingRight, 0); + mSystemIconsView.setPadding( + Math.max(padding.first + statusBarPaddingLeft - mRoundedCornerPadding, 0), + waterfallTopInset, + Math.max(padding.second + statusBarPaddingRight - mRoundedCornerPadding, 0), + 0); return super.onApplyWindowInsets(insets); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.java new file mode 100644 index 000000000000..573c129f199a --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.java @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.notification.collection.coordinator; + +import static com.android.systemui.statusbar.NotificationRemoteInputManager.FORCE_REMOTE_INPUT_HISTORY; + +import android.annotation.Nullable; + +import com.android.systemui.statusbar.NotificationRemoteInputManager; +import com.android.systemui.statusbar.notification.collection.ListEntry; +import com.android.systemui.statusbar.notification.collection.NotifPipeline; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; +import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter; +import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSection; +import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener; +import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender; +import com.android.systemui.statusbar.policy.HeadsUpManager; +import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener; + +import java.util.Objects; + +import javax.inject.Inject; +import javax.inject.Singleton; + +/** + * Coordinates heads up notification (HUN) interactions with the notification pipeline based on + * the HUN state reported by the {@link HeadsUpManager}. In this class we only consider one + * notification, in particular the {@link HeadsUpManager#getTopEntry()}, to be HeadsUpping at a + * time even though other notifications may be queued to heads up next. + * + * The current HUN, but not HUNs that are queued to heads up, will be: + * - Lifetime extended until it's no longer heads upping. + * - Promoted out of its group if it's a child of a group. + * - In the HeadsUpCoordinatorSection. Ordering is configured in {@link NotifCoordinators}. + * - Removed from HeadsUpManager if it's removed from the NotificationCollection. + * + * Note: The inflation callback in {@link PreparationCoordinator} handles showing HUNs. + */ +@Singleton +public class HeadsUpCoordinator implements Coordinator { + private static final String TAG = "HeadsUpCoordinator"; + + private final HeadsUpManager mHeadsUpManager; + private final NotificationRemoteInputManager mRemoteInputManager; + + // tracks the current HeadUpNotification reported by HeadsUpManager + private @Nullable NotificationEntry mCurrentHun; + + private NotifLifetimeExtender.OnEndLifetimeExtensionCallback mEndLifetimeExtension; + private NotificationEntry mNotifExtendingLifetime; // notif we've extended the lifetime for + + @Inject + public HeadsUpCoordinator( + HeadsUpManager headsUpManager, + NotificationRemoteInputManager remoteInputManager) { + mHeadsUpManager = headsUpManager; + mRemoteInputManager = remoteInputManager; + } + + @Override + public void attach(NotifPipeline pipeline) { + mHeadsUpManager.addListener(mOnHeadsUpChangedListener); + pipeline.addCollectionListener(mNotifCollectionListener); + pipeline.addPromoter(mNotifPromoter); + pipeline.addNotificationLifetimeExtender(mLifetimeExtender); + } + + @Override + public NotifSection getSection() { + return mNotifSection; + } + + private final NotifCollectionListener mNotifCollectionListener = new NotifCollectionListener() { + /** + * Stop alerting HUNs that are removed from the notification collection + */ + @Override + public void onEntryRemoved(NotificationEntry entry, int reason) { + final String entryKey = entry.getKey(); + if (mHeadsUpManager.isAlerting(entryKey)) { + boolean removeImmediatelyForRemoteInput = + mRemoteInputManager.getController().isSpinning(entryKey) + && !FORCE_REMOTE_INPUT_HISTORY; + mHeadsUpManager.removeNotification(entry.getKey(), removeImmediatelyForRemoteInput); + } + } + }; + + private final NotifLifetimeExtender mLifetimeExtender = new NotifLifetimeExtender() { + @Override + public String getName() { + return TAG; + } + + @Override + public void setCallback(OnEndLifetimeExtensionCallback callback) { + mEndLifetimeExtension = callback; + } + + @Override + public boolean shouldExtendLifetime(NotificationEntry entry, int reason) { + boolean isShowingHun = isCurrentlyShowingHun(entry); + if (isShowingHun) { + mNotifExtendingLifetime = entry; + } + return isShowingHun; + } + + @Override + public void cancelLifetimeExtension(NotificationEntry entry) { + if (Objects.equals(mNotifExtendingLifetime, entry)) { + mNotifExtendingLifetime = null; + } + } + }; + + private final NotifPromoter mNotifPromoter = new NotifPromoter(TAG) { + @Override + public boolean shouldPromoteToTopLevel(NotificationEntry entry) { + return isCurrentlyShowingHun(entry); + } + }; + + private final NotifSection mNotifSection = new NotifSection(TAG) { + @Override + public boolean isInSection(ListEntry entry) { + return isCurrentlyShowingHun(entry); + } + }; + + private final OnHeadsUpChangedListener mOnHeadsUpChangedListener = + new OnHeadsUpChangedListener() { + @Override + public void onHeadsUpStateChanged(NotificationEntry entry, boolean isHeadsUp) { + NotificationEntry newHUN = mHeadsUpManager.getTopEntry(); + if (!Objects.equals(mCurrentHun, newHUN)) { + endNotifLifetimeExtension(); + mCurrentHun = newHUN; + mNotifPromoter.invalidateList(); + mNotifSection.invalidateList(); + } + } + }; + + private boolean isCurrentlyShowingHun(ListEntry entry) { + return mCurrentHun == entry.getRepresentativeEntry(); + } + + private void endNotifLifetimeExtension() { + if (mNotifExtendingLifetime != null) { + mEndLifetimeExtension.onEndLifetimeExtension( + mLifetimeExtender, + mNotifExtendingLifetime); + mNotifExtendingLifetime = null; + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java index 7a22d75505e5..98104f84f30e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.java @@ -49,6 +49,7 @@ public class NotifCoordinators implements Dumpable { public NotifCoordinators( DumpManager dumpManager, FeatureFlags featureFlags, + HeadsUpCoordinator headsUpCoordinator, KeyguardCoordinator keyguardCoordinator, RankingCoordinator rankingCoordinator, ForegroundCoordinator foregroundCoordinator, @@ -56,7 +57,6 @@ public class NotifCoordinators implements Dumpable { BubbleCoordinator bubbleCoordinator, PreparationCoordinator preparationCoordinator) { dumpManager.registerDumpable(TAG, this); - mCoordinators.add(new HideLocallyDismissedNotifsCoordinator()); mCoordinators.add(keyguardCoordinator); mCoordinators.add(rankingCoordinator); @@ -64,9 +64,10 @@ public class NotifCoordinators implements Dumpable { mCoordinators.add(deviceProvisionedCoordinator); mCoordinators.add(bubbleCoordinator); if (featureFlags.isNewNotifPipelineRenderingEnabled()) { + mCoordinators.add(headsUpCoordinator); mCoordinators.add(preparationCoordinator); } - // TODO: add new Coordinators here! (b/145134683, b/112656837) + // TODO: add new Coordinators here! (b/112656837) // TODO: add the sections in a particular ORDER (HeadsUp < People < Alerting) for (Coordinator c : mCoordinators) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java index 98a019e35d2c..742615c7fd0f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java @@ -33,7 +33,9 @@ import com.android.systemui.statusbar.notification.collection.inflation.NotifInf import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeFinalizeFilterListener; import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter; import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener; +import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider; import com.android.systemui.statusbar.notification.row.NotifInflationErrorManager; +import com.android.systemui.statusbar.policy.HeadsUpManager; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -61,6 +63,8 @@ public class PreparationCoordinator implements Coordinator { private final NotifViewBarn mViewBarn; private final Map<NotificationEntry, Integer> mInflationStates = new ArrayMap<>(); private final IStatusBarService mStatusBarService; + private final NotificationInterruptStateProvider mNotificationInterruptStateProvider; + private final HeadsUpManager mHeadsUpManager; @Inject public PreparationCoordinator( @@ -68,7 +72,10 @@ public class PreparationCoordinator implements Coordinator { NotifInflaterImpl notifInflater, NotifInflationErrorManager errorManager, NotifViewBarn viewBarn, - IStatusBarService service) { + IStatusBarService service, + NotificationInterruptStateProvider notificationInterruptStateProvider, + HeadsUpManager headsUpManager + ) { mLogger = logger; mNotifInflater = notifInflater; mNotifInflater.setInflationCallback(mInflationCallback); @@ -76,6 +83,8 @@ public class PreparationCoordinator implements Coordinator { mNotifErrorManager.addInflationErrorListener(mInflationErrorListener); mViewBarn = viewBarn; mStatusBarService = service; + mNotificationInterruptStateProvider = notificationInterruptStateProvider; + mHeadsUpManager = headsUpManager; } @Override @@ -149,6 +158,11 @@ public class PreparationCoordinator implements Coordinator { mLogger.logNotifInflated(entry.getKey()); mViewBarn.registerViewForEntry(entry, entry.getRow()); mInflationStates.put(entry, STATE_INFLATED); + + // TODO: should eventually be moved to HeadsUpCoordinator + if (mNotificationInterruptStateProvider.shouldHeadsUp(entry)) { + mHeadsUpManager.showNotification(entry); + } mNotifInflatingFilter.invalidateList(); } }; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java index ea1bdd6a0ef6..b9dd97482d88 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationView.java @@ -271,6 +271,10 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView } } + public boolean isActive() { + return mActivated; + } + private void startActivateAnimation(final boolean reverse) { if (!isAttachedToWindow()) { return; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewController.java index 2643ec975023..2f0e433b3927 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewController.java @@ -111,7 +111,7 @@ public class ActivatableNotificationViewController { if (mNeedsDimming && ev.getActionMasked() == MotionEvent.ACTION_DOWN && mView.disallowSingleClick(ev) && !mAccessibilityManager.isTouchExplorationEnabled()) { - if (!mView.isActivated()) { + if (!mView.isActive()) { return true; } else if (!mDoubleTapHelper.isWithinDoubleTapSlop(ev)) { mBlockNextTouch = true; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapper.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapper.kt index 1e2571b5c801..162786cc1fbd 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapper.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapper.kt @@ -40,6 +40,7 @@ class NotificationConversationTemplateViewWrapper constructor( private var conversationIcon: View? = null private var conversationBadge: View? = null private var expandButton: View? = null + private lateinit var expandButtonContainer: View private var messagingLinearLayout: MessagingLinearLayout? = null init { @@ -56,6 +57,8 @@ class NotificationConversationTemplateViewWrapper constructor( com.android.internal.R.id.conversation_icon_badge) expandButton = conversationLayout.requireViewById( com.android.internal.R.id.expand_button) + expandButtonContainer = conversationLayout.requireViewById( + com.android.internal.R.id.expand_button_container) } override fun onContentUpdated(row: ExpandableNotificationRow) { @@ -90,6 +93,14 @@ class NotificationConversationTemplateViewWrapper constructor( conversationLayout.updateExpandability(expandable, onClickListener) } + override fun disallowSingleClick(x: Float, y: Float): Boolean { + if (expandButtonContainer.visibility == View.VISIBLE + && isOnView(expandButtonContainer, x, y)) { + return true + } + return super.disallowSingleClick(x, y) + } + override fun getMinLayoutHeight(): Int { if (mActionsContainer != null && mActionsContainer.visibility != View.GONE) { return minHeightWithActions diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapper.java index d41f5af6c524..2d99ab1e999f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapper.java @@ -58,7 +58,6 @@ public class NotificationTemplateViewWrapper extends NotificationHeaderViewWrapp private TextView mText; protected View mActionsContainer; private ImageView mReplyAction; - private Rect mTmpRect = new Rect(); private int mContentHeight; private int mMinHeightHint; @@ -271,18 +270,6 @@ public class NotificationTemplateViewWrapper extends NotificationHeaderViewWrapp return super.disallowSingleClick(x, y); } - private boolean isOnView(View view, float x, float y) { - View searchView = (View) view.getParent(); - while (searchView != null && !(searchView instanceof ExpandableNotificationRow)) { - searchView.getHitRect(mTmpRect); - x -= mTmpRect.left; - y -= mTmpRect.top; - searchView = (View) searchView.getParent(); - } - view.getHitRect(mTmpRect); - return mTmpRect.contains((int) x,(int) y); - } - @Override public void onContentUpdated(ExpandableNotificationRow row) { // Reinspect the notification. Before the super call, because the super call also updates diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java index c834e4b376ed..46d7d9374290 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java @@ -24,6 +24,7 @@ import android.graphics.Color; import android.graphics.ColorMatrix; import android.graphics.ColorMatrixColorFilter; import android.graphics.Paint; +import android.graphics.Rect; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.os.Build; @@ -49,6 +50,7 @@ public abstract class NotificationViewWrapper implements TransformableView { protected final View mView; protected final ExpandableNotificationRow mRow; + private final Rect mTmpRect = new Rect(); protected int mBackgroundColor = 0; @@ -305,6 +307,26 @@ public abstract class NotificationViewWrapper implements TransformableView { return false; } + /** + * Is a given x and y coordinate on a view. + * + * @param view the view to be checked + * @param x the x coordinate, relative to the ExpandableNotificationRow + * @param y the y coordinate, relative to the ExpandableNotificationRow + * @return {@code true} if it is on the view + */ + protected boolean isOnView(View view, float x, float y) { + View searchView = (View) view.getParent(); + while (searchView != null && !(searchView instanceof ExpandableNotificationRow)) { + searchView.getHitRect(mTmpRect); + x -= mTmpRect.left; + y -= mTmpRect.top; + searchView = (View) searchView.getParent(); + } + view.getHitRect(mTmpRect); + return mTmpRect.contains((int) x,(int) y); + } + public int getMinLayoutHeight() { return 0; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java index c282cb8a5cb5..0b747f94e935 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java @@ -114,8 +114,9 @@ public class HeadsUpTouchHelper implements Gefingerpoken { mInitialTouchY = y; int startHeight = (int) (mPickedChild.getActualHeight() + mPickedChild.getTranslationY()); - mPanel.setPanelScrimMinFraction((float) startHeight - / mPanel.getMaxPanelHeight()); + float maxPanelHeight = mPanel.getMaxPanelHeight(); + mPanel.setPanelScrimMinFraction(maxPanelHeight > 0f + ? (float) startHeight / maxPanelHeight : 0f); mPanel.startExpandMotion(x, y, true /* startTracking */, startHeight); mPanel.startExpandingFromPeek(); // This call needs to be after the expansion start otherwise we will get a diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java index c61d7bbf67c5..f9726d2d77f9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java @@ -1844,7 +1844,14 @@ public class NotificationPanelViewController extends PanelViewController { } else { maxHeight = calculatePanelHeightShade(); } - maxHeight = Math.max(maxHeight, min); + maxHeight = Math.max(min, maxHeight); + if (maxHeight == 0) { + Log.wtf(TAG, "maxPanelHeight is 0. getOverExpansionAmount(): " + + getOverExpansionAmount() + ", calculatePanelHeightQsExpanded: " + + calculatePanelHeightQsExpanded() + ", calculatePanelHeightShade: " + + calculatePanelHeightShade() + ", mStatusBarMinHeight = " + + mStatusBarMinHeight + ", mQsMinExpansionHeight = " + mQsMinExpansionHeight); + } return maxHeight; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java index 8d8c8da62b4c..c1065189f716 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java @@ -16,6 +16,8 @@ package com.android.systemui.statusbar.phone; +import static java.lang.Float.isNaN; + import android.content.Context; import android.os.Bundle; import android.os.Parcelable; @@ -161,6 +163,9 @@ public abstract class PanelBar extends FrameLayout { * fraction as the panel also might be expanded if the fraction is 0 */ public void panelExpansionChanged(float frac, boolean expanded) { + if (isNaN(frac)) { + throw new IllegalArgumentException("frac cannot be NaN"); + } boolean fullyClosed = true; boolean fullyOpened = false; if (SPEW) LOG("panelExpansionChanged: start state=%d", mState); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java index e25c14c86fd5..1c1e7c4eaa4a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java @@ -18,6 +18,8 @@ package com.android.systemui.statusbar.phone; import static com.android.systemui.ScreenDecorations.DisplayCutoutView.boundsFromDirection; +import static java.lang.Float.isNaN; + import android.annotation.Nullable; import android.content.Context; import android.content.res.Configuration; @@ -254,6 +256,9 @@ public class PhoneStatusBarView extends PanelBar { @Override public void panelScrimMinFractionChanged(float minFraction) { + if (isNaN(minFraction)) { + throw new IllegalArgumentException("minFraction cannot be NaN"); + } if (mMinFraction != minFraction) { mMinFraction = minFraction; updateScrimFraction(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java index 7d532a88caac..38c165b661b4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java @@ -65,7 +65,6 @@ public class HotspotControllerImpl implements HotspotController, WifiManager.Sof new TetheringManager.TetheringEventCallback() { @Override public void onTetheringSupported(boolean supported) { - super.onTetheringSupported(supported); if (mIsTetheringSupported != supported) { mIsTetheringSupported = supported; fireHotspotAvailabilityChanged(); @@ -75,7 +74,6 @@ public class HotspotControllerImpl implements HotspotController, WifiManager.Sof @Override public void onTetherableInterfaceRegexpsChanged( TetheringManager.TetheringInterfaceRegexps reg) { - super.onTetherableInterfaceRegexpsChanged(reg); final boolean newValue = reg.getTetherableWifiRegexs().size() != 0; if (mHasTetherableWifiRegexs != newValue) { mHasTetherableWifiRegexs = newValue; diff --git a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java index a36f2c754243..bb2eea9dd134 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java +++ b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java @@ -31,6 +31,7 @@ import android.util.Log; import androidx.test.InstrumentationRegistry; import com.android.keyguard.KeyguardUpdateMonitor; +import com.android.settingslib.bluetooth.LocalBluetoothManager; import com.android.systemui.classifier.FalsingManagerFake; import com.android.systemui.plugins.FalsingManager; @@ -80,6 +81,9 @@ public abstract class SysuiTestCase { // None of them actually need it. mDependency.injectTestDependency(FalsingManager.class, new FalsingManagerFake()); mDependency.injectMockDependency(KeyguardUpdateMonitor.class); + + // TODO: b/151614195 investigate root cause of needing this mock dependency + mDependency.injectMockDependency(LocalBluetoothManager.class); } @After diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.java index ac304210d416..dbbbaac66554 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.java @@ -85,6 +85,8 @@ public class QSPanelTest extends SysuiTestCase { @Mock private NotificationMediaManager mNotificationMediaManager; @Mock + private Executor mForegroundExecutor; + @Mock private Executor mBackgroundExecutor; @Mock private LocalBluetoothManager mLocalBluetoothManager; @@ -97,7 +99,7 @@ public class QSPanelTest extends SysuiTestCase { mTestableLooper.runWithLooper(() -> { mMetricsLogger = mDependency.injectMockDependency(MetricsLogger.class); mQsPanel = new QSPanel(mContext, null, mDumpManager, mBroadcastDispatcher, - mQSLogger, mNotificationMediaManager, mBackgroundExecutor, + mQSLogger, mNotificationMediaManager, mForegroundExecutor, mBackgroundExecutor, mLocalBluetoothManager); // Provides a parent with non-zero size for QSPanel mParentView = new FrameLayout(mContext); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.java new file mode 100644 index 000000000000..0c109c498dd7 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.java @@ -0,0 +1,191 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.notification.collection.coordinator; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; + +import androidx.test.filters.SmallTest; + +import com.android.systemui.SysuiTestCase; +import com.android.systemui.statusbar.NotificationRemoteInputManager; +import com.android.systemui.statusbar.RemoteInputController; +import com.android.systemui.statusbar.notification.collection.NotifPipeline; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; +import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder; +import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter; +import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSection; +import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener; +import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender; +import com.android.systemui.statusbar.policy.HeadsUpManager; +import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +@SmallTest +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper +public class HeadsUpCoordinatorTest extends SysuiTestCase { + + private HeadsUpCoordinator mCoordinator; + + // captured listeners and pluggables: + private NotifCollectionListener mCollectionListener; + private NotifPromoter mNotifPromoter; + private NotifLifetimeExtender mNotifLifetimeExtender; + private OnHeadsUpChangedListener mOnHeadsUpChangedListener; + private NotifSection mNotifSection; + + @Mock private NotifPipeline mNotifPipeline; + @Mock private HeadsUpManager mHeadsUpManager; + @Mock private NotificationRemoteInputManager mRemoteInputManager; + @Mock private RemoteInputController mRemoteInputController; + @Mock private NotifLifetimeExtender.OnEndLifetimeExtensionCallback mEndLifetimeExtension; + + private NotificationEntry mEntry; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + when(mRemoteInputManager.getController()).thenReturn(mRemoteInputController); + + mCoordinator = new HeadsUpCoordinator( + mHeadsUpManager, + mRemoteInputManager + ); + + mCoordinator.attach(mNotifPipeline); + + // capture arguments: + ArgumentCaptor<NotifCollectionListener> notifCollectionCaptor = + ArgumentCaptor.forClass(NotifCollectionListener.class); + ArgumentCaptor<NotifPromoter> notifPromoterCaptor = + ArgumentCaptor.forClass(NotifPromoter.class); + ArgumentCaptor<NotifLifetimeExtender> notifLifetimeExtenderCaptor = + ArgumentCaptor.forClass(NotifLifetimeExtender.class); + ArgumentCaptor<OnHeadsUpChangedListener> headsUpChangedListenerCaptor = + ArgumentCaptor.forClass(OnHeadsUpChangedListener.class); + + verify(mNotifPipeline).addCollectionListener(notifCollectionCaptor.capture()); + verify(mNotifPipeline).addPromoter(notifPromoterCaptor.capture()); + verify(mNotifPipeline).addNotificationLifetimeExtender( + notifLifetimeExtenderCaptor.capture()); + verify(mHeadsUpManager).addListener(headsUpChangedListenerCaptor.capture()); + + mCollectionListener = notifCollectionCaptor.getValue(); + mNotifPromoter = notifPromoterCaptor.getValue(); + mNotifLifetimeExtender = notifLifetimeExtenderCaptor.getValue(); + mOnHeadsUpChangedListener = headsUpChangedListenerCaptor.getValue(); + + mNotifSection = mCoordinator.getSection(); + mNotifLifetimeExtender.setCallback(mEndLifetimeExtension); + mEntry = new NotificationEntryBuilder().build(); + } + + @Test + public void testPromotesCurrentHUN() { + // GIVEN the current HUN is set to mEntry + setCurrentHUN(mEntry); + + // THEN only promote the current HUN, mEntry + assertTrue(mNotifPromoter.shouldPromoteToTopLevel(mEntry)); + assertFalse(mNotifPromoter.shouldPromoteToTopLevel(new NotificationEntryBuilder().build())); + } + + @Test + public void testIncludeInSectionCurrentHUN() { + // GIVEN the current HUN is set to mEntry + setCurrentHUN(mEntry); + + // THEN only section the current HUN, mEntry + assertTrue(mNotifSection.isInSection(mEntry)); + assertFalse(mNotifSection.isInSection(new NotificationEntryBuilder().build())); + } + + @Test + public void testLifetimeExtendsCurrentHUN() { + // GIVEN there is a HUN, mEntry + setCurrentHUN(mEntry); + + // THEN only the current HUN, mEntry, should be lifetimeExtended + assertTrue(mNotifLifetimeExtender.shouldExtendLifetime(mEntry, /* cancellationReason */ 0)); + assertFalse(mNotifLifetimeExtender.shouldExtendLifetime( + new NotificationEntryBuilder().build(), /* cancellationReason */ 0)); + } + + @Test + public void testLifetimeExtensionEndsOnNewHUN() { + // GIVEN there was a HUN that was lifetime extended + setCurrentHUN(mEntry); + assertTrue(mNotifLifetimeExtender.shouldExtendLifetime( + mEntry, /* cancellation reason */ 0)); + + // WHEN there's a new HUN + NotificationEntry newHUN = new NotificationEntryBuilder().build(); + setCurrentHUN(newHUN); + + // THEN the old entry's lifetime extension should be cancelled + verify(mEndLifetimeExtension).onEndLifetimeExtension(mNotifLifetimeExtender, mEntry); + } + + @Test + public void testLifetimeExtensionEndsOnNoHUNs() { + // GIVEN there was a HUN that was lifetime extended + setCurrentHUN(mEntry); + assertTrue(mNotifLifetimeExtender.shouldExtendLifetime( + mEntry, /* cancellation reason */ 0)); + + // WHEN there's no longer a HUN + setCurrentHUN(null); + + // THEN the old entry's lifetime extension should be cancelled + verify(mEndLifetimeExtension).onEndLifetimeExtension(mNotifLifetimeExtender, mEntry); + } + + @Test + public void testOnEntryRemovedRemovesHeadsUpNotification() { + // GIVEN the current HUN is mEntry + setCurrentHUN(mEntry); + + // WHEN mEntry is removed from the notification collection + mCollectionListener.onEntryRemoved(mEntry, /* cancellation reason */ 0); + when(mRemoteInputController.isSpinning(any())).thenReturn(false); + + // THEN heads up manager should remove the entry + verify(mHeadsUpManager).removeNotification(mEntry.getKey(), false); + } + + private void setCurrentHUN(NotificationEntry entry) { + when(mHeadsUpManager.getTopEntry()).thenReturn(entry); + when(mHeadsUpManager.isAlerting(any())).thenReturn(false); + if (entry != null) { + when(mHeadsUpManager.isAlerting(entry.getKey())).thenReturn(true); + } + mOnHeadsUpChangedListener.onHeadsUpStateChanged(entry, entry != null); + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java index 6b9e43bcb290..8143cf5a4673 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinatorTest.java @@ -20,8 +20,10 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import android.os.RemoteException; import android.testing.AndroidTestingRunner; @@ -39,7 +41,9 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntryB import com.android.systemui.statusbar.notification.collection.listbuilder.OnBeforeFinalizeFilterListener; import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter; import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener; +import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider; import com.android.systemui.statusbar.notification.row.NotifInflationErrorManager; +import com.android.systemui.statusbar.policy.HeadsUpManager; import org.junit.Before; import org.junit.Test; @@ -74,6 +78,8 @@ public class PreparationCoordinatorTest extends SysuiTestCase { @Mock private NotifPipeline mNotifPipeline; @Mock private IStatusBarService mService; @Mock private NotifInflaterImpl mNotifInflater; + @Mock private NotificationInterruptStateProvider mNotificationInterruptStateProvider; + @Mock private HeadsUpManager mHeadsUpManager; @Before public void setUp() { @@ -88,7 +94,9 @@ public class PreparationCoordinatorTest extends SysuiTestCase { mNotifInflater, mErrorManager, mock(NotifViewBarn.class), - mService); + mService, + mNotificationInterruptStateProvider, + mHeadsUpManager); ArgumentCaptor<NotifFilter> filterCaptor = ArgumentCaptor.forClass(NotifFilter.class); mCoordinator.attach(mNotifPipeline); @@ -172,4 +180,24 @@ public class PreparationCoordinatorTest extends SysuiTestCase { // THEN it isn't filtered from shade list assertFalse(mUninflatedFilter.shouldFilterOut(mEntry, 0)); } + + @Test + public void testShowHUNOnInflationFinished() { + // WHEN a notification should HUN and its inflation is finished + when(mNotificationInterruptStateProvider.shouldHeadsUp(mEntry)).thenReturn(true); + mCallback.onInflationFinished(mEntry); + + // THEN we tell the HeadsUpManager to show the notification + verify(mHeadsUpManager).showNotification(mEntry); + } + + @Test + public void testNoHUNOnInflationFinished() { + // WHEN a notification shouldn't HUN and its inflation is finished + when(mNotificationInterruptStateProvider.shouldHeadsUp(mEntry)).thenReturn(false); + mCallback.onInflationFinished(mEntry); + + // THEN we never tell the HeadsUpManager to show the notification + verify(mHeadsUpManager, never()).showNotification(mEntry); + } } diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/OffloadController.java b/packages/Tethering/src/com/android/server/connectivity/tethering/OffloadController.java index a402ffa47355..15cdb6ad7a8e 100644 --- a/packages/Tethering/src/com/android/server/connectivity/tethering/OffloadController.java +++ b/packages/Tethering/src/com/android/server/connectivity/tethering/OffloadController.java @@ -39,8 +39,7 @@ import android.net.RouteInfo; import android.net.netlink.ConntrackMessage; import android.net.netlink.NetlinkConstants; import android.net.netlink.NetlinkSocket; -import android.net.netstats.provider.AbstractNetworkStatsProvider; -import android.net.netstats.provider.NetworkStatsProviderCallback; +import android.net.netstats.provider.NetworkStatsProvider; import android.net.util.SharedLog; import android.os.Handler; import android.provider.Settings; @@ -89,8 +88,8 @@ public class OffloadController { private final Handler mHandler; private final OffloadHardwareInterface mHwInterface; private final ContentResolver mContentResolver; - private final @NonNull OffloadTetheringStatsProvider mStatsProvider; - private final @Nullable NetworkStatsProviderCallback mStatsProviderCb; + @Nullable + private final OffloadTetheringStatsProvider mStatsProvider; private final SharedLog mLog; private final HashMap<String, LinkProperties> mDownstreams; private boolean mConfigInitialized; @@ -124,19 +123,18 @@ public class OffloadController { mHandler = h; mHwInterface = hwi; mContentResolver = contentResolver; - mStatsProvider = new OffloadTetheringStatsProvider(); mLog = log.forSubComponent(TAG); mDownstreams = new HashMap<>(); mExemptPrefixes = new HashSet<>(); mLastLocalPrefixStrs = new HashSet<>(); - NetworkStatsProviderCallback providerCallback = null; + OffloadTetheringStatsProvider provider = new OffloadTetheringStatsProvider(); try { - providerCallback = nsm.registerNetworkStatsProvider( - getClass().getSimpleName(), mStatsProvider); + nsm.registerNetworkStatsProvider(getClass().getSimpleName(), provider); } catch (RuntimeException e) { Log.wtf(TAG, "Cannot register offload stats provider: " + e); + provider = null; } - mStatsProviderCb = providerCallback; + mStatsProvider = provider; } /** Start hardware offload. */ @@ -185,7 +183,7 @@ public class OffloadController { // and we need to synchronize stats and limits between // software and hardware forwarding. updateStatsForAllUpstreams(); - mStatsProvider.pushTetherStats(); + if (mStatsProvider != null) mStatsProvider.pushTetherStats(); } @Override @@ -198,7 +196,7 @@ public class OffloadController { // limits set take into account any software tethering // traffic that has been happening in the meantime. updateStatsForAllUpstreams(); - mStatsProvider.pushTetherStats(); + if (mStatsProvider != null) mStatsProvider.pushTetherStats(); // [2] (Re)Push all state. computeAndPushLocalPrefixes(UpdateType.FORCE); pushAllDownstreamState(); @@ -217,10 +215,12 @@ public class OffloadController { // TODO: rev the HAL so that it provides an interface name. updateStatsForCurrentUpstream(); - mStatsProvider.pushTetherStats(); - // Push stats to service does not cause the service react to it immediately. - // Inform the service about limit reached. - if (mStatsProviderCb != null) mStatsProviderCb.onLimitReached(); + if (mStatsProvider != null) { + mStatsProvider.pushTetherStats(); + // Push stats to service does not cause the service react to it + // immediately. Inform the service about limit reached. + mStatsProvider.notifyLimitReached(); + } } @Override @@ -263,13 +263,17 @@ public class OffloadController { } @VisibleForTesting - class OffloadTetheringStatsProvider extends AbstractNetworkStatsProvider { + class OffloadTetheringStatsProvider extends NetworkStatsProvider { // These stats must only ever be touched on the handler thread. @NonNull private NetworkStats mIfaceStats = new NetworkStats(0L, 0); @NonNull private NetworkStats mUidStats = new NetworkStats(0L, 0); + /** + * A helper function that collect tether stats from local hashmap. Note that this does not + * invoke binder call. + */ @VisibleForTesting @NonNull NetworkStats getTetherStats(@NonNull StatsType how) { @@ -280,14 +284,14 @@ public class OffloadController { final ForwardedStats value = kv.getValue(); final Entry entry = new Entry(kv.getKey(), uid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, value.rxBytes, 0L, value.txBytes, 0L, 0L); - stats = stats.addValues(entry); + stats = stats.addEntry(entry); } return stats; } @Override - public void setLimit(String iface, long quotaBytes) { + public void onSetLimit(String iface, long quotaBytes) { // Listen for all iface is necessary since upstream might be changed after limit // is set. mHandler.post(() -> { @@ -315,13 +319,12 @@ public class OffloadController { */ public void pushTetherStats() { // TODO: remove the accumulated stats and report the diff from HAL directly. - if (null == mStatsProviderCb) return; final NetworkStats ifaceDiff = getTetherStats(StatsType.STATS_PER_IFACE).subtract(mIfaceStats); final NetworkStats uidDiff = getTetherStats(StatsType.STATS_PER_UID).subtract(mUidStats); try { - mStatsProviderCb.onStatsUpdated(0 /* token */, ifaceDiff, uidDiff); + notifyStatsUpdated(0 /* token */, ifaceDiff, uidDiff); mIfaceStats = mIfaceStats.add(ifaceDiff); mUidStats = mUidStats.add(uidDiff); } catch (RuntimeException e) { @@ -330,7 +333,7 @@ public class OffloadController { } @Override - public void requestStatsUpdate(int token) { + public void onRequestStatsUpdate(int token) { // Do not attempt to update stats by querying the offload HAL // synchronously from a different thread than the Handler thread. http://b/64771555. mHandler.post(() -> { @@ -340,7 +343,7 @@ public class OffloadController { } @Override - public void setAlert(long quotaBytes) { + public void onSetAlert(long quotaBytes) { // TODO: Ask offload HAL to notify alert without stopping traffic. } } diff --git a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/OffloadControllerTest.java b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/OffloadControllerTest.java index 7e62e5aca993..fe840864fb99 100644 --- a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/OffloadControllerTest.java +++ b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/OffloadControllerTest.java @@ -33,6 +33,8 @@ import static com.android.testutils.MiscAssertsKt.assertContainsAll; import static com.android.testutils.MiscAssertsKt.assertThrows; import static com.android.testutils.NetworkStatsUtilsKt.orderInsensitiveEquals; +import static junit.framework.Assert.assertNotNull; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.anyInt; @@ -61,8 +63,7 @@ import android.net.LinkProperties; import android.net.NetworkStats; import android.net.NetworkStats.Entry; import android.net.RouteInfo; -import android.net.netstats.provider.AbstractNetworkStatsProvider; -import android.net.netstats.provider.NetworkStatsProviderCallback; +import android.net.netstats.provider.INetworkStatsProviderCallback; import android.net.util.SharedLog; import android.os.Handler; import android.os.Looper; @@ -108,12 +109,10 @@ public class OffloadControllerTest { @Mock private ApplicationInfo mApplicationInfo; @Mock private Context mContext; @Mock private NetworkStatsManager mStatsManager; - @Mock private NetworkStatsProviderCallback mTetherStatsProviderCb; + @Mock private INetworkStatsProviderCallback mTetherStatsProviderCb; + private OffloadController.OffloadTetheringStatsProvider mTetherStatsProvider; private final ArgumentCaptor<ArrayList> mStringArrayCaptor = ArgumentCaptor.forClass(ArrayList.class); - private final ArgumentCaptor<OffloadController.OffloadTetheringStatsProvider> - mTetherStatsProviderCaptor = - ArgumentCaptor.forClass(OffloadController.OffloadTetheringStatsProvider.class); private final ArgumentCaptor<OffloadHardwareInterface.ControlCallback> mControlCallbackCaptor = ArgumentCaptor.forClass(OffloadHardwareInterface.ControlCallback.class); private MockContentResolver mContentResolver; @@ -126,8 +125,6 @@ public class OffloadControllerTest { mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider()); when(mContext.getContentResolver()).thenReturn(mContentResolver); FakeSettingsProvider.clearSettingsProvider(); - when(mStatsManager.registerNetworkStatsProvider(anyString(), any())) - .thenReturn(mTetherStatsProviderCb); } @After public void tearDown() throws Exception { @@ -154,8 +151,14 @@ public class OffloadControllerTest { private OffloadController makeOffloadController() throws Exception { OffloadController offload = new OffloadController(new Handler(Looper.getMainLooper()), mHardware, mContentResolver, mStatsManager, new SharedLog("test")); + final ArgumentCaptor<OffloadController.OffloadTetheringStatsProvider> + tetherStatsProviderCaptor = + ArgumentCaptor.forClass(OffloadController.OffloadTetheringStatsProvider.class); verify(mStatsManager).registerNetworkStatsProvider(anyString(), - mTetherStatsProviderCaptor.capture()); + tetherStatsProviderCaptor.capture()); + mTetherStatsProvider = tetherStatsProviderCaptor.getValue(); + assertNotNull(mTetherStatsProvider); + mTetherStatsProvider.setProviderCallbackBinder(mTetherStatsProviderCb); return offload; } @@ -413,9 +416,6 @@ public class OffloadControllerTest { final OffloadController offload = makeOffloadController(); offload.start(); - final OffloadController.OffloadTetheringStatsProvider provider = - mTetherStatsProviderCaptor.getValue(); - final String ethernetIface = "eth1"; final String mobileIface = "rmnet_data0"; @@ -443,15 +443,15 @@ public class OffloadControllerTest { inOrder.verify(mHardware, times(1)).getForwardedStats(eq(mobileIface)); // Verify that the fetched stats are stored. - final NetworkStats ifaceStats = provider.getTetherStats(STATS_PER_IFACE); - final NetworkStats uidStats = provider.getTetherStats(STATS_PER_UID); + final NetworkStats ifaceStats = mTetherStatsProvider.getTetherStats(STATS_PER_IFACE); + final NetworkStats uidStats = mTetherStatsProvider.getTetherStats(STATS_PER_UID); final NetworkStats expectedIfaceStats = new NetworkStats(0L, 2) - .addValues(buildTestEntry(STATS_PER_IFACE, mobileIface, 999, 99999)) - .addValues(buildTestEntry(STATS_PER_IFACE, ethernetIface, 12345, 54321)); + .addEntry(buildTestEntry(STATS_PER_IFACE, mobileIface, 999, 99999)) + .addEntry(buildTestEntry(STATS_PER_IFACE, ethernetIface, 12345, 54321)); final NetworkStats expectedUidStats = new NetworkStats(0L, 2) - .addValues(buildTestEntry(STATS_PER_UID, mobileIface, 999, 99999)) - .addValues(buildTestEntry(STATS_PER_UID, ethernetIface, 12345, 54321)); + .addEntry(buildTestEntry(STATS_PER_UID, mobileIface, 999, 99999)) + .addEntry(buildTestEntry(STATS_PER_UID, ethernetIface, 12345, 54321)); assertTrue(orderInsensitiveEquals(expectedIfaceStats, ifaceStats)); assertTrue(orderInsensitiveEquals(expectedUidStats, uidStats)); @@ -462,13 +462,12 @@ public class OffloadControllerTest { NetworkStats.class); // Force pushing stats update to verify the stats reported. - provider.pushTetherStats(); - verify(mTetherStatsProviderCb, times(1)).onStatsUpdated(anyInt(), - ifaceStatsCaptor.capture(), uidStatsCaptor.capture()); + mTetherStatsProvider.pushTetherStats(); + verify(mTetherStatsProviderCb, times(1)) + .notifyStatsUpdated(anyInt(), ifaceStatsCaptor.capture(), uidStatsCaptor.capture()); assertTrue(orderInsensitiveEquals(expectedIfaceStats, ifaceStatsCaptor.getValue())); assertTrue(orderInsensitiveEquals(expectedUidStats, uidStatsCaptor.getValue())); - when(mHardware.getForwardedStats(eq(ethernetIface))).thenReturn( new ForwardedStats(100000, 100000)); offload.setUpstreamLinkProperties(null); @@ -483,31 +482,31 @@ public class OffloadControllerTest { inOrder.verifyNoMoreInteractions(); // Verify that the stored stats is accumulated. - final NetworkStats ifaceStatsAccu = provider.getTetherStats(STATS_PER_IFACE); - final NetworkStats uidStatsAccu = provider.getTetherStats(STATS_PER_UID); + final NetworkStats ifaceStatsAccu = mTetherStatsProvider.getTetherStats(STATS_PER_IFACE); + final NetworkStats uidStatsAccu = mTetherStatsProvider.getTetherStats(STATS_PER_UID); final NetworkStats expectedIfaceStatsAccu = new NetworkStats(0L, 2) - .addValues(buildTestEntry(STATS_PER_IFACE, mobileIface, 999, 99999)) - .addValues(buildTestEntry(STATS_PER_IFACE, ethernetIface, 112345, 154321)); + .addEntry(buildTestEntry(STATS_PER_IFACE, mobileIface, 999, 99999)) + .addEntry(buildTestEntry(STATS_PER_IFACE, ethernetIface, 112345, 154321)); final NetworkStats expectedUidStatsAccu = new NetworkStats(0L, 2) - .addValues(buildTestEntry(STATS_PER_UID, mobileIface, 999, 99999)) - .addValues(buildTestEntry(STATS_PER_UID, ethernetIface, 112345, 154321)); + .addEntry(buildTestEntry(STATS_PER_UID, mobileIface, 999, 99999)) + .addEntry(buildTestEntry(STATS_PER_UID, ethernetIface, 112345, 154321)); assertTrue(orderInsensitiveEquals(expectedIfaceStatsAccu, ifaceStatsAccu)); assertTrue(orderInsensitiveEquals(expectedUidStatsAccu, uidStatsAccu)); // Verify that only diff of stats is reported. reset(mTetherStatsProviderCb); - provider.pushTetherStats(); + mTetherStatsProvider.pushTetherStats(); final NetworkStats expectedIfaceStatsDiff = new NetworkStats(0L, 2) - .addValues(buildTestEntry(STATS_PER_IFACE, mobileIface, 0, 0)) - .addValues(buildTestEntry(STATS_PER_IFACE, ethernetIface, 100000, 100000)); + .addEntry(buildTestEntry(STATS_PER_IFACE, mobileIface, 0, 0)) + .addEntry(buildTestEntry(STATS_PER_IFACE, ethernetIface, 100000, 100000)); final NetworkStats expectedUidStatsDiff = new NetworkStats(0L, 2) - .addValues(buildTestEntry(STATS_PER_UID, mobileIface, 0, 0)) - .addValues(buildTestEntry(STATS_PER_UID, ethernetIface, 100000, 100000)); - verify(mTetherStatsProviderCb, times(1)).onStatsUpdated(anyInt(), - ifaceStatsCaptor.capture(), uidStatsCaptor.capture()); + .addEntry(buildTestEntry(STATS_PER_UID, mobileIface, 0, 0)) + .addEntry(buildTestEntry(STATS_PER_UID, ethernetIface, 100000, 100000)); + verify(mTetherStatsProviderCb, times(1)) + .notifyStatsUpdated(anyInt(), ifaceStatsCaptor.capture(), uidStatsCaptor.capture()); assertTrue(orderInsensitiveEquals(expectedIfaceStatsDiff, ifaceStatsCaptor.getValue())); assertTrue(orderInsensitiveEquals(expectedUidStatsDiff, uidStatsCaptor.getValue())); } @@ -529,19 +528,18 @@ public class OffloadControllerTest { lp.setInterfaceName(ethernetIface); offload.setUpstreamLinkProperties(lp); - AbstractNetworkStatsProvider provider = mTetherStatsProviderCaptor.getValue(); final InOrder inOrder = inOrder(mHardware); when(mHardware.setUpstreamParameters(any(), any(), any(), any())).thenReturn(true); when(mHardware.setDataLimit(anyString(), anyLong())).thenReturn(true); // Applying an interface quota to the current upstream immediately sends it to the hardware. - provider.setLimit(ethernetIface, ethernetLimit); + mTetherStatsProvider.onSetLimit(ethernetIface, ethernetLimit); waitForIdle(); inOrder.verify(mHardware).setDataLimit(ethernetIface, ethernetLimit); inOrder.verifyNoMoreInteractions(); // Applying an interface quota to another upstream does not take any immediate action. - provider.setLimit(mobileIface, mobileLimit); + mTetherStatsProvider.onSetLimit(mobileIface, mobileLimit); waitForIdle(); inOrder.verify(mHardware, never()).setDataLimit(anyString(), anyLong()); @@ -554,7 +552,7 @@ public class OffloadControllerTest { // Setting a limit of ITetheringStatsProvider.QUOTA_UNLIMITED causes the limit to be set // to Long.MAX_VALUE. - provider.setLimit(mobileIface, ITetheringStatsProvider.QUOTA_UNLIMITED); + mTetherStatsProvider.onSetLimit(mobileIface, ITetheringStatsProvider.QUOTA_UNLIMITED); waitForIdle(); inOrder.verify(mHardware).setDataLimit(mobileIface, Long.MAX_VALUE); @@ -562,7 +560,7 @@ public class OffloadControllerTest { when(mHardware.setUpstreamParameters(any(), any(), any(), any())).thenReturn(false); lp.setInterfaceName(ethernetIface); offload.setUpstreamLinkProperties(lp); - provider.setLimit(mobileIface, mobileLimit); + mTetherStatsProvider.onSetLimit(mobileIface, mobileLimit); waitForIdle(); inOrder.verify(mHardware, never()).setDataLimit(anyString(), anyLong()); @@ -571,7 +569,7 @@ public class OffloadControllerTest { when(mHardware.setDataLimit(anyString(), anyLong())).thenReturn(false); lp.setInterfaceName(mobileIface); offload.setUpstreamLinkProperties(lp); - provider.setLimit(mobileIface, mobileLimit); + mTetherStatsProvider.onSetLimit(mobileIface, mobileLimit); waitForIdle(); inOrder.verify(mHardware).getForwardedStats(ethernetIface); inOrder.verify(mHardware).stopOffloadControl(); @@ -587,7 +585,7 @@ public class OffloadControllerTest { OffloadHardwareInterface.ControlCallback callback = mControlCallbackCaptor.getValue(); callback.onStoppedLimitReached(); - verify(mTetherStatsProviderCb, times(1)).onStatsUpdated(anyInt(), any(), any()); + verify(mTetherStatsProviderCb, times(1)).notifyStatsUpdated(anyInt(), any(), any()); } @Test @@ -691,7 +689,7 @@ public class OffloadControllerTest { verify(mHardware, times(1)).getForwardedStats(eq(RMNET0)); verify(mHardware, times(1)).getForwardedStats(eq(WLAN0)); // TODO: verify the exact stats reported. - verify(mTetherStatsProviderCb, times(1)).onStatsUpdated(anyInt(), any(), any()); + verify(mTetherStatsProviderCb, times(1)).notifyStatsUpdated(anyInt(), any(), any()); verifyNoMoreInteractions(mTetherStatsProviderCb); verifyNoMoreInteractions(mHardware); } @@ -756,7 +754,7 @@ public class OffloadControllerTest { // Verify forwarded stats behaviour. verify(mHardware, times(1)).getForwardedStats(eq(RMNET0)); verify(mHardware, times(1)).getForwardedStats(eq(WLAN0)); - verify(mTetherStatsProviderCb, times(1)).onStatsUpdated(anyInt(), any(), any()); + verify(mTetherStatsProviderCb, times(1)).notifyStatsUpdated(anyInt(), any(), any()); verifyNoMoreInteractions(mTetherStatsProviderCb); // TODO: verify local prefixes and downstreams are also pushed to the HAL. diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java index 6247a635233a..69154b49c96f 100644 --- a/services/backup/java/com/android/server/backup/UserBackupManagerService.java +++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java @@ -157,7 +157,6 @@ import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; import java.util.List; -import java.util.Map; import java.util.Objects; import java.util.Queue; import java.util.Random; @@ -174,29 +173,47 @@ public class UserBackupManagerService { public static class BackupWakeLock { private final PowerManager.WakeLock mPowerManagerWakeLock; private boolean mHasQuit = false; + private int mUserId; - public BackupWakeLock(PowerManager.WakeLock powerManagerWakeLock) { + public BackupWakeLock(PowerManager.WakeLock powerManagerWakeLock, int userId) { mPowerManagerWakeLock = powerManagerWakeLock; + mUserId = userId; } /** Acquires the {@link PowerManager.WakeLock} if hasn't been quit. */ public synchronized void acquire() { if (mHasQuit) { - Slog.v(TAG, "Ignore wakelock acquire after quit: " + mPowerManagerWakeLock.getTag()); + Slog.v( + TAG, + addUserIdToLogMessage( + mUserId, + "Ignore wakelock acquire after quit: " + + mPowerManagerWakeLock.getTag())); return; } mPowerManagerWakeLock.acquire(); - Slog.v(TAG, "Acquired wakelock:" + mPowerManagerWakeLock.getTag()); + Slog.v( + TAG, + addUserIdToLogMessage( + mUserId, "Acquired wakelock:" + mPowerManagerWakeLock.getTag())); } /** Releases the {@link PowerManager.WakeLock} if hasn't been quit. */ public synchronized void release() { if (mHasQuit) { - Slog.v(TAG, "Ignore wakelock release after quit: " + mPowerManagerWakeLock.getTag()); + Slog.v( + TAG, + addUserIdToLogMessage( + mUserId, + "Ignore wakelock release after quit: " + + mPowerManagerWakeLock.getTag())); return; } mPowerManagerWakeLock.release(); - Slog.v(TAG, "Released wakelock:" + mPowerManagerWakeLock.getTag()); + Slog.v( + TAG, + addUserIdToLogMessage( + mUserId, "Released wakelock:" + mPowerManagerWakeLock.getTag())); } /** @@ -209,7 +226,10 @@ public class UserBackupManagerService { /** Release the {@link PowerManager.WakeLock} till it isn't held. */ public synchronized void quit() { while (mPowerManagerWakeLock.isHeld()) { - Slog.v(TAG, "Releasing wakelock: " + mPowerManagerWakeLock.getTag()); + Slog.v( + TAG, + addUserIdToLogMessage( + mUserId, "Releasing wakelock: " + mPowerManagerWakeLock.getTag())); mPowerManagerWakeLock.release(); } mHasQuit = true; @@ -439,7 +459,9 @@ public class UserBackupManagerService { } if (DEBUG) { - Slog.v(TAG, "Starting with transport " + currentTransport); + Slog.v( + TAG, + addUserIdToLogMessage(userId, "Starting with transport " + currentTransport)); } TransportManager transportManager = new TransportManager(userId, context, transportWhitelist, currentTransport); @@ -451,7 +473,9 @@ public class UserBackupManagerService { new HandlerThread("backup-" + userId, Process.THREAD_PRIORITY_BACKGROUND); userBackupThread.start(); if (DEBUG) { - Slog.d(TAG, "Started thread " + userBackupThread.getName() + " for user " + userId); + Slog.d( + TAG, + addUserIdToLogMessage(userId, "Started thread " + userBackupThread.getName())); } return createAndInitializeService( @@ -556,7 +580,10 @@ public class UserBackupManagerService { if (userId == UserHandle.USER_SYSTEM) { mBaseStateDir.mkdirs(); if (!SELinux.restorecon(mBaseStateDir)) { - Slog.w(TAG, "SELinux restorecon failed on " + mBaseStateDir); + Slog.w( + TAG, + addUserIdToLogMessage( + userId, "SELinux restorecon failed on " + mBaseStateDir)); } } @@ -604,7 +631,8 @@ public class UserBackupManagerService { addPackageParticipantsLocked(null); } - mTransportManager = Objects.requireNonNull(transportManager, "transportManager cannot be null"); + mTransportManager = + Objects.requireNonNull(transportManager, "transportManager cannot be null"); mTransportManager.setOnTransportRegisteredListener(this::onTransportRegistered); mRegisterTransportsRequestedTime = SystemClock.elapsedRealtime(); mBackupHandler.postDelayed( @@ -620,7 +648,7 @@ public class UserBackupManagerService { mWakelock = new BackupWakeLock( mPowerManager.newWakeLock( PowerManager.PARTIAL_WAKE_LOCK, - "*backup*-" + userId + "-" + userBackupThread.getThreadId())); + "*backup*-" + userId + "-" + userBackupThread.getThreadId()), userId); // Set up the various sorts of package tracking we do mFullBackupScheduleFile = new File(mBaseStateDir, "fb-schedule"); @@ -869,7 +897,7 @@ public class UserBackupManagerService { } private void initPackageTracking() { - if (MORE_DEBUG) Slog.v(TAG, "` tracking"); + if (MORE_DEBUG) Slog.v(TAG, addUserIdToLogMessage(mUserId, "` tracking")); // Remember our ancestral dataset mTokenFile = new File(mBaseStateDir, "ancestral"); @@ -891,9 +919,9 @@ public class UserBackupManagerService { } } catch (FileNotFoundException fnf) { // Probably innocuous - Slog.v(TAG, "No ancestral data"); + Slog.v(TAG, addUserIdToLogMessage(mUserId, "No ancestral data")); } catch (IOException e) { - Slog.w(TAG, "Unable to read token file", e); + Slog.w(TAG, addUserIdToLogMessage(mUserId, "Unable to read token file"), e); } mProcessedPackagesJournal = new ProcessedPackagesJournal(mBaseStateDir); @@ -941,7 +969,10 @@ public class UserBackupManagerService { DataInputStream in = new DataInputStream(bufStream)) { int version = in.readInt(); if (version != SCHEDULE_FILE_VERSION) { - Slog.e(TAG, "Unknown backup schedule version " + version); + Slog.e( + TAG, + addUserIdToLogMessage( + mUserId, "Unknown backup schedule version " + version)); return null; } @@ -966,14 +997,14 @@ public class UserBackupManagerService { schedule.add(new FullBackupEntry(pkgName, lastBackup)); } else { if (DEBUG) { - Slog.i(TAG, "Package " + pkgName - + " no longer eligible for full backup"); + Slog.i(TAG, addUserIdToLogMessage(mUserId, "Package " + pkgName + + " no longer eligible for full backup")); } } } catch (NameNotFoundException e) { if (DEBUG) { - Slog.i(TAG, "Package " + pkgName - + " not installed; dropping from full backup"); + Slog.i(TAG, addUserIdToLogMessage(mUserId, "Package " + pkgName + + " not installed; dropping from full backup")); } } } @@ -986,7 +1017,13 @@ public class UserBackupManagerService { mUserId)) { if (!foundApps.contains(app.packageName)) { if (MORE_DEBUG) { - Slog.i(TAG, "New full backup app " + app.packageName + " found"); + Slog.i( + TAG, + addUserIdToLogMessage( + mUserId, + "New full backup app " + + app.packageName + + " found")); } schedule.add(new FullBackupEntry(app.packageName, 0)); changed = true; @@ -996,7 +1033,7 @@ public class UserBackupManagerService { Collections.sort(schedule); } catch (Exception e) { - Slog.e(TAG, "Unable to read backup schedule", e); + Slog.e(TAG, addUserIdToLogMessage(mUserId, "Unable to read backup schedule"), e); mFullBackupScheduleFile.delete(); schedule = null; } @@ -1052,7 +1089,11 @@ public class UserBackupManagerService { out.write(bufStream.toByteArray()); af.finishWrite(out); } catch (Exception e) { - Slog.e(TAG, "Unable to write backup schedule!", e); + Slog.e( + TAG, + addUserIdToLogMessage( + mUserId, "Unable to write backup schedule!"), + e); } } } @@ -1069,12 +1110,17 @@ public class UserBackupManagerService { if (!journal.equals(mJournal)) { try { journal.forEach(packageName -> { - Slog.i(TAG, "Found stale backup journal, scheduling"); - if (MORE_DEBUG) Slog.i(TAG, " " + packageName); + Slog.i( + TAG, + addUserIdToLogMessage( + mUserId, "Found stale backup journal, scheduling")); + if (MORE_DEBUG) { + Slog.i(TAG, addUserIdToLogMessage(mUserId, " " + packageName)); + } dataChangedImpl(packageName); }); } catch (IOException e) { - Slog.e(TAG, "Can't read " + journal, e); + Slog.e(TAG, addUserIdToLogMessage(mUserId, "Can't read " + journal), e); } } } @@ -1114,7 +1160,14 @@ public class UserBackupManagerService { boolean isPending, String transportName, String transportDirName) { synchronized (mQueueLock) { if (MORE_DEBUG) { - Slog.i(TAG, "recordInitPending(" + isPending + ") on transport " + transportName); + Slog.i( + TAG, + addUserIdToLogMessage( + mUserId, + "recordInitPending(" + + isPending + + ") on transport " + + transportName)); } File stateDir = new File(mBaseStateDir, transportDirName); @@ -1175,8 +1228,17 @@ public class UserBackupManagerService { private void onTransportRegistered(String transportName, String transportDirName) { if (DEBUG) { long timeMs = SystemClock.elapsedRealtime() - mRegisterTransportsRequestedTime; - Slog.d(TAG, "Transport " + transportName + " registered " + timeMs - + "ms after first request (delay = " + INITIALIZATION_DELAY_MILLIS + "ms)"); + Slog.d( + TAG, + addUserIdToLogMessage( + mUserId, + "Transport " + + transportName + + " registered " + + timeMs + + "ms after first request (delay = " + + INITIALIZATION_DELAY_MILLIS + + "ms)")); } File stateDir = new File(mBaseStateDir, transportDirName); @@ -1202,7 +1264,7 @@ public class UserBackupManagerService { private BroadcastReceiver mPackageTrackingReceiver = new BroadcastReceiver() { public void onReceive(Context context, Intent intent) { if (MORE_DEBUG) { - Slog.d(TAG, "Received broadcast " + intent); + Slog.d(TAG, addUserIdToLogMessage(mUserId, "Received broadcast " + intent)); } String action = intent.getAction(); @@ -1222,24 +1284,33 @@ public class UserBackupManagerService { String packageName = uri.getSchemeSpecificPart(); if (packageName != null) { - packageList = new String[]{packageName}; + packageList = new String[] {packageName}; } changed = Intent.ACTION_PACKAGE_CHANGED.equals(action); if (changed) { // Look at new transport states for package changed events. String[] components = - intent.getStringArrayExtra(Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST); + intent.getStringArrayExtra( + Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST); if (MORE_DEBUG) { - Slog.i(TAG, "Package " + packageName + " changed"); + Slog.i( + TAG, + addUserIdToLogMessage( + mUserId, "Package " + packageName + " changed")); for (int i = 0; i < components.length; i++) { - Slog.i(TAG, " * " + components[i]); + Slog.i( + TAG, + addUserIdToLogMessage( + mUserId, " * " + components[i])); } } mBackupHandler.post( - () -> mTransportManager.onPackageChanged(packageName, components)); + () -> + mTransportManager.onPackageChanged( + packageName, components)); return; } @@ -1261,7 +1332,8 @@ public class UserBackupManagerService { if (added) { synchronized (mBackupParticipants) { if (replacing) { - // Remove the entry under the old uid and fall through to re-add. If an app + // Remove the entry under the old uid and fall through to re-add. If + // an app // just opted into key/value backup, add it as a known participant. removePackageParticipantsLocked(packageList, uid); } @@ -1275,13 +1347,15 @@ public class UserBackupManagerService { mPackageManager.getPackageInfoAsUser( packageName, /* flags */ 0, mUserId); if (AppBackupUtils.appGetsFullBackup(app) - && AppBackupUtils.appIsEligibleForBackup(app.applicationInfo, - mUserId)) { + && AppBackupUtils.appIsEligibleForBackup( + app.applicationInfo, mUserId)) { enqueueFullBackup(packageName, now); scheduleNextFullBackupJob(0); } else { - // The app might have just transitioned out of full-data into doing - // key/value backups, or might have just disabled backups entirely. Make + // The app might have just transitioned out of full-data into + // doing + // key/value backups, or might have just disabled backups + // entirely. Make // sure it is no longer in the full-data queue. synchronized (mQueueLock) { dequeueFullBackupLocked(packageName); @@ -1293,17 +1367,23 @@ public class UserBackupManagerService { () -> mTransportManager.onPackageAdded(packageName)); } catch (NameNotFoundException e) { if (DEBUG) { - Slog.w(TAG, "Can't resolve new app " + packageName); + Slog.w( + TAG, + addUserIdToLogMessage( + mUserId, + "Can't resolve new app " + packageName)); } } } - // Whenever a package is added or updated we need to update the package metadata + // Whenever a package is added or updated we need to update the package + // metadata // bookkeeping. dataChangedImpl(PACKAGE_MANAGER_SENTINEL); } else { if (!replacing) { - // Outright removal. In the full-data case, the app will be dropped from the + // Outright removal. In the full-data case, the app will be dropped from + // the // queue when its (now obsolete) name comes up again for backup. synchronized (mBackupParticipants) { removePackageParticipantsLocked(packageList, uid); @@ -1324,12 +1404,19 @@ public class UserBackupManagerService { // Look for apps that define the android:backupAgent attribute List<PackageInfo> targetApps = allAgentPackages(); if (packageNames != null) { - if (MORE_DEBUG) Slog.v(TAG, "addPackageParticipantsLocked: #" + packageNames.length); + if (MORE_DEBUG) { + Slog.v( + TAG, + addUserIdToLogMessage( + mUserId, "addPackageParticipantsLocked: #" + packageNames.length)); + } for (String packageName : packageNames) { addPackageParticipantsLockedInner(packageName, targetApps); } } else { - if (MORE_DEBUG) Slog.v(TAG, "addPackageParticipantsLocked: all"); + if (MORE_DEBUG) { + Slog.v(TAG, addUserIdToLogMessage(mUserId, "addPackageParticipantsLocked: all")); + } addPackageParticipantsLockedInner(null, targetApps); } } @@ -1337,7 +1424,10 @@ public class UserBackupManagerService { private void addPackageParticipantsLockedInner(String packageName, List<PackageInfo> targetPkgs) { if (MORE_DEBUG) { - Slog.v(TAG, "Examining " + packageName + " for backup agent"); + Slog.v( + TAG, + addUserIdToLogMessage( + mUserId, "Examining " + packageName + " for backup agent")); } for (PackageInfo pkg : targetPkgs) { @@ -1349,10 +1439,15 @@ public class UserBackupManagerService { mBackupParticipants.put(uid, set); } set.add(pkg.packageName); - if (MORE_DEBUG) Slog.v(TAG, "Agent found; added"); + if (MORE_DEBUG) Slog.v(TAG, addUserIdToLogMessage(mUserId, "Agent found; added")); // Schedule a backup for it on general principles - if (MORE_DEBUG) Slog.i(TAG, "Scheduling backup for new app " + pkg.packageName); + if (MORE_DEBUG) { + Slog.i( + TAG, + addUserIdToLogMessage( + mUserId, "Scheduling backup for new app " + pkg.packageName)); + } Message msg = mBackupHandler .obtainMessage(MSG_SCHEDULE_BACKUP_PACKAGE, pkg.packageName); mBackupHandler.sendMessage(msg); @@ -1363,13 +1458,19 @@ public class UserBackupManagerService { // Remove the given packages' entries from our known active set. private void removePackageParticipantsLocked(String[] packageNames, int oldUid) { if (packageNames == null) { - Slog.w(TAG, "removePackageParticipants with null list"); + Slog.w(TAG, addUserIdToLogMessage(mUserId, "removePackageParticipants with null list")); return; } if (MORE_DEBUG) { - Slog.v(TAG, "removePackageParticipantsLocked: uid=" + oldUid - + " #" + packageNames.length); + Slog.v( + TAG, + addUserIdToLogMessage( + mUserId, + "removePackageParticipantsLocked: uid=" + + oldUid + + " #" + + packageNames.length)); } for (String pkg : packageNames) { // Known previous UID, so we know which package set to check @@ -1377,7 +1478,12 @@ public class UserBackupManagerService { if (set != null && set.contains(pkg)) { removePackageFromSetLocked(set, pkg); if (set.isEmpty()) { - if (MORE_DEBUG) Slog.v(TAG, " last one of this uid; purging set"); + if (MORE_DEBUG) { + Slog.v( + TAG, + addUserIdToLogMessage( + mUserId, " last one of this uid; purging set")); + } mBackupParticipants.remove(oldUid); } } @@ -1393,7 +1499,11 @@ public class UserBackupManagerService { // Note that we deliberately leave it 'known' in the "ever backed up" // bookkeeping so that its current-dataset data will be retrieved // if the app is subsequently reinstalled - if (MORE_DEBUG) Slog.v(TAG, " removing participant " + packageName); + if (MORE_DEBUG) { + Slog.v( + TAG, + addUserIdToLogMessage(mUserId, " removing participant " + packageName)); + } set.remove(packageName); mPendingBackups.remove(packageName); } @@ -1467,14 +1577,19 @@ public class UserBackupManagerService { af.writeInt(-1); } else { af.writeInt(mAncestralPackages.size()); - if (DEBUG) Slog.v(TAG, "Ancestral packages: " + mAncestralPackages.size()); + if (DEBUG) { + Slog.v( + TAG, + addUserIdToLogMessage( + mUserId, "Ancestral packages: " + mAncestralPackages.size())); + } for (String pkgName : mAncestralPackages) { af.writeUTF(pkgName); - if (MORE_DEBUG) Slog.v(TAG, " " + pkgName); + if (MORE_DEBUG) Slog.v(TAG, addUserIdToLogMessage(mUserId, " " + pkgName)); } } } catch (IOException e) { - Slog.w(TAG, "Unable to write token file:", e); + Slog.w(TAG, addUserIdToLogMessage(mUserId, "Unable to write token file:"), e); } } @@ -1487,7 +1602,7 @@ public class UserBackupManagerService { mConnectedAgent = null; try { if (mActivityManager.bindBackupAgent(app.packageName, mode, mUserId)) { - Slog.d(TAG, "awaiting agent for " + app); + Slog.d(TAG, addUserIdToLogMessage(mUserId, "awaiting agent for " + app)); // success; wait for the agent to arrive // only wait 10 seconds for the bind to happen @@ -1498,7 +1613,7 @@ public class UserBackupManagerService { mAgentConnectLock.wait(5000); } catch (InterruptedException e) { // just bail - Slog.w(TAG, "Interrupted: " + e); + Slog.w(TAG, addUserIdToLogMessage(mUserId, "Interrupted: " + e)); mConnecting = false; mConnectedAgent = null; } @@ -1506,10 +1621,14 @@ public class UserBackupManagerService { // if we timed out with no connect, abort and move on if (mConnecting) { - Slog.w(TAG, "Timeout waiting for agent " + app); + Slog.w( + TAG, + addUserIdToLogMessage(mUserId, "Timeout waiting for agent " + app)); mConnectedAgent = null; } - if (DEBUG) Slog.i(TAG, "got agent " + mConnectedAgent); + if (DEBUG) { + Slog.i(TAG, addUserIdToLogMessage(mUserId, "got agent " + mConnectedAgent)); + } agent = mConnectedAgent; } } catch (RemoteException e) { @@ -1575,13 +1694,20 @@ public class UserBackupManagerService { if (!shouldClearData) { if (MORE_DEBUG) { - Slog.i(TAG, "Clearing app data is not allowed so not wiping " - + packageName); + Slog.i( + TAG, + addUserIdToLogMessage( + mUserId, + "Clearing app data is not allowed so not wiping " + + packageName)); } return; } } catch (NameNotFoundException e) { - Slog.w(TAG, "Tried to clear data for " + packageName + " but not found"); + Slog.w( + TAG, + addUserIdToLogMessage( + mUserId, "Tried to clear data for " + packageName + " but not found")); return; } @@ -1604,13 +1730,22 @@ public class UserBackupManagerService { } catch (InterruptedException e) { // won't happen, but still. mClearingData = false; - Slog.w(TAG, "Interrupted while waiting for " + packageName - + " data to be cleared", e); + Slog.w( + TAG, + addUserIdToLogMessage( + mUserId, + "Interrupted while waiting for " + + packageName + + " data to be cleared"), + e); } } if (mClearingData) { - Slog.w(TAG, "Clearing app data for " + packageName + " timed out"); + Slog.w( + TAG, + addUserIdToLogMessage( + mUserId, "Clearing app data for " + packageName + " timed out")); } } } @@ -1627,12 +1762,17 @@ public class UserBackupManagerService { synchronized (mQueueLock) { if (mCurrentToken != 0 && mProcessedPackagesJournal.hasBeenProcessed(packageName)) { if (MORE_DEBUG) { - Slog.i(TAG, "App in ever-stored, so using current token"); + Slog.i( + TAG, + addUserIdToLogMessage( + mUserId, "App in ever-stored, so using current token")); } token = mCurrentToken; } } - if (MORE_DEBUG) Slog.i(TAG, "getAvailableRestoreToken() == " + token); + if (MORE_DEBUG) { + Slog.i(TAG, addUserIdToLogMessage(mUserId, "getAvailableRestoreToken() == " + token)); + } return token; } @@ -1654,7 +1794,7 @@ public class UserBackupManagerService { mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "requestBackup"); if (packages == null || packages.length < 1) { - Slog.e(TAG, "No packages named for backup request"); + Slog.e(TAG, addUserIdToLogMessage(mUserId, "No packages named for backup request")); BackupObserverUtils.sendBackupFinished(observer, BackupManager.ERROR_TRANSPORT_ABORTED); monitor = BackupManagerMonitorUtils.monitorEvent(monitor, BackupManagerMonitor.LOG_EVENT_ID_NO_PACKAGES, @@ -1665,10 +1805,10 @@ public class UserBackupManagerService { if (!mEnabled || !mSetupComplete) { Slog.i( TAG, - "Backup requested but enabled=" + addUserIdToLogMessage(mUserId, "Backup requested but enabled=" + mEnabled + " setupComplete=" - + mSetupComplete); + + mSetupComplete)); BackupObserverUtils.sendBackupFinished(observer, BackupManager.ERROR_BACKUP_NOT_ALLOWED); final int logTag = mSetupComplete @@ -1726,9 +1866,17 @@ public class UserBackupManagerService { EventLog.writeEvent(EventLogTags.BACKUP_REQUESTED, packages.length, kvBackupList.size(), fullBackupList.size()); if (MORE_DEBUG) { - Slog.i(TAG, "Backup requested for " + packages.length + " packages, of them: " - + fullBackupList.size() + " full backups, " + kvBackupList.size() - + " k/v backups"); + Slog.i( + TAG, + addUserIdToLogMessage( + mUserId, + "Backup requested for " + + packages.length + + " packages, of them: " + + fullBackupList.size() + + " full backups, " + + kvBackupList.size() + + " k/v backups")); } boolean nonIncrementalBackup = (flags & BackupManager.FLAG_NON_INCREMENTAL_BACKUP) != 0; @@ -1744,7 +1892,7 @@ public class UserBackupManagerService { public void cancelBackups() { mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "cancelBackups"); if (MORE_DEBUG) { - Slog.i(TAG, "cancelBackups() called."); + Slog.i(TAG, addUserIdToLogMessage(mUserId, "cancelBackups() called.")); } final long oldToken = Binder.clearCallingIdentity(); try { @@ -1774,13 +1922,27 @@ public class UserBackupManagerService { public void prepareOperationTimeout(int token, long interval, BackupRestoreTask callback, int operationType) { if (operationType != OP_TYPE_BACKUP_WAIT && operationType != OP_TYPE_RESTORE_WAIT) { - Slog.wtf(TAG, "prepareOperationTimeout() doesn't support operation " - + Integer.toHexString(token) + " of type " + operationType); + Slog.wtf( + TAG, + addUserIdToLogMessage( + mUserId, + "prepareOperationTimeout() doesn't support operation " + + Integer.toHexString(token) + + " of type " + + operationType)); return; } if (MORE_DEBUG) { - Slog.v(TAG, "starting timeout: token=" + Integer.toHexString(token) - + " interval=" + interval + " callback=" + callback); + Slog.v( + TAG, + addUserIdToLogMessage( + mUserId, + "starting timeout: token=" + + Integer.toHexString(token) + + " interval=" + + interval + + " callback=" + + callback)); } synchronized (mCurrentOpLock) { @@ -1798,8 +1960,12 @@ public class UserBackupManagerService { case OP_TYPE_RESTORE_WAIT: return MSG_RESTORE_OPERATION_TIMEOUT; default: - Slog.wtf(TAG, "getMessageIdForOperationType called on invalid operation type: " - + operationType); + Slog.wtf( + TAG, + addUserIdToLogMessage( + mUserId, + "getMessageIdForOperationType called on invalid operation type: " + + operationType)); return -1; } } @@ -1810,8 +1976,14 @@ public class UserBackupManagerService { */ public void putOperation(int token, Operation operation) { if (MORE_DEBUG) { - Slog.d(TAG, "Adding operation token=" + Integer.toHexString(token) + ", operation type=" - + operation.type); + Slog.d( + TAG, + addUserIdToLogMessage( + mUserId, + "Adding operation token=" + + Integer.toHexString(token) + + ", operation type=" + + operation.type)); } synchronized (mCurrentOpLock) { mCurrentOperations.put(token, operation); @@ -1824,12 +1996,15 @@ public class UserBackupManagerService { */ public void removeOperation(int token) { if (MORE_DEBUG) { - Slog.d(TAG, "Removing operation token=" + Integer.toHexString(token)); + Slog.d( + TAG, + addUserIdToLogMessage( + mUserId, "Removing operation token=" + Integer.toHexString(token))); } synchronized (mCurrentOpLock) { if (mCurrentOperations.get(token) == null) { - Slog.w(TAG, "Duplicate remove for operation. token=" - + Integer.toHexString(token)); + Slog.w(TAG, addUserIdToLogMessage(mUserId, "Duplicate remove for operation. token=" + + Integer.toHexString(token))); } mCurrentOperations.remove(token); } @@ -1838,8 +2013,8 @@ public class UserBackupManagerService { /** Block until we received an operation complete message (from the agent or cancellation). */ public boolean waitUntilOperationComplete(int token) { if (MORE_DEBUG) { - Slog.i(TAG, "Blocking until operation complete for " - + Integer.toHexString(token)); + Slog.i(TAG, addUserIdToLogMessage(mUserId, "Blocking until operation complete for " + + Integer.toHexString(token))); } int finalState = OP_PENDING; Operation op = null; @@ -1858,8 +2033,12 @@ public class UserBackupManagerService { // When the wait is notified we loop around and recheck the current state } else { if (MORE_DEBUG) { - Slog.d(TAG, "Unblocked waiting for operation token=" - + Integer.toHexString(token)); + Slog.d( + TAG, + addUserIdToLogMessage( + mUserId, + "Unblocked waiting for operation token=" + + Integer.toHexString(token))); } // No longer pending; we're done finalState = op.state; @@ -1874,8 +2053,8 @@ public class UserBackupManagerService { mBackupHandler.removeMessages(getMessageIdForOperationType(op.type)); } if (MORE_DEBUG) { - Slog.v(TAG, "operation " + Integer.toHexString(token) - + " complete: finalState=" + finalState); + Slog.v(TAG, addUserIdToLogMessage(mUserId, "operation " + Integer.toHexString(token) + + " complete: finalState=" + finalState)); } return finalState == OP_ACKNOWLEDGED; } @@ -1888,21 +2067,31 @@ public class UserBackupManagerService { op = mCurrentOperations.get(token); if (MORE_DEBUG) { if (op == null) { - Slog.w(TAG, "Cancel of token " + Integer.toHexString(token) - + " but no op found"); + Slog.w( + TAG, + addUserIdToLogMessage( + mUserId, + "Cancel of token " + + Integer.toHexString(token) + + " but no op found")); } } int state = (op != null) ? op.state : OP_TIMEOUT; if (state == OP_ACKNOWLEDGED) { // The operation finished cleanly, so we have nothing more to do. if (DEBUG) { - Slog.w(TAG, "Operation already got an ack." - + "Should have been removed from mCurrentOperations."); + Slog.w(TAG, addUserIdToLogMessage(mUserId, "Operation already got an ack." + + "Should have been removed from mCurrentOperations.")); } op = null; mCurrentOperations.delete(token); } else if (state == OP_PENDING) { - if (DEBUG) Slog.v(TAG, "Cancel: token=" + Integer.toHexString(token)); + if (DEBUG) { + Slog.v( + TAG, + addUserIdToLogMessage( + mUserId, "Cancel: token=" + Integer.toHexString(token))); + } op.state = OP_TIMEOUT; // Can't delete op from mCurrentOperations here. waitUntilOperationComplete may be // called after we receive cancel here. We need this op's state there. @@ -1920,7 +2109,7 @@ public class UserBackupManagerService { // If there's a TimeoutHandler for this event, call it if (op != null && op.callback != null) { if (MORE_DEBUG) { - Slog.v(TAG, " Invoking cancel on " + op.callback); + Slog.v(TAG, addUserIdToLogMessage(mUserId, " Invoking cancel on " + op.callback)); } op.callback.handleCancel(cancelAll); } @@ -1955,13 +2144,20 @@ public class UserBackupManagerService { // manifest flag! TODO something less direct. if (!UserHandle.isCore(app.uid) && !app.packageName.equals("com.android.backupconfirm")) { - if (MORE_DEBUG) Slog.d(TAG, "Killing agent host process"); + if (MORE_DEBUG) { + Slog.d(TAG, addUserIdToLogMessage(mUserId, "Killing agent host process")); + } mActivityManager.killApplicationProcess(app.processName, app.uid); } else { - if (MORE_DEBUG) Slog.d(TAG, "Not killing after operation: " + app.processName); + if (MORE_DEBUG) { + Slog.d( + TAG, + addUserIdToLogMessage( + mUserId, "Not killing after operation: " + app.processName)); + } } } catch (RemoteException e) { - Slog.d(TAG, "Lost app trying to shut down"); + Slog.d(TAG, addUserIdToLogMessage(mUserId, "Lost app trying to shut down")); } } @@ -1975,7 +2171,12 @@ public class UserBackupManagerService { } catch (Exception e) { // If we can't talk to the storagemanager service we have a serious problem; fail // "secure" i.e. assuming that the device is encrypted. - Slog.e(TAG, "Unable to communicate with storagemanager service: " + e.getMessage()); + Slog.e( + TAG, + addUserIdToLogMessage( + mUserId, + "Unable to communicate with storagemanager service: " + + e.getMessage())); return true; } } @@ -1999,7 +2200,10 @@ public class UserBackupManagerService { FullBackupJob.schedule(mUserId, mContext, latency, mConstants); } else { if (DEBUG_SCHEDULING) { - Slog.i(TAG, "Full backup queue empty; not scheduling"); + Slog.i( + TAG, + addUserIdToLogMessage( + mUserId, "Full backup queue empty; not scheduling")); } } } @@ -2054,7 +2258,10 @@ public class UserBackupManagerService { private boolean fullBackupAllowable(String transportName) { if (!mTransportManager.isTransportRegistered(transportName)) { - Slog.w(TAG, "Transport not registered; full data backup not performed"); + Slog.w( + TAG, + addUserIdToLogMessage( + mUserId, "Transport not registered; full data backup not performed")); return false; } @@ -2066,12 +2273,19 @@ public class UserBackupManagerService { File pmState = new File(stateDir, PACKAGE_MANAGER_SENTINEL); if (pmState.length() <= 0) { if (DEBUG) { - Slog.i(TAG, "Full backup requested but dataset not yet initialized"); + Slog.i( + TAG, + addUserIdToLogMessage( + mUserId, + "Full backup requested but dataset not yet initialized")); } return false; } } catch (Exception e) { - Slog.w(TAG, "Unable to get transport name: " + e.getMessage()); + Slog.w( + TAG, + addUserIdToLogMessage( + mUserId, "Unable to get transport name: " + e.getMessage())); return false; } @@ -2104,8 +2318,8 @@ public class UserBackupManagerService { // the job driving automatic backups; that job will be scheduled again when // the user enables backup. if (MORE_DEBUG) { - Slog.i(TAG, "beginFullBackup but enabled=" + mEnabled - + " setupComplete=" + mSetupComplete + "; ignoring"); + Slog.i(TAG, addUserIdToLogMessage(mUserId, "beginFullBackup but enabled=" + mEnabled + + " setupComplete=" + mSetupComplete + "; ignoring")); } return false; } @@ -2115,19 +2329,29 @@ public class UserBackupManagerService { final PowerSaveState result = mPowerManager.getPowerSaveState(ServiceType.FULL_BACKUP); if (result.batterySaverEnabled) { - if (DEBUG) Slog.i(TAG, "Deferring scheduled full backups in battery saver mode"); + if (DEBUG) { + Slog.i( + TAG, + addUserIdToLogMessage( + mUserId, "Deferring scheduled full backups in battery saver mode")); + } FullBackupJob.schedule(mUserId, mContext, keyValueBackupInterval, mConstants); return false; } if (DEBUG_SCHEDULING) { - Slog.i(TAG, "Beginning scheduled full backup operation"); + Slog.i( + TAG, + addUserIdToLogMessage(mUserId, "Beginning scheduled full backup operation")); } // Great; we're able to run full backup jobs now. See if we have any work to do. synchronized (mQueueLock) { if (mRunningFullBackupTask != null) { - Slog.e(TAG, "Backup triggered but one already/still running!"); + Slog.e( + TAG, + addUserIdToLogMessage( + mUserId, "Backup triggered but one already/still running!")); return false; } @@ -2143,7 +2367,10 @@ public class UserBackupManagerService { if (mFullBackupQueue.size() == 0) { // no work to do so just bow out if (DEBUG) { - Slog.i(TAG, "Backup queue empty; doing nothing"); + Slog.i( + TAG, + addUserIdToLogMessage( + mUserId, "Backup queue empty; doing nothing")); } runBackup = false; break; @@ -2154,7 +2381,10 @@ public class UserBackupManagerService { String transportName = mTransportManager.getCurrentTransportName(); if (!fullBackupAllowable(transportName)) { if (MORE_DEBUG) { - Slog.i(TAG, "Preconditions not met; not running full backup"); + Slog.i( + TAG, + addUserIdToLogMessage( + mUserId, "Preconditions not met; not running full backup")); } runBackup = false; // Typically this means we haven't run a key/value backup yet. Back off @@ -2170,7 +2400,11 @@ public class UserBackupManagerService { if (!runBackup) { // It's too early to back up the next thing in the queue, so bow out if (MORE_DEBUG) { - Slog.i(TAG, "Device ready but too early to back up next app"); + Slog.i( + TAG, + addUserIdToLogMessage( + mUserId, + "Device ready but too early to back up next app")); } // Wait until the next app in the queue falls due for a full data backup latency = fullBackupInterval - timeSinceRun; @@ -2185,8 +2419,14 @@ public class UserBackupManagerService { // so we cull it and force a loop around to consider the new head // app. if (MORE_DEBUG) { - Slog.i(TAG, "Culling package " + entry.packageName - + " in full-backup queue but not eligible"); + Slog.i( + TAG, + addUserIdToLogMessage( + mUserId, + "Culling package " + + entry.packageName + + " in full-backup queue but not" + + " eligible")); } mFullBackupQueue.remove(0); headBusy = true; // force the while() condition @@ -2204,9 +2444,14 @@ public class UserBackupManagerService { + mTokenGenerator.nextInt(BUSY_BACKOFF_FUZZ); if (DEBUG_SCHEDULING) { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); - Slog.i(TAG, "Full backup time but " + entry.packageName - + " is busy; deferring to " - + sdf.format(new Date(nextEligible))); + Slog.i( + TAG, + addUserIdToLogMessage( + mUserId, + "Full backup time but " + + entry.packageName + + " is busy; deferring to " + + sdf.format(new Date(nextEligible)))); } // This relocates the app's entry from the head of the queue to // its order-appropriate position further down, so upon looping @@ -2225,7 +2470,11 @@ public class UserBackupManagerService { if (!runBackup) { if (DEBUG_SCHEDULING) { - Slog.i(TAG, "Nothing pending full backup; rescheduling +" + latency); + Slog.i( + TAG, + addUserIdToLogMessage( + mUserId, + "Nothing pending full backup; rescheduling +" + latency)); } final long deferTime = latency; // pin for the closure FullBackupJob.schedule(mUserId, mContext, deferTime, mConstants); @@ -2273,7 +2522,10 @@ public class UserBackupManagerService { } if (pftbt != null) { if (DEBUG_SCHEDULING) { - Slog.i(TAG, "Telling running backup to stop"); + Slog.i( + TAG, + addUserIdToLogMessage( + mUserId, "Telling running backup to stop")); } pftbt.handleCancel(true); } @@ -2286,7 +2538,7 @@ public class UserBackupManagerService { public void restoreWidgetData(String packageName, byte[] widgetData) { // Apply the restored widget state and generate the ID update for the app if (MORE_DEBUG) { - Slog.i(TAG, "Incorporating restored widget data"); + Slog.i(TAG, addUserIdToLogMessage(mUserId, "Incorporating restored widget data")); } AppWidgetBackupBridge.restoreWidgetState(packageName, widgetData, mUserId); } @@ -2306,8 +2558,15 @@ public class UserBackupManagerService { // may share a uid, we need to note all candidates within that uid and schedule // a backup pass for each of them. if (targets == null) { - Slog.w(TAG, "dataChanged but no participant pkg='" + packageName + "'" - + " uid=" + Binder.getCallingUid()); + Slog.w( + TAG, + addUserIdToLogMessage( + mUserId, + "dataChanged but no participant pkg='" + + packageName + + "'" + + " uid=" + + Binder.getCallingUid())); return; } @@ -2318,7 +2577,12 @@ public class UserBackupManagerService { // one already there, then overwrite it, but no harm done. BackupRequest req = new BackupRequest(packageName); if (mPendingBackups.put(packageName, req) == null) { - if (MORE_DEBUG) Slog.d(TAG, "Now staging backup of " + packageName); + if (MORE_DEBUG) { + Slog.d( + TAG, + addUserIdToLogMessage( + mUserId, "Now staging backup of " + packageName)); + } // Journal this request in case of crash. The put() // operation returned null when this package was not already @@ -2358,7 +2622,10 @@ public class UserBackupManagerService { if (mJournal == null) mJournal = DataChangedJournal.newJournal(mJournalDir); mJournal.addPackage(str); } catch (IOException e) { - Slog.e(TAG, "Can't write " + str + " to backup journal", e); + Slog.e( + TAG, + addUserIdToLogMessage(mUserId, "Can't write " + str + " to backup journal"), + e); mJournal = null; } } @@ -2369,8 +2636,15 @@ public class UserBackupManagerService { public void dataChanged(final String packageName) { final HashSet<String> targets = dataChangedTargets(packageName); if (targets == null) { - Slog.w(TAG, "dataChanged but no participant pkg='" + packageName + "'" - + " uid=" + Binder.getCallingUid()); + Slog.w( + TAG, + addUserIdToLogMessage( + mUserId, + "dataChanged but no participant pkg='" + + packageName + + "'" + + " uid=" + + Binder.getCallingUid())); return; } @@ -2385,7 +2659,10 @@ public class UserBackupManagerService { public void initializeTransports(String[] transportNames, IBackupObserver observer) { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, "initializeTransport"); - Slog.v(TAG, "initializeTransport(): " + Arrays.asList(transportNames)); + Slog.v( + TAG, + addUserIdToLogMessage( + mUserId, "initializeTransport(): " + Arrays.asList(transportNames))); final long oldId = Binder.clearCallingIdentity(); try { @@ -2404,11 +2681,18 @@ public class UserBackupManagerService { public void setAncestralSerialNumber(long ancestralSerialNumber) { mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "setAncestralSerialNumber"); - Slog.v(TAG, "Setting ancestral work profile id to " + ancestralSerialNumber); + Slog.v( + TAG, + addUserIdToLogMessage( + mUserId, "Setting ancestral work profile id to " + ancestralSerialNumber)); try (RandomAccessFile af = getAncestralSerialNumberFile()) { af.writeLong(ancestralSerialNumber); } catch (IOException e) { - Slog.w(TAG, "Unable to write to work profile serial mapping file:", e); + Slog.w( + TAG, + addUserIdToLogMessage( + mUserId, "Unable to write to work profile serial mapping file:"), + e); } } @@ -2420,7 +2704,11 @@ public class UserBackupManagerService { try (RandomAccessFile af = getAncestralSerialNumberFile()) { return af.readLong(); } catch (IOException e) { - Slog.w(TAG, "Unable to write to work profile serial number file:", e); + Slog.w( + TAG, + addUserIdToLogMessage( + mUserId, "Unable to write to work profile serial number file:"), + e); return -1; } } @@ -2443,13 +2731,24 @@ public class UserBackupManagerService { /** Clear the given package's backup data from the current transport. */ public void clearBackupData(String transportName, String packageName) { - if (DEBUG) Slog.v(TAG, "clearBackupData() of " + packageName + " on " + transportName); + if (DEBUG) { + Slog.v( + TAG, + addUserIdToLogMessage( + mUserId, + "clearBackupData() of " + packageName + " on " + transportName)); + } + PackageInfo info; try { info = mPackageManager.getPackageInfoAsUser(packageName, PackageManager.GET_SIGNING_CERTIFICATES, mUserId); } catch (NameNotFoundException e) { - Slog.d(TAG, "No such package '" + packageName + "' - not clearing backup data"); + Slog.d( + TAG, + addUserIdToLogMessage( + mUserId, + "No such package '" + packageName + "' - not clearing backup data")); return; } @@ -2462,13 +2761,22 @@ public class UserBackupManagerService { } else { // a caller with full permission can ask to back up any participating app // !!! TODO: allow data-clear of ANY app? - if (MORE_DEBUG) Slog.v(TAG, "Privileged caller, allowing clear of other apps"); + if (MORE_DEBUG) { + Slog.v( + TAG, + addUserIdToLogMessage( + mUserId, "Privileged caller, allowing clear of other apps")); + } apps = mProcessedPackagesJournal.getPackagesCopy(); } if (apps.contains(packageName)) { // found it; fire off the clear request - if (MORE_DEBUG) Slog.v(TAG, "Found the app - running clear process"); + if (MORE_DEBUG) { + Slog.v( + TAG, + addUserIdToLogMessage(mUserId, "Found the app - running clear process")); + } mBackupHandler.removeMessages(MSG_RETRY_CLEAR); synchronized (mQueueLock) { TransportClient transportClient = @@ -2507,24 +2815,36 @@ public class UserBackupManagerService { final PowerSaveState result = mPowerManager.getPowerSaveState(ServiceType.KEYVALUE_BACKUP); if (result.batterySaverEnabled) { - if (DEBUG) Slog.v(TAG, "Not running backup while in battery save mode"); + if (DEBUG) { + Slog.v( + TAG, + addUserIdToLogMessage( + mUserId, "Not running backup while in battery save mode")); + } // Try again in several hours. KeyValueBackupJob.schedule(mUserId, mContext, mConstants); } else { - if (DEBUG) Slog.v(TAG, "Scheduling immediate backup pass"); + if (DEBUG) { + Slog.v(TAG, addUserIdToLogMessage(mUserId, "Scheduling immediate backup pass")); + } synchronized (getQueueLock()) { if (getPendingInits().size() > 0) { // If there are pending init operations, we process those and then settle // into the usual periodic backup schedule. if (MORE_DEBUG) { - Slog.v(TAG, "Init pending at scheduled backup"); + Slog.v( + TAG, + addUserIdToLogMessage( + mUserId, "Init pending at scheduled backup")); } try { getAlarmManager().cancel(mRunInitIntent); mRunInitIntent.send(); } catch (PendingIntent.CanceledException ce) { - Slog.w(TAG, "Run init intent cancelled"); + Slog.w( + TAG, + addUserIdToLogMessage(mUserId, "Run init intent cancelled")); } return; } @@ -2534,8 +2854,8 @@ public class UserBackupManagerService { if (!isEnabled() || !isSetupComplete()) { Slog.w( TAG, - "Backup pass but enabled=" + isEnabled() - + " setupComplete=" + isSetupComplete()); + addUserIdToLogMessage(mUserId, "Backup pass but enabled=" + isEnabled() + + " setupComplete=" + isSetupComplete())); return; } @@ -2582,16 +2902,31 @@ public class UserBackupManagerService { long oldId = Binder.clearCallingIdentity(); try { if (!mSetupComplete) { - Slog.i(TAG, "Backup not supported before setup"); + Slog.i(TAG, addUserIdToLogMessage(mUserId, "Backup not supported before setup")); return; } if (DEBUG) { - Slog.v(TAG, "Requesting backup: apks=" + includeApks + " obb=" + includeObbs - + " shared=" + includeShared + " all=" + doAllApps + " system=" - + includeSystem + " includekeyvalue=" + doKeyValue + " pkgs=" + pkgList); + Slog.v( + TAG, + addUserIdToLogMessage( + mUserId, + "Requesting backup: apks=" + + includeApks + + " obb=" + + includeObbs + + " shared=" + + includeShared + + " all=" + + doAllApps + + " system=" + + includeSystem + + " includekeyvalue=" + + doKeyValue + + " pkgs=" + + pkgList)); } - Slog.i(TAG, "Beginning adb backup..."); + Slog.i(TAG, addUserIdToLogMessage(mUserId, "Beginning adb backup...")); AdbBackupParams params = new AdbBackupParams(fd, includeApks, includeObbs, includeShared, doWidgets, doAllApps, includeSystem, compress, doKeyValue, @@ -2602,9 +2937,16 @@ public class UserBackupManagerService { } // start up the confirmation UI - if (DEBUG) Slog.d(TAG, "Starting backup confirmation UI, token=" + token); + if (DEBUG) { + Slog.d( + TAG, + addUserIdToLogMessage( + mUserId, "Starting backup confirmation UI, token=" + token)); + } if (!startConfirmationUi(token, FullBackup.FULL_BACKUP_INTENT_ACTION)) { - Slog.e(TAG, "Unable to launch backup confirmation UI"); + Slog.e( + TAG, + addUserIdToLogMessage(mUserId, "Unable to launch backup confirmation UI")); mAdbBackupRestoreConfirmations.delete(token); return; } @@ -2618,16 +2960,22 @@ public class UserBackupManagerService { startConfirmationTimeout(token, params); // wait for the backup to be performed - if (DEBUG) Slog.d(TAG, "Waiting for backup completion..."); + if (DEBUG) { + Slog.d(TAG, addUserIdToLogMessage(mUserId, "Waiting for backup completion...")); + } waitForCompletion(params); } finally { try { fd.close(); } catch (IOException e) { - Slog.e(TAG, "IO error closing output for adb backup: " + e.getMessage()); + Slog.e( + TAG, + addUserIdToLogMessage( + mUserId, + "IO error closing output for adb backup: " + e.getMessage())); } Binder.restoreCallingIdentity(oldId); - Slog.d(TAG, "Adb backup processing complete."); + Slog.d(TAG, addUserIdToLogMessage(mUserId, "Adb backup processing complete.")); } } @@ -2644,10 +2992,14 @@ public class UserBackupManagerService { String transportName = mTransportManager.getCurrentTransportName(); if (!fullBackupAllowable(transportName)) { - Slog.i(TAG, "Full backup not currently possible -- key/value backup not yet run?"); + Slog.i( + TAG, + addUserIdToLogMessage( + mUserId, + "Full backup not currently possible -- key/value backup not yet run?")); } else { if (DEBUG) { - Slog.d(TAG, "fullTransportBackup()"); + Slog.d(TAG, addUserIdToLogMessage(mUserId, "fullTransportBackup()")); } final long oldId = Binder.clearCallingIdentity(); @@ -2687,7 +3039,7 @@ public class UserBackupManagerService { } if (DEBUG) { - Slog.d(TAG, "Done with full transport backup."); + Slog.d(TAG, addUserIdToLogMessage(mUserId, "Done with full transport backup.")); } } @@ -2707,11 +3059,13 @@ public class UserBackupManagerService { try { if (!mSetupComplete) { - Slog.i(TAG, "Full restore not permitted before setup"); + Slog.i( + TAG, + addUserIdToLogMessage(mUserId, "Full restore not permitted before setup")); return; } - Slog.i(TAG, "Beginning restore..."); + Slog.i(TAG, addUserIdToLogMessage(mUserId, "Beginning restore...")); AdbRestoreParams params = new AdbRestoreParams(fd); final int token = generateRandomIntegerToken(); @@ -2720,9 +3074,16 @@ public class UserBackupManagerService { } // start up the confirmation UI - if (DEBUG) Slog.d(TAG, "Starting restore confirmation UI, token=" + token); + if (DEBUG) { + Slog.d( + TAG, + addUserIdToLogMessage( + mUserId, "Starting restore confirmation UI, token=" + token)); + } if (!startConfirmationUi(token, FullBackup.FULL_RESTORE_INTENT_ACTION)) { - Slog.e(TAG, "Unable to launch restore confirmation"); + Slog.e( + TAG, + addUserIdToLogMessage(mUserId, "Unable to launch restore confirmation")); mAdbBackupRestoreConfirmations.delete(token); return; } @@ -2736,16 +3097,21 @@ public class UserBackupManagerService { startConfirmationTimeout(token, params); // wait for the restore to be performed - if (DEBUG) Slog.d(TAG, "Waiting for restore completion..."); + if (DEBUG) { + Slog.d(TAG, addUserIdToLogMessage(mUserId, "Waiting for restore completion...")); + } waitForCompletion(params); } finally { try { fd.close(); } catch (IOException e) { - Slog.w(TAG, "Error trying to close fd after adb restore: " + e); + Slog.w( + TAG, + addUserIdToLogMessage( + mUserId, "Error trying to close fd after adb restore: " + e)); } Binder.restoreCallingIdentity(oldId); - Slog.i(TAG, "adb restore processing complete."); + Slog.i(TAG, addUserIdToLogMessage(mUserId, "adb restore processing complete.")); } } @@ -2773,8 +3139,8 @@ public class UserBackupManagerService { private void startConfirmationTimeout(int token, AdbParams params) { if (MORE_DEBUG) { - Slog.d(TAG, "Posting conf timeout msg after " - + TIMEOUT_FULL_CONFIRMATION + " millis"); + Slog.d(TAG, addUserIdToLogMessage(mUserId, "Posting conf timeout msg after " + + TIMEOUT_FULL_CONFIRMATION + " millis")); } Message msg = mBackupHandler.obtainMessage(MSG_FULL_CONFIRMATION_TIMEOUT, token, 0, params); @@ -2806,8 +3172,11 @@ public class UserBackupManagerService { public void acknowledgeAdbBackupOrRestore(int token, boolean allow, String curPassword, String encPpassword, IFullBackupRestoreObserver observer) { if (DEBUG) { - Slog.d(TAG, "acknowledgeAdbBackupOrRestore : token=" + token - + " allow=" + allow); + Slog.d( + TAG, + addUserIdToLogMessage( + mUserId, + "acknowledgeAdbBackupOrRestore : token=" + token + " allow=" + allow)); } // TODO: possibly require not just this signature-only permission, but even @@ -2835,17 +3204,29 @@ public class UserBackupManagerService { params.encryptPassword = encPpassword; - if (MORE_DEBUG) Slog.d(TAG, "Sending conf message with verb " + verb); + if (MORE_DEBUG) { + Slog.d( + TAG, + addUserIdToLogMessage( + mUserId, "Sending conf message with verb " + verb)); + } mWakelock.acquire(); Message msg = mBackupHandler.obtainMessage(verb, params); mBackupHandler.sendMessage(msg); } else { - Slog.w(TAG, "User rejected full backup/restore operation"); + Slog.w( + TAG, + addUserIdToLogMessage( + mUserId, "User rejected full backup/restore operation")); // indicate completion without having actually transferred any data signalAdbBackupRestoreCompletion(params); } } else { - Slog.w(TAG, "Attempted to ack full backup/restore with invalid token"); + Slog.w( + TAG, + addUserIdToLogMessage( + mUserId, + "Attempted to ack full backup/restore with invalid token")); } } } finally { @@ -2858,7 +3239,7 @@ public class UserBackupManagerService { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, "setBackupEnabled"); - Slog.i(TAG, "Backup enabled => " + enable); + Slog.i(TAG, addUserIdToLogMessage(mUserId, "Backup enabled => " + enable)); long oldId = Binder.clearCallingIdentity(); try { @@ -2875,7 +3256,9 @@ public class UserBackupManagerService { scheduleNextFullBackupJob(0); } else if (!enable) { // No longer enabled, so stop running backups - if (MORE_DEBUG) Slog.i(TAG, "Opting out of backup"); + if (MORE_DEBUG) { + Slog.i(TAG, addUserIdToLogMessage(mUserId, "Opting out of backup")); + } KeyValueBackupJob.cancel(mUserId, mContext); @@ -2891,12 +3274,15 @@ public class UserBackupManagerService { name -> { final String dirName; try { - dirName = - mTransportManager - .getTransportDirName(name); + dirName = mTransportManager.getTransportDirName(name); } catch (TransportNotRegisteredException e) { // Should never happen - Slog.e(TAG, "Unexpected unregistered transport", e); + Slog.e( + TAG, + addUserIdToLogMessage( + mUserId, + "Unexpected unregistered transport"), + e); return; } transportNames.add(name); @@ -2925,7 +3311,7 @@ public class UserBackupManagerService { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, "setAutoRestore"); - Slog.i(TAG, "Auto restore => " + doAutoRestore); + Slog.i(TAG, addUserIdToLogMessage(mUserId, "Auto restore => " + doAutoRestore)); final long oldId = Binder.clearCallingIdentity(); try { @@ -2951,7 +3337,12 @@ public class UserBackupManagerService { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, "getCurrentTransport"); String currentTransport = mTransportManager.getCurrentTransportName(); - if (MORE_DEBUG) Slog.v(TAG, "... getCurrentTransport() returning " + currentTransport); + if (MORE_DEBUG) { + Slog.v( + TAG, + addUserIdToLogMessage( + mUserId, "... getCurrentTransport() returning " + currentTransport)); + } return currentTransport; } @@ -3090,8 +3481,14 @@ public class UserBackupManagerService { try { String previousTransportName = mTransportManager.selectTransport(transportName); updateStateForTransport(transportName); - Slog.v(TAG, "selectBackupTransport(transport = " + transportName - + "): previous transport = " + previousTransportName); + Slog.v( + TAG, + addUserIdToLogMessage( + mUserId, + "selectBackupTransport(transport = " + + transportName + + "): previous transport = " + + previousTransportName)); return previousTransportName; } finally { Binder.restoreCallingIdentity(oldId); @@ -3110,7 +3507,11 @@ public class UserBackupManagerService { final long oldId = Binder.clearCallingIdentity(); try { String transportString = transportComponent.flattenToShortString(); - Slog.v(TAG, "selectBackupTransportAsync(transport = " + transportString + ")"); + Slog.v( + TAG, + addUserIdToLogMessage( + mUserId, + "selectBackupTransportAsync(transport = " + transportString + ")")); mBackupHandler.post( () -> { String transportName = null; @@ -3122,7 +3523,10 @@ public class UserBackupManagerService { mTransportManager.getTransportName(transportComponent); updateStateForTransport(transportName); } catch (TransportNotRegisteredException e) { - Slog.e(TAG, "Transport got unregistered"); + Slog.e( + TAG, + addUserIdToLogMessage( + mUserId, "Transport got unregistered")); result = BackupManager.ERROR_TRANSPORT_UNAVAILABLE; } } @@ -3134,7 +3538,12 @@ public class UserBackupManagerService { listener.onFailure(result); } } catch (RemoteException e) { - Slog.e(TAG, "ISelectBackupTransportCallback listener not available"); + Slog.e( + TAG, + addUserIdToLogMessage( + mUserId, + "ISelectBackupTransportCallback listener not" + + " available")); } }); } finally { @@ -3159,11 +3568,23 @@ public class UserBackupManagerService { // Oops. We can't know the current dataset token, so reset and figure it out // when we do the next k/v backup operation on this transport. mCurrentToken = 0; - Slog.w(TAG, "Transport " + newTransportName + " not available: current token = 0"); + Slog.w( + TAG, + addUserIdToLogMessage( + mUserId, + "Transport " + + newTransportName + + " not available: current token = 0")); } mTransportManager.disposeOfTransportClient(transportClient, callerLogString); } else { - Slog.w(TAG, "Transport " + newTransportName + " not registered: current token = 0"); + Slog.w( + TAG, + addUserIdToLogMessage( + mUserId, + "Transport " + + newTransportName + + " not registered: current token = 0")); // The named transport isn't registered, so we can't know what its current dataset token // is. Reset as above. mCurrentToken = 0; @@ -3181,11 +3602,19 @@ public class UserBackupManagerService { try { Intent intent = mTransportManager.getTransportConfigurationIntent(transportName); if (MORE_DEBUG) { - Slog.d(TAG, "getConfigurationIntent() returning intent " + intent); + Slog.d( + TAG, + addUserIdToLogMessage( + mUserId, "getConfigurationIntent() returning intent " + intent)); } return intent; } catch (TransportNotRegisteredException e) { - Slog.e(TAG, "Unable to get configuration intent from transport: " + e.getMessage()); + Slog.e( + TAG, + addUserIdToLogMessage( + mUserId, + "Unable to get configuration intent from transport: " + + e.getMessage())); return null; } } @@ -3206,11 +3635,18 @@ public class UserBackupManagerService { try { String string = mTransportManager.getTransportCurrentDestinationString(transportName); if (MORE_DEBUG) { - Slog.d(TAG, "getDestinationString() returning " + string); + Slog.d( + TAG, + addUserIdToLogMessage( + mUserId, "getDestinationString() returning " + string)); } return string; } catch (TransportNotRegisteredException e) { - Slog.e(TAG, "Unable to get destination string from transport: " + e.getMessage()); + Slog.e( + TAG, + addUserIdToLogMessage( + mUserId, + "Unable to get destination string from transport: " + e.getMessage())); return null; } } @@ -3223,11 +3659,18 @@ public class UserBackupManagerService { try { Intent intent = mTransportManager.getTransportDataManagementIntent(transportName); if (MORE_DEBUG) { - Slog.d(TAG, "getDataManagementIntent() returning intent " + intent); + Slog.d( + TAG, + addUserIdToLogMessage( + mUserId, "getDataManagementIntent() returning intent " + intent)); } return intent; } catch (TransportNotRegisteredException e) { - Slog.e(TAG, "Unable to get management intent from transport: " + e.getMessage()); + Slog.e( + TAG, + addUserIdToLogMessage( + mUserId, + "Unable to get management intent from transport: " + e.getMessage())); return null; } } @@ -3243,11 +3686,18 @@ public class UserBackupManagerService { try { CharSequence label = mTransportManager.getTransportDataManagementLabel(transportName); if (MORE_DEBUG) { - Slog.d(TAG, "getDataManagementLabel() returning " + label); + Slog.d( + TAG, + addUserIdToLogMessage( + mUserId, "getDataManagementLabel() returning " + label)); } return label; } catch (TransportNotRegisteredException e) { - Slog.e(TAG, "Unable to get management label from transport: " + e.getMessage()); + Slog.e( + TAG, + addUserIdToLogMessage( + mUserId, + "Unable to get management label from transport: " + e.getMessage())); return null; } } @@ -3259,12 +3709,21 @@ public class UserBackupManagerService { public void agentConnected(String packageName, IBinder agentBinder) { synchronized (mAgentConnectLock) { if (Binder.getCallingUid() == Process.SYSTEM_UID) { - Slog.d(TAG, "agentConnected pkg=" + packageName + " agent=" + agentBinder); + Slog.d( + TAG, + addUserIdToLogMessage( + mUserId, + "agentConnected pkg=" + packageName + " agent=" + agentBinder)); mConnectedAgent = IBackupAgent.Stub.asInterface(agentBinder); mConnecting = false; } else { - Slog.w(TAG, "Non-system process uid=" + Binder.getCallingUid() - + " claiming agent connected"); + Slog.w( + TAG, + addUserIdToLogMessage( + mUserId, + "Non-system process uid=" + + Binder.getCallingUid() + + " claiming agent connected")); } mAgentConnectLock.notifyAll(); } @@ -3282,8 +3741,13 @@ public class UserBackupManagerService { mConnectedAgent = null; mConnecting = false; } else { - Slog.w(TAG, "Non-system process uid=" + Binder.getCallingUid() - + " claiming agent disconnected"); + Slog.w( + TAG, + addUserIdToLogMessage( + mUserId, + "Non-system process uid=" + + Binder.getCallingUid() + + " claiming agent disconnected")); } mAgentConnectLock.notifyAll(); } @@ -3295,8 +3759,13 @@ public class UserBackupManagerService { */ public void restoreAtInstall(String packageName, int token) { if (Binder.getCallingUid() != Process.SYSTEM_UID) { - Slog.w(TAG, "Non-system process uid=" + Binder.getCallingUid() - + " attemping install-time restore"); + Slog.w( + TAG, + addUserIdToLogMessage( + mUserId, + "Non-system process uid=" + + Binder.getCallingUid() + + " attemping install-time restore")); return; } @@ -3304,25 +3773,35 @@ public class UserBackupManagerService { long restoreSet = getAvailableRestoreToken(packageName); if (DEBUG) { - Slog.v(TAG, "restoreAtInstall pkg=" + packageName - + " token=" + Integer.toHexString(token) - + " restoreSet=" + Long.toHexString(restoreSet)); + Slog.v( + TAG, + addUserIdToLogMessage( + mUserId, + "restoreAtInstall pkg=" + + packageName + + " token=" + + Integer.toHexString(token) + + " restoreSet=" + + Long.toHexString(restoreSet))); } if (restoreSet == 0) { - if (MORE_DEBUG) Slog.i(TAG, "No restore set"); + if (MORE_DEBUG) Slog.i(TAG, addUserIdToLogMessage(mUserId, "No restore set")); skip = true; } TransportClient transportClient = mTransportManager.getCurrentTransportClient("BMS.restoreAtInstall()"); if (transportClient == null) { - if (DEBUG) Slog.w(TAG, "No transport client"); + if (DEBUG) Slog.w(TAG, addUserIdToLogMessage(mUserId, "No transport client")); skip = true; } if (!mAutoRestore) { if (DEBUG) { - Slog.w(TAG, "Non-restorable state: auto=" + mAutoRestore); + Slog.w( + TAG, + addUserIdToLogMessage( + mUserId, "Non-restorable state: auto=" + mAutoRestore)); } skip = true; } @@ -3341,7 +3820,9 @@ public class UserBackupManagerService { }; if (MORE_DEBUG) { - Slog.d(TAG, "Restore at install of " + packageName); + Slog.d( + TAG, + addUserIdToLogMessage(mUserId, "Restore at install of " + packageName)); } Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE); msg.obj = @@ -3356,7 +3837,10 @@ public class UserBackupManagerService { mBackupHandler.sendMessage(msg); } catch (Exception e) { // Calling into the transport broke; back off and proceed with the installation. - Slog.e(TAG, "Unable to contact transport: " + e.getMessage()); + Slog.e( + TAG, + addUserIdToLogMessage( + mUserId, "Unable to contact transport: " + e.getMessage())); skip = true; } } @@ -3370,7 +3854,7 @@ public class UserBackupManagerService { } // Tell the PackageManager to proceed with the post-install handling for this package. - if (DEBUG) Slog.v(TAG, "Finishing install immediately"); + if (DEBUG) Slog.v(TAG, addUserIdToLogMessage(mUserId, "Finishing install immediately")); try { mPackageManagerBinder.finishPackageInstall(token, false); } catch (RemoteException e) { /* can't happen */ } @@ -3380,8 +3864,11 @@ public class UserBackupManagerService { /** Hand off a restore session. */ public IRestoreSession beginRestoreSession(String packageName, String transport) { if (DEBUG) { - Slog.v(TAG, "beginRestoreSession: pkg=" + packageName - + " transport=" + transport); + Slog.v( + TAG, + addUserIdToLogMessage( + mUserId, + "beginRestoreSession: pkg=" + packageName + " transport=" + transport)); } boolean needPermission = true; @@ -3393,7 +3880,10 @@ public class UserBackupManagerService { try { app = mPackageManager.getPackageInfoAsUser(packageName, 0, mUserId); } catch (NameNotFoundException nnf) { - Slog.w(TAG, "Asked to restore nonexistent pkg " + packageName); + Slog.w( + TAG, + addUserIdToLogMessage( + mUserId, "Asked to restore nonexistent pkg " + packageName)); throw new IllegalArgumentException("Package " + packageName + " not found"); } @@ -3407,19 +3897,32 @@ public class UserBackupManagerService { } if (needPermission) { - mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, - "beginRestoreSession"); + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.BACKUP, "beginRestoreSession"); } else { - if (DEBUG) Slog.d(TAG, "restoring self on current transport; no permission needed"); + if (DEBUG) { + Slog.d( + TAG, + addUserIdToLogMessage( + mUserId, + "restoring self on current transport; no permission needed")); + } } synchronized (this) { if (mActiveRestoreSession != null) { - Slog.i(TAG, "Restore session requested but one already active"); + Slog.i( + TAG, + addUserIdToLogMessage( + mUserId, "Restore session requested but one already active")); return null; } if (mBackupRunning) { - Slog.i(TAG, "Restore session requested but currently running backups"); + Slog.i( + TAG, + addUserIdToLogMessage( + mUserId, + "Restore session requested but currently running backups")); return null; } mActiveRestoreSession = new ActiveRestoreSession(this, packageName, transport); @@ -3433,9 +3936,14 @@ public class UserBackupManagerService { public void clearRestoreSession(ActiveRestoreSession currentSession) { synchronized (this) { if (currentSession != mActiveRestoreSession) { - Slog.e(TAG, "ending non-current restore session"); + Slog.e(TAG, addUserIdToLogMessage(mUserId, "ending non-current restore session")); } else { - if (DEBUG) Slog.v(TAG, "Clearing restore session and halting timeout"); + if (DEBUG) { + Slog.v( + TAG, + addUserIdToLogMessage( + mUserId, "Clearing restore session and halting timeout")); + } mActiveRestoreSession = null; mBackupHandler.removeMessages(MSG_RESTORE_SESSION_TIMEOUT); } @@ -3448,7 +3956,11 @@ public class UserBackupManagerService { */ public void opComplete(int token, long result) { if (MORE_DEBUG) { - Slog.v(TAG, "opComplete: " + Integer.toHexString(token) + " result=" + result); + Slog.v( + TAG, + addUserIdToLogMessage( + mUserId, + "opComplete: " + Integer.toHexString(token) + " result=" + result)); } Operation op = null; synchronized (mCurrentOpLock) { @@ -3461,8 +3973,12 @@ public class UserBackupManagerService { mCurrentOperations.delete(token); } else if (op.state == OP_ACKNOWLEDGED) { if (DEBUG) { - Slog.w(TAG, "Received duplicate ack for token=" - + Integer.toHexString(token)); + Slog.w( + TAG, + addUserIdToLogMessage( + mUserId, + "Received duplicate ack for token=" + + Integer.toHexString(token))); } op = null; mCurrentOperations.remove(token); @@ -3606,7 +4122,7 @@ public class UserBackupManagerService { " " + f.getName() + " - " + f.length() + " state bytes"); } } catch (Exception e) { - Slog.e(TAG, "Error in transport", e); + Slog.e(TAG, addUserIdToLogMessage(mUserId, "Error in transport"), e); pw.println(" Error: " + e); } } @@ -3665,6 +4181,10 @@ public class UserBackupManagerService { } } + private static String addUserIdToLogMessage(int userId, String message) { + return "[UserID:" + userId + "] " + message; + } + public IBackupManager getBackupManagerBinder() { return mBackupManagerBinder; diff --git a/services/core/java/com/android/server/PackageWatchdog.java b/services/core/java/com/android/server/PackageWatchdog.java index 52a1b5a62941..41a104c5d4dc 100644 --- a/services/core/java/com/android/server/PackageWatchdog.java +++ b/services/core/java/com/android/server/PackageWatchdog.java @@ -161,6 +161,9 @@ public class PackageWatchdog { private final Runnable mSaveToFile = this::saveToFile; private final SystemClock mSystemClock; private final BootThreshold mBootThreshold; + // The set of packages that have been synced with the ExplicitHealthCheckController + @GuardedBy("mLock") + private Set<String> mRequestedHealthCheckPackages = new ArraySet<>(); @GuardedBy("mLock") private boolean mIsPackagesReady; // Flag to control whether explicit health checks are supported or not @@ -174,6 +177,9 @@ public class PackageWatchdog { // 0 if no prune is scheduled. @GuardedBy("mLock") private long mUptimeAtLastStateSync; + // If true, sync explicit health check packages with the ExplicitHealthCheckController. + @GuardedBy("mLock") + private boolean mSyncRequired = false; @FunctionalInterface @VisibleForTesting @@ -249,6 +255,7 @@ public class PackageWatchdog { */ public void registerHealthObserver(PackageHealthObserver observer) { synchronized (mLock) { + mSyncRequired = true; ObserverInternal internalObserver = mAllObservers.get(observer.getName()); if (internalObserver != null) { internalObserver.registeredObserver = observer; @@ -628,17 +635,23 @@ public class PackageWatchdog { * @see #syncRequestsAsync */ private void syncRequests() { - Set<String> packages = null; + boolean syncRequired = false; synchronized (mLock) { if (mIsPackagesReady) { - packages = getPackagesPendingHealthChecksLocked(); + Set<String> packages = getPackagesPendingHealthChecksLocked(); + if (!packages.equals(mRequestedHealthCheckPackages) || mSyncRequired) { + syncRequired = true; + mRequestedHealthCheckPackages = packages; + } } // else, we will sync requests when packages become ready } // Call outside lock to avoid holding lock when calling into the controller. - if (packages != null) { - Slog.i(TAG, "Syncing health check requests for packages: " + packages); - mHealthCheckController.syncRequests(packages); + if (syncRequired) { + Slog.i(TAG, "Syncing health check requests for packages: " + + mRequestedHealthCheckPackages); + mHealthCheckController.syncRequests(mRequestedHealthCheckPackages); + mSyncRequired = false; } } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 1c225d9d64b2..ebca1f7e97a4 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -19842,6 +19842,7 @@ public class ActivityManagerService extends IActivityManager.Stub void setPermissions(@Nullable String[] permissions) { mPermissions = permissions; + PackageManager.invalidatePackageInfoCache(); } @Override diff --git a/services/core/java/com/android/server/am/BugReportHandlerUtil.java b/services/core/java/com/android/server/am/BugReportHandlerUtil.java index ba89fce0b3f8..03f4a54086a8 100644 --- a/services/core/java/com/android/server/am/BugReportHandlerUtil.java +++ b/services/core/java/com/android/server/am/BugReportHandlerUtil.java @@ -16,15 +16,20 @@ package com.android.server.am; +import static android.app.AppOpsManager.OP_NONE; import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; +import android.app.Activity; import android.app.BroadcastOptions; +import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.os.Binder; +import android.os.BugreportManager; +import android.os.BugreportParams; import android.os.UserHandle; import android.provider.Settings; import android.text.TextUtils; @@ -110,9 +115,17 @@ public final class BugReportHandlerUtil { options.setBackgroundActivityStartsAllowed(true); final long identity = Binder.clearCallingIdentity(); try { - context.sendBroadcastAsUser(intent, UserHandle.of(handlerUser), + // Handler app's BroadcastReceiver should call setResultCode(Activity.RESULT_OK) to + // let ResultBroadcastReceiver know the handler app is available. + context.sendOrderedBroadcastAsUser(intent, + UserHandle.of(handlerUser), android.Manifest.permission.DUMP, - options.toBundle()); + OP_NONE, options.toBundle(), + new ResultBroadcastReceiver(), + /* scheduler= */ null, + Activity.RESULT_CANCELED, + /* initialData= */ null, + /* initialExtras= */ null); } catch (RuntimeException e) { Slog.e(TAG, "Error while trying to launch bugreport handler app.", e); return false; @@ -176,4 +189,19 @@ public final class BugReportHandlerUtil { Binder.restoreCallingIdentity(identity); } } + + private static class ResultBroadcastReceiver extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + if (getResultCode() == Activity.RESULT_OK) { + return; + } + + Slog.w(TAG, "Request bug report because handler app seems to be not available."); + BugreportManager bugreportManager = context.getSystemService(BugreportManager.class); + bugreportManager.requestBugreport( + new BugreportParams(BugreportParams.BUGREPORT_MODE_INTERACTIVE), + /* shareTitle= */null, /* shareDescription= */ null); + } + } } diff --git a/services/core/java/com/android/server/media/BluetoothRouteProvider.java b/services/core/java/com/android/server/media/BluetoothRouteProvider.java index 265b9ad10561..28f838044907 100644 --- a/services/core/java/com/android/server/media/BluetoothRouteProvider.java +++ b/services/core/java/com/android/server/media/BluetoothRouteProvider.java @@ -85,7 +85,9 @@ class BluetoothRouteProvider { mListener = listener; mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); buildBluetoothRoutes(); + } + public void start() { mBluetoothAdapter.getProfileProxy(mContext, mProfileListener, BluetoothProfile.A2DP); mBluetoothAdapter.getProfileProxy(mContext, mProfileListener, BluetoothProfile.HEARING_AID); diff --git a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java index 5c97e90a3ba3..c7d14e0afe7b 100644 --- a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java +++ b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java @@ -103,25 +103,20 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider { publishProviderState(); boolean sessionInfoChanged; - synchronized (mLock) { - sessionInfoChanged = updateSessionInfosIfNeededLocked(); - } + sessionInfoChanged = updateSessionInfosIfNeeded(); if (sessionInfoChanged) { notifySessionInfoUpdated(); } }); - - mHandler.post(() -> notifyProviderState()); - - //TODO: clean up this - // This is required because it is not instantiated in the main thread and - // BluetoothRoutesUpdatedListener can be called before here - synchronized (mLock) { - updateSessionInfosIfNeededLocked(); - } + updateSessionInfosIfNeeded(); mContext.registerReceiver(new VolumeChangeReceiver(), new IntentFilter(AudioManager.VOLUME_CHANGED_ACTION)); + + mHandler.post(() -> { + mBtRouteProvider.start(); + notifyProviderState(); + }); } @Override @@ -220,35 +215,38 @@ class SystemMediaRoute2Provider extends MediaRoute2Provider { /** * Updates the mSessionInfo. Returns true if the session info is changed. */ - boolean updateSessionInfosIfNeededLocked() { - // Prevent to execute this method before mBtRouteProvider is created. - if (mBtRouteProvider == null) return false; - RoutingSessionInfo oldSessionInfo = mSessionInfos.isEmpty() ? null : mSessionInfos.get(0); - - RoutingSessionInfo.Builder builder = new RoutingSessionInfo.Builder( - SYSTEM_SESSION_ID, "" /* clientPackageName */) - .setSystemSession(true); - - MediaRoute2Info selectedRoute = mBtRouteProvider.getSelectedRoute(); - if (selectedRoute == null) { - selectedRoute = mDefaultRoute; - } else { - builder.addTransferableRoute(mDefaultRoute.getId()); - } - mSelectedRouteId = selectedRoute.getId(); - builder.addSelectedRoute(mSelectedRouteId); + boolean updateSessionInfosIfNeeded() { + synchronized (mLock) { + // Prevent to execute this method before mBtRouteProvider is created. + if (mBtRouteProvider == null) return false; + RoutingSessionInfo oldSessionInfo = mSessionInfos.isEmpty() ? null : mSessionInfos.get( + 0); + + RoutingSessionInfo.Builder builder = new RoutingSessionInfo.Builder( + SYSTEM_SESSION_ID, "" /* clientPackageName */) + .setSystemSession(true); + + MediaRoute2Info selectedRoute = mBtRouteProvider.getSelectedRoute(); + if (selectedRoute == null) { + selectedRoute = mDefaultRoute; + } else { + builder.addTransferableRoute(mDefaultRoute.getId()); + } + mSelectedRouteId = selectedRoute.getId(); + builder.addSelectedRoute(mSelectedRouteId); - for (MediaRoute2Info route : mBtRouteProvider.getTransferableRoutes()) { - builder.addTransferableRoute(route.getId()); - } + for (MediaRoute2Info route : mBtRouteProvider.getTransferableRoutes()) { + builder.addTransferableRoute(route.getId()); + } - RoutingSessionInfo newSessionInfo = builder.setProviderId(mUniqueId).build(); - if (Objects.equals(oldSessionInfo, newSessionInfo)) { - return false; - } else { - mSessionInfos.clear(); - mSessionInfos.add(newSessionInfo); - return true; + RoutingSessionInfo newSessionInfo = builder.setProviderId(mUniqueId).build(); + if (Objects.equals(oldSessionInfo, newSessionInfo)) { + return false; + } else { + mSessionInfos.clear(); + mSessionInfos.add(newSessionInfo); + return true; + } } } diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java b/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java index 563dcf7e1156..48f1ddb023fd 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java @@ -21,7 +21,7 @@ import static com.android.server.net.NetworkPolicyManagerService.isUidNetworking import android.annotation.NonNull; import android.net.Network; import android.net.NetworkTemplate; -import android.net.netstats.provider.AbstractNetworkStatsProvider; +import android.net.netstats.provider.NetworkStatsProvider; import android.telephony.SubscriptionPlan; import java.util.Set; @@ -130,8 +130,8 @@ public abstract class NetworkPolicyManagerInternal { Set<String> packageNames, int userId); /** - * Notifies that the specified {@link AbstractNetworkStatsProvider} has reached its quota - * which was set through {@link AbstractNetworkStatsProvider#setLimit(String, long)}. + * Notifies that the specified {@link NetworkStatsProvider} has reached its quota + * which was set through {@link NetworkStatsProvider#onSetLimit(String, long)}. * * @param tag the human readable identifier of the custom network stats provider. */ diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java index 0b1c91f4e2f5..caf29146e9db 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java @@ -75,7 +75,7 @@ import static android.net.NetworkTemplate.MATCH_MOBILE; import static android.net.NetworkTemplate.MATCH_WIFI; import static android.net.NetworkTemplate.buildTemplateMobileAll; import static android.net.TrafficStats.MB_IN_BYTES; -import static android.net.netstats.provider.AbstractNetworkStatsProvider.QUOTA_UNLIMITED; +import static android.net.netstats.provider.NetworkStatsProvider.QUOTA_UNLIMITED; import static android.os.Trace.TRACE_TAG_NETWORK; import static android.provider.Settings.Global.NETPOLICY_OVERRIDE_ENABLED; import static android.provider.Settings.Global.NETPOLICY_QUOTA_ENABLED; diff --git a/services/core/java/com/android/server/net/NetworkStatsFactory.java b/services/core/java/com/android/server/net/NetworkStatsFactory.java index 22b01bee6c6a..75ffe35674d1 100644 --- a/services/core/java/com/android/server/net/NetworkStatsFactory.java +++ b/services/core/java/com/android/server/net/NetworkStatsFactory.java @@ -229,7 +229,7 @@ public class NetworkStatsFactory { entry.txPackets += reader.nextLong(); } - stats.addEntry(entry); + stats.insertEntry(entry); reader.finishLine(); } } catch (NullPointerException|NumberFormatException e) { @@ -279,7 +279,7 @@ public class NetworkStatsFactory { entry.txBytes = reader.nextLong(); entry.txPackets = reader.nextLong(); - stats.addEntry(entry); + stats.insertEntry(entry); reader.finishLine(); } } catch (NullPointerException|NumberFormatException e) { @@ -439,7 +439,7 @@ public class NetworkStatsFactory { if ((limitIfaces == null || ArrayUtils.contains(limitIfaces, entry.iface)) && (limitUid == UID_ALL || limitUid == entry.uid) && (limitTag == TAG_ALL || limitTag == entry.tag)) { - stats.addEntry(entry); + stats.insertEntry(entry); } reader.finishLine(); diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 45047048cc45..10136b3b8b64 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -17,6 +17,7 @@ package com.android.server.net; import static android.Manifest.permission.ACCESS_NETWORK_STATE; +import static android.Manifest.permission.NETWORK_STATS_PROVIDER; import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY; import static android.Manifest.permission.UPDATE_DEVICE_STATS; import static android.content.Intent.ACTION_SHUTDOWN; @@ -102,7 +103,7 @@ import android.net.NetworkTemplate; import android.net.TrafficStats; import android.net.netstats.provider.INetworkStatsProvider; import android.net.netstats.provider.INetworkStatsProviderCallback; -import android.net.netstats.provider.NetworkStatsProviderCallback; +import android.net.netstats.provider.NetworkStatsProvider; import android.os.BestClock; import android.os.Binder; import android.os.DropBoxManager; @@ -557,7 +558,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } catch (RemoteException e) { // ignored; service lives in system_server } - invokeForAllStatsProviderCallbacks((cb) -> cb.mProvider.setAlert(mGlobalAlertBytes)); + invokeForAllStatsProviderCallbacks((cb) -> cb.mProvider.onSetAlert(mGlobalAlertBytes)); } @Override @@ -758,7 +759,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final NetworkStatsHistory.Entry entry = history.getValues(start, end, now, null); final NetworkStats stats = new NetworkStats(end - start, 1); - stats.addEntry(new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_ALL, TAG_NONE, + stats.insertEntry(new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, entry.rxBytes, entry.rxPackets, entry.txBytes, entry.txPackets, entry.operations)); return stats; @@ -1375,7 +1376,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { Trace.traceBegin(TRACE_TAG_NETWORK, "provider.requestStatsUpdate"); final int registeredCallbackCount = mStatsProviderCbList.getRegisteredCallbackCount(); mStatsProviderSem.drainPermits(); - invokeForAllStatsProviderCallbacks((cb) -> cb.mProvider.requestStatsUpdate(0 /* unused */)); + invokeForAllStatsProviderCallbacks( + (cb) -> cb.mProvider.onRequestStatsUpdate(0 /* unused */)); try { mStatsProviderSem.tryAcquire(registeredCallbackCount, MAX_STATS_PROVIDER_POLL_WAIT_TIME_MS, TimeUnit.MILLISECONDS); @@ -1550,7 +1552,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public void setStatsProviderLimitAsync(@NonNull String iface, long quota) { Slog.v(TAG, "setStatsProviderLimitAsync(" + iface + "," + quota + ")"); - invokeForAllStatsProviderCallbacks((cb) -> cb.mProvider.setLimit(iface, quota)); + invokeForAllStatsProviderCallbacks((cb) -> cb.mProvider.onSetLimit(iface, quota)); } } @@ -1819,16 +1821,15 @@ public class NetworkStatsService extends INetworkStatsService.Stub { * * @param tag a human readable identifier of the custom network stats provider. * @param provider the {@link INetworkStatsProvider} binder corresponding to the - * {@link android.net.netstats.provider.AbstractNetworkStatsProvider} to be - * registered. + * {@link NetworkStatsProvider} to be registered. * - * @return a binder interface of - * {@link android.net.netstats.provider.NetworkStatsProviderCallback}, which can be - * used to report events to the system. + * @return a {@link INetworkStatsProviderCallback} binder + * interface, which can be used to report events to the system. */ public @NonNull INetworkStatsProviderCallback registerNetworkStatsProvider( @NonNull String tag, @NonNull INetworkStatsProvider provider) { - mContext.enforceCallingOrSelfPermission(UPDATE_DEVICE_STATS, TAG); + enforceAnyPermissionOf(NETWORK_STATS_PROVIDER, + NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK); Objects.requireNonNull(provider, "provider is null"); Objects.requireNonNull(tag, "tag is null"); try { @@ -1929,7 +1930,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } @Override - public void onStatsUpdated(int token, @Nullable NetworkStats ifaceStats, + public void notifyStatsUpdated(int token, @Nullable NetworkStats ifaceStats, @Nullable NetworkStats uidStats) { // TODO: 1. Use token to map ifaces to correct NetworkIdentity. // 2. Store the difference and store it directly to the recorder. @@ -1941,12 +1942,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } @Override - public void onAlertReached() throws RemoteException { + public void notifyAlertReached() throws RemoteException { mAlertObserver.limitReached(LIMIT_GLOBAL_ALERT, null /* unused */); } @Override - public void onLimitReached() { + public void notifyLimitReached() { Log.d(TAG, mTag + ": onLimitReached"); LocalServices.getService(NetworkPolicyManagerInternal.class) .onStatsProviderLimitReached(mTag); diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java index f45e66e79c76..2853956d0a79 100644 --- a/services/core/java/com/android/server/notification/ZenModeHelper.java +++ b/services/core/java/com/android/server/notification/ZenModeHelper.java @@ -141,6 +141,7 @@ public class ZenModeHelper { updateDefaultAutomaticRuleNames(); mConfig = mDefaultConfig.copy(); mConfigs.put(UserHandle.USER_SYSTEM, mConfig); + mConsolidatedPolicy = mConfig.toNotificationPolicy(); mSettingsObserver = new SettingsObserver(mHandler); mSettingsObserver.observe(); @@ -821,9 +822,6 @@ public class ZenModeHelper { * @return a copy of the zen mode consolidated policy */ public Policy getConsolidatedNotificationPolicy() { - if (mConsolidatedPolicy == null) { - return null; - } return mConsolidatedPolicy.copy(); } diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java index 8031eaa62084..1b271a739777 100644 --- a/services/core/java/com/android/server/pm/LauncherAppsService.java +++ b/services/core/java/com/android/server/pm/LauncherAppsService.java @@ -819,6 +819,18 @@ public class LauncherAppsService extends SystemService { } @Override + public String getShortcutIconUri(String callingPackage, String packageName, + String shortcutId, int userId) { + ensureShortcutPermission(callingPackage); + if (!canAccessProfile(userId, "Cannot access shortcuts")) { + return null; + } + + return mShortcutServiceInternal.getShortcutIconUri(getCallingUserId(), callingPackage, + packageName, shortcutId, userId); + } + + @Override public boolean hasShortcutHostPermission(String callingPackage) { verifyCallingPackage(callingPackage); return mShortcutServiceInternal.hasShortcutHostPermission(getCallingUserId(), diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java index cdc37364ca79..2ff3d2a3a938 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerService.java +++ b/services/core/java/com/android/server/pm/PackageInstallerService.java @@ -47,7 +47,6 @@ import android.graphics.Bitmap; import android.net.Uri; import android.os.Binder; import android.os.Build; -import android.os.Bundle; import android.os.Environment; import android.os.Handler; import android.os.HandlerThread; @@ -1038,80 +1037,11 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements } } - static void sendPendingStreaming(Context context, IntentSender target, int sessionId, - Throwable cause) { - final Intent intent = new Intent(); - intent.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId); - intent.putExtra(PackageInstaller.EXTRA_STATUS, PackageInstaller.STATUS_PENDING_STREAMING); - if (cause != null && !TextUtils.isEmpty(cause.getMessage())) { - intent.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE, - "Staging Image Not Ready [" + cause.getMessage() + "]"); - } else { - intent.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE, "Staging Image Not Ready"); - } - try { - target.sendIntent(context, 0, intent, null, null); - } catch (SendIntentException ignored) { - } - } - - static void sendOnUserActionRequired(Context context, IntentSender target, int sessionId, - Intent intent) { - final Intent fillIn = new Intent(); - fillIn.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId); - fillIn.putExtra(PackageInstaller.EXTRA_STATUS, PackageInstaller.STATUS_PENDING_USER_ACTION); - fillIn.putExtra(Intent.EXTRA_INTENT, intent); - try { - target.sendIntent(context, 0, fillIn, null, null); - } catch (SendIntentException ignored) { - } - } - - static void sendOnPackageInstalled(Context context, IntentSender target, int sessionId, - boolean showNotification, int userId, String basePackageName, int returnCode, - String msg, Bundle extras) { - if (PackageManager.INSTALL_SUCCEEDED == returnCode && showNotification) { - boolean update = (extras != null) && extras.getBoolean(Intent.EXTRA_REPLACING); - Notification notification = buildSuccessNotification(context, - context.getResources() - .getString(update ? R.string.package_updated_device_owner : - R.string.package_installed_device_owner), - basePackageName, - userId); - if (notification != null) { - NotificationManager notificationManager = (NotificationManager) - context.getSystemService(Context.NOTIFICATION_SERVICE); - notificationManager.notify(basePackageName, - SystemMessage.NOTE_PACKAGE_STATE, - notification); - } - } - final Intent fillIn = new Intent(); - fillIn.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, basePackageName); - fillIn.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId); - fillIn.putExtra(PackageInstaller.EXTRA_STATUS, - PackageManager.installStatusToPublicStatus(returnCode)); - fillIn.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE, - PackageManager.installStatusToString(returnCode, msg)); - fillIn.putExtra(PackageInstaller.EXTRA_LEGACY_STATUS, returnCode); - if (extras != null) { - final String existing = extras.getString( - PackageManager.EXTRA_FAILURE_EXISTING_PACKAGE); - if (!TextUtils.isEmpty(existing)) { - fillIn.putExtra(PackageInstaller.EXTRA_OTHER_PACKAGE_NAME, existing); - } - } - try { - target.sendIntent(context, 0, fillIn, null, null); - } catch (SendIntentException ignored) { - } - } - /** * Build a notification for package installation / deletion by device owners that is shown if * the operation succeeds. */ - private static Notification buildSuccessNotification(Context context, String contentText, + static Notification buildSuccessNotification(Context context, String contentText, String basePackageName, int userId) { PackageInfo packageInfo = null; try { diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index 28d7c13d5b13..45a25a04e971 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -51,6 +51,8 @@ import static com.android.server.pm.PackageInstallerService.prepareStageDir; import android.Manifest; import android.annotation.NonNull; import android.annotation.Nullable; +import android.app.Notification; +import android.app.NotificationManager; import android.app.admin.DevicePolicyEventLogger; import android.app.admin.DevicePolicyManagerInternal; import android.content.ComponentName; @@ -119,9 +121,11 @@ import android.util.Slog; import android.util.SparseIntArray; import android.util.apk.ApkSignatureVerifier; +import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.content.NativeLibraryHelper; import com.android.internal.content.PackageHelper; +import com.android.internal.messages.nano.SystemMessageProto; import com.android.internal.os.SomeArgs; import com.android.internal.util.ArrayUtils; import com.android.internal.util.IndentingPrintWriter; @@ -440,8 +444,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { final int returnCode = args.argi1; args.recycle(); - PackageInstallerService.sendOnPackageInstalled(mContext, - statusReceiver, sessionId, + sendOnPackageInstalled(mContext, statusReceiver, sessionId, isInstallerDeviceOwnerOrAffiliatedProfileOwnerLocked(), userId, packageName, returnCode, message, extras); @@ -1636,8 +1639,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } } if (!success) { - PackageInstallerService.sendOnPackageInstalled(mContext, - mRemoteStatusReceiver, sessionId, + sendOnPackageInstalled(mContext, mRemoteStatusReceiver, sessionId, isInstallerDeviceOwnerOrAffiliatedProfileOwnerLocked(), userId, null, failure.error, failure.getLocalizedMessage(), null); return; @@ -1684,8 +1686,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { intent.setPackage(mPm.getPackageInstallerPackageName()); intent.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId); - PackageInstallerService.sendOnUserActionRequired(mContext, - mRemoteStatusReceiver, sessionId, intent); + sendOnUserActionRequired(mContext, mRemoteStatusReceiver, sessionId, intent); // Commit was keeping session marked as active until now; release // that extra refcount so session appears idle. @@ -2620,9 +2621,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } catch (RemoteException e) { // In case of streaming failure we don't want to fail or commit the session. // Just return from this method and allow caller to commit again. - PackageInstallerService.sendPendingStreaming(mContext, - mRemoteStatusReceiver, - sessionId, new StreamingException(e)); + sendPendingStreaming(mContext, mRemoteStatusReceiver, sessionId, + new StreamingException(e)); } } }; @@ -2924,6 +2924,75 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { pw.decreaseIndent(); } + private static void sendOnUserActionRequired(Context context, IntentSender target, + int sessionId, Intent intent) { + final Intent fillIn = new Intent(); + fillIn.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId); + fillIn.putExtra(PackageInstaller.EXTRA_STATUS, PackageInstaller.STATUS_PENDING_USER_ACTION); + fillIn.putExtra(Intent.EXTRA_INTENT, intent); + try { + target.sendIntent(context, 0, fillIn, null, null); + } catch (IntentSender.SendIntentException ignored) { + } + } + + private static void sendOnPackageInstalled(Context context, IntentSender target, int sessionId, + boolean showNotification, int userId, String basePackageName, int returnCode, + String msg, Bundle extras) { + if (PackageManager.INSTALL_SUCCEEDED == returnCode && showNotification) { + boolean update = (extras != null) && extras.getBoolean(Intent.EXTRA_REPLACING); + Notification notification = PackageInstallerService.buildSuccessNotification(context, + context.getResources() + .getString(update ? R.string.package_updated_device_owner : + R.string.package_installed_device_owner), + basePackageName, + userId); + if (notification != null) { + NotificationManager notificationManager = (NotificationManager) + context.getSystemService(Context.NOTIFICATION_SERVICE); + notificationManager.notify(basePackageName, + SystemMessageProto.SystemMessage.NOTE_PACKAGE_STATE, + notification); + } + } + final Intent fillIn = new Intent(); + fillIn.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, basePackageName); + fillIn.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId); + fillIn.putExtra(PackageInstaller.EXTRA_STATUS, + PackageManager.installStatusToPublicStatus(returnCode)); + fillIn.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE, + PackageManager.installStatusToString(returnCode, msg)); + fillIn.putExtra(PackageInstaller.EXTRA_LEGACY_STATUS, returnCode); + if (extras != null) { + final String existing = extras.getString( + PackageManager.EXTRA_FAILURE_EXISTING_PACKAGE); + if (!TextUtils.isEmpty(existing)) { + fillIn.putExtra(PackageInstaller.EXTRA_OTHER_PACKAGE_NAME, existing); + } + } + try { + target.sendIntent(context, 0, fillIn, null, null); + } catch (IntentSender.SendIntentException ignored) { + } + } + + private static void sendPendingStreaming(Context context, IntentSender target, int sessionId, + Throwable cause) { + final Intent intent = new Intent(); + intent.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId); + intent.putExtra(PackageInstaller.EXTRA_STATUS, PackageInstaller.STATUS_PENDING_STREAMING); + if (cause != null && !TextUtils.isEmpty(cause.getMessage())) { + intent.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE, + "Staging Image Not Ready [" + cause.getMessage() + "]"); + } else { + intent.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE, "Staging Image Not Ready"); + } + try { + target.sendIntent(context, 0, intent, null, null); + } catch (IntentSender.SendIntentException ignored) { + } + } + private static void writeGrantedRuntimePermissionsLocked(XmlSerializer out, String[] grantedRuntimePermissions) throws IOException { if (grantedRuntimePermissions != null) { diff --git a/services/core/java/com/android/server/pm/ShortcutBitmapSaver.java b/services/core/java/com/android/server/pm/ShortcutBitmapSaver.java index dc534a702946..1c5f0a7fc0f3 100644 --- a/services/core/java/com/android/server/pm/ShortcutBitmapSaver.java +++ b/services/core/java/com/android/server/pm/ShortcutBitmapSaver.java @@ -28,7 +28,6 @@ import android.util.Log; import android.util.Slog; import com.android.internal.annotations.GuardedBy; -import com.android.internal.util.Preconditions; import com.android.server.pm.ShortcutService.FileOutputStreamWithPath; import libcore.io.IoUtils; @@ -150,9 +149,10 @@ public class ShortcutBitmapSaver { shortcut.setIconResourceId(0); shortcut.setIconResName(null); shortcut.setBitmapPath(null); + shortcut.setIconUri(null); shortcut.clearFlags(ShortcutInfo.FLAG_HAS_ICON_FILE | ShortcutInfo.FLAG_ADAPTIVE_BITMAP | ShortcutInfo.FLAG_HAS_ICON_RES | - ShortcutInfo.FLAG_ICON_FILE_PENDING_SAVE); + ShortcutInfo.FLAG_ICON_FILE_PENDING_SAVE | ShortcutInfo.FLAG_HAS_ICON_URI); } public void saveBitmapLocked(ShortcutInfo shortcut, diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java index c8df5c731845..1fc0a38e1ed3 100644 --- a/services/core/java/com/android/server/pm/ShortcutPackage.java +++ b/services/core/java/com/android/server/pm/ShortcutPackage.java @@ -102,6 +102,7 @@ class ShortcutPackage extends ShortcutPackageItem { private static final String ATTR_ICON_RES_ID = "icon-res"; private static final String ATTR_ICON_RES_NAME = "icon-resname"; private static final String ATTR_BITMAP_PATH = "bitmap-path"; + private static final String ATTR_ICON_URI = "icon-uri"; private static final String ATTR_LOCUS_ID = "locus-id"; private static final String ATTR_PERSON_NAME = "name"; @@ -1628,7 +1629,8 @@ class ShortcutPackage extends ShortcutPackageItem { int flags = si.getFlags() & ~(ShortcutInfo.FLAG_HAS_ICON_FILE | ShortcutInfo.FLAG_HAS_ICON_RES | ShortcutInfo.FLAG_ICON_FILE_PENDING_SAVE - | ShortcutInfo.FLAG_DYNAMIC); + | ShortcutInfo.FLAG_DYNAMIC + | ShortcutInfo.FLAG_HAS_ICON_URI | ShortcutInfo.FLAG_ADAPTIVE_BITMAP); ShortcutService.writeAttr(out, ATTR_FLAGS, flags); // Set the publisher version code at every backup. @@ -1646,6 +1648,7 @@ class ShortcutPackage extends ShortcutPackageItem { ShortcutService.writeAttr(out, ATTR_ICON_RES_ID, si.getIconResourceId()); ShortcutService.writeAttr(out, ATTR_ICON_RES_NAME, si.getIconResName()); ShortcutService.writeAttr(out, ATTR_BITMAP_PATH, si.getBitmapPath()); + ShortcutService.writeAttr(out, ATTR_ICON_URI, si.getIconUri()); } if (shouldBackupDetails) { @@ -1764,6 +1767,7 @@ class ShortcutPackage extends ShortcutPackageItem { int iconResId; String iconResName; String bitmapPath; + String iconUri; final String locusIdString; int backupVersionCode; ArraySet<String> categories = null; @@ -1791,6 +1795,7 @@ class ShortcutPackage extends ShortcutPackageItem { iconResId = (int) ShortcutService.parseLongAttribute(parser, ATTR_ICON_RES_ID); iconResName = ShortcutService.parseStringAttribute(parser, ATTR_ICON_RES_NAME); bitmapPath = ShortcutService.parseStringAttribute(parser, ATTR_BITMAP_PATH); + iconUri = ShortcutService.parseStringAttribute(parser, ATTR_ICON_URI); locusIdString = ShortcutService.parseStringAttribute(parser, ATTR_LOCUS_ID); final int outerDepth = parser.getDepth(); @@ -1866,8 +1871,8 @@ class ShortcutPackage extends ShortcutPackageItem { categories, intents.toArray(new Intent[intents.size()]), rank, extras, lastChangedTimestamp, flags, - iconResId, iconResName, bitmapPath, disabledReason, - persons.toArray(new Person[persons.size()]), locusId); + iconResId, iconResName, bitmapPath, iconUri, + disabledReason, persons.toArray(new Person[persons.size()]), locusId); } private static Intent parseIntent(XmlPullParser parser) @@ -1991,16 +1996,26 @@ class ShortcutPackage extends ShortcutPackageItem { Log.e(TAG_VERIFY, "Package " + getPackageName() + ": shortcut " + si.getId() + " still has an icon"); } - if (si.hasAdaptiveBitmap() && !si.hasIconFile()) { + if (si.hasAdaptiveBitmap() && !(si.hasIconFile() || si.hasIconUri())) { failed = true; Log.e(TAG_VERIFY, "Package " + getPackageName() + ": shortcut " + si.getId() - + " has adaptive bitmap but was not saved to a file."); + + " has adaptive bitmap but was not saved to a file nor has icon uri."); } if (si.hasIconFile() && si.hasIconResource()) { failed = true; Log.e(TAG_VERIFY, "Package " + getPackageName() + ": shortcut " + si.getId() + " has both resource and bitmap icons"); } + if (si.hasIconFile() && si.hasIconUri()) { + failed = true; + Log.e(TAG_VERIFY, "Package " + getPackageName() + ": shortcut " + si.getId() + + " has both url and bitmap icons"); + } + if (si.hasIconUri() && si.hasIconResource()) { + failed = true; + Log.e(TAG_VERIFY, "Package " + getPackageName() + ": shortcut " + si.getId() + + " has both url and resource icons"); + } if (si.isEnabled() != (si.getDisabledReason() == ShortcutInfo.DISABLED_REASON_NOT_DISABLED)) { failed = true; diff --git a/services/core/java/com/android/server/pm/ShortcutParser.java b/services/core/java/com/android/server/pm/ShortcutParser.java index f9c0db0e9a1d..d3aace19672a 100644 --- a/services/core/java/com/android/server/pm/ShortcutParser.java +++ b/services/core/java/com/android/server/pm/ShortcutParser.java @@ -449,6 +449,7 @@ public class ShortcutParser { iconResId, null, // icon res name null, // bitmap path + null, // icon Url disabledReason, null /* persons */, null /* locusId */); diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java index 66f3574d83a0..8768ab0a683b 100644 --- a/services/core/java/com/android/server/pm/ShortcutService.java +++ b/services/core/java/com/android/server/pm/ShortcutService.java @@ -24,6 +24,8 @@ import android.app.ActivityManager; import android.app.ActivityManagerInternal; import android.app.AppGlobals; import android.app.IUidObserver; +import android.app.IUriGrantsManager; +import android.app.UriGrantsManager; import android.app.usage.UsageStatsManagerInternal; import android.appwidget.AppWidgetProviderInfo; import android.content.BroadcastReceiver; @@ -65,6 +67,7 @@ import android.os.Bundle; import android.os.Environment; import android.os.FileUtils; import android.os.Handler; +import android.os.IBinder; import android.os.LocaleList; import android.os.Looper; import android.os.ParcelFileDescriptor; @@ -106,6 +109,7 @@ import com.android.internal.util.StatLogger; import com.android.server.LocalServices; import com.android.server.SystemService; import com.android.server.pm.ShortcutUser.PackageWithUser; +import com.android.server.uri.UriGrantsManagerInternal; import libcore.io.IoUtils; @@ -327,6 +331,9 @@ public class ShortcutService extends IShortcutService.Stub { private final UserManagerInternal mUserManagerInternal; private final UsageStatsManagerInternal mUsageStatsManagerInternal; private final ActivityManagerInternal mActivityManagerInternal; + private final IUriGrantsManager mUriGrantsManager; + private final UriGrantsManagerInternal mUriGrantsManagerInternal; + private final IBinder mUriPermissionOwner; private final ShortcutRequestPinProcessor mShortcutRequestPinProcessor; private final ShortcutBitmapSaver mShortcutBitmapSaver; @@ -449,6 +456,11 @@ public class ShortcutService extends IShortcutService.Stub { mActivityManagerInternal = Objects.requireNonNull( LocalServices.getService(ActivityManagerInternal.class)); + mUriGrantsManager = UriGrantsManager.getService(); + mUriGrantsManagerInternal = Objects.requireNonNull( + LocalServices.getService(UriGrantsManagerInternal.class)); + mUriPermissionOwner = mUriGrantsManagerInternal.newUriPermissionOwner(TAG); + mShortcutRequestPinProcessor = new ShortcutRequestPinProcessor(this, mLock); mShortcutBitmapSaver = new ShortcutBitmapSaver(this); mShortcutDumpFiles = new ShortcutDumpFiles(this); @@ -1414,7 +1426,7 @@ public class ShortcutService extends IShortcutService.Stub { } void saveIconAndFixUpShortcutLocked(ShortcutInfo shortcut) { - if (shortcut.hasIconFile() || shortcut.hasIconResource()) { + if (shortcut.hasIconFile() || shortcut.hasIconResource() || shortcut.hasIconUri()) { return; } @@ -1438,6 +1450,15 @@ public class ShortcutService extends IShortcutService.Stub { shortcut.addFlags(ShortcutInfo.FLAG_HAS_ICON_RES); return; } + case Icon.TYPE_URI: + shortcut.setIconUri(icon.getUriString()); + shortcut.addFlags(ShortcutInfo.FLAG_HAS_ICON_URI); + return; + case Icon.TYPE_URI_ADAPTIVE_BITMAP: + shortcut.setIconUri(icon.getUriString()); + shortcut.addFlags(ShortcutInfo.FLAG_HAS_ICON_URI + | ShortcutInfo.FLAG_ADAPTIVE_BITMAP); + return; case Icon.TYPE_BITMAP: bitmap = icon.getBitmap(); // Don't recycle in this case. break; @@ -3129,6 +3150,59 @@ public class ShortcutService extends IShortcutService.Stub { } @Override + public String getShortcutIconUri(int launcherUserId, @NonNull String launcherPackage, + @NonNull String packageName, @NonNull String shortcutId, int userId) { + Objects.requireNonNull(launcherPackage, "launcherPackage"); + Objects.requireNonNull(packageName, "packageName"); + Objects.requireNonNull(shortcutId, "shortcutId"); + + synchronized (mLock) { + throwIfUserLockedL(userId); + throwIfUserLockedL(launcherUserId); + + getLauncherShortcutsLocked(launcherPackage, userId, launcherUserId) + .attemptToRestoreIfNeededAndSave(); + + final ShortcutPackage p = getUserShortcutsLocked(userId) + .getPackageShortcutsIfExists(packageName); + if (p == null) { + return null; + } + + final ShortcutInfo shortcutInfo = p.findShortcutById(shortcutId); + if (shortcutInfo == null || !shortcutInfo.hasIconUri()) { + return null; + } + String uri = shortcutInfo.getIconUri(); + if (uri == null) { + Slog.w(TAG, "null uri detected in getShortcutIconUri()"); + return null; + } + + final long token = Binder.clearCallingIdentity(); + try { + int packageUid = mPackageManagerInternal.getPackageUidInternal(packageName, + PackageManager.MATCH_DIRECT_BOOT_AUTO, userId); + // Grant read uri permission to the caller on behalf of the shortcut owner. All + // granted permissions are revoked when the default launcher changes, or when + // device is rebooted. + // b/151572645 is tracking a bug where Uri permissions are persisted across + // reboots, even when Intent#FLAG_GRANT_PERSISTABLE_URI_PERMISSION is not used. + mUriGrantsManager.grantUriPermissionFromOwner(mUriPermissionOwner, packageUid, + launcherPackage, Uri.parse(uri), Intent.FLAG_GRANT_READ_URI_PERMISSION, + userId, launcherUserId); + } catch (Exception e) { + Slog.e(TAG, "Failed to grant uri access to " + launcherPackage + " for " + uri, + e); + uri = null; + } finally { + Binder.restoreCallingIdentity(token); + } + return uri; + } + } + + @Override public boolean hasShortcutHostPermission(int launcherUserId, @NonNull String callingPackage, int callingPid, int callingUid) { return ShortcutService.this.hasShortcutHostPermission(callingPackage, launcherUserId, @@ -3241,7 +3315,14 @@ public class ShortcutService extends IShortcutService.Stub { user.clearLauncher(); } if (Intent.ACTION_PREFERRED_ACTIVITY_CHANGED.equals(action)) { - // Nothing farther to do. + final ShortcutUser user = getUserShortcutsLocked(userId); + final ComponentName lastLauncher = user.getLastKnownLauncher(); + final ComponentName currentLauncher = getDefaultLauncher(userId); + if (currentLauncher == null || !currentLauncher.equals(lastLauncher)) { + // Default launcher is removed or changed, revoke all URI permissions. + mUriGrantsManagerInternal.revokeUriPermissionFromOwner(mUriPermissionOwner, + null, ~0, 0); + } return; } diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index 1c2fcc15b399..8280a614fc54 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -455,11 +455,13 @@ public class UserManagerService extends IUserManager.Stub { @Override public void onFinished(int id, Bundle extras) { - try { - mContext.startIntentSender(mTarget, null, 0, 0, 0); - } catch (IntentSender.SendIntentException e) { - Slog.e(LOG_TAG, "Failed to start the target in the callback", e); - } + mHandler.post(() -> { + try { + mContext.startIntentSender(mTarget, null, 0, 0, 0); + } catch (IntentSender.SendIntentException e) { + Slog.e(LOG_TAG, "Failed to start the target in the callback", e); + } + }); } } diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java index 294deba459fe..3257b63843ec 100644 --- a/services/core/java/com/android/server/power/PowerManagerService.java +++ b/services/core/java/com/android/server/power/PowerManagerService.java @@ -18,6 +18,8 @@ package com.android.server.power; import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_CRITICAL; import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_DEFAULT; +import static android.os.PowerManagerInternal.MODE_DEVICE_IDLE; +import static android.os.PowerManagerInternal.MODE_DISPLAY_INACTIVE; import static android.os.PowerManagerInternal.WAKEFULNESS_ASLEEP; import static android.os.PowerManagerInternal.WAKEFULNESS_AWAKE; import static android.os.PowerManagerInternal.WAKEFULNESS_DOZING; @@ -42,8 +44,6 @@ import android.hardware.SystemSensorManager; import android.hardware.display.AmbientDisplayConfiguration; import android.hardware.display.DisplayManagerInternal; import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest; -import android.hardware.power.Boost; -import android.hardware.power.Mode; import android.hardware.power.V1_0.PowerHint; import android.net.Uri; import android.os.BatteryManager; @@ -2975,6 +2975,8 @@ public final class PowerManagerService extends SystemService synchronized (mLock) { if (mDisplayState != state) { mDisplayState = state; + setPowerModeInternal(MODE_DISPLAY_INACTIVE, + !Display.isActiveState(state)); if (state == Display.STATE_OFF) { if (!mDecoupleHalInteractiveModeFromDisplayConfig) { setHalInteractiveModeLocked(false); @@ -3297,6 +3299,7 @@ public final class PowerManagerService extends SystemService } mDeviceIdleMode = enabled; updateWakeLockDisabledStatesLocked(); + setPowerModeInternal(MODE_DEVICE_IDLE, mDeviceIdleMode || mLightDeviceIdleMode); } if (enabled) { EventLogTags.writeDeviceIdleOnPhase("power"); @@ -3310,6 +3313,7 @@ public final class PowerManagerService extends SystemService synchronized (mLock) { if (mLightDeviceIdleMode != enabled) { mLightDeviceIdleMode = enabled; + setPowerModeInternal(MODE_DEVICE_IDLE, mDeviceIdleMode || mLightDeviceIdleMode); return true; } return false; diff --git a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java index 74a6383bc01c..0d16fccc81fd 100644 --- a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java +++ b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java @@ -234,7 +234,7 @@ public final class TextClassificationManagerService extends ITextClassifierServi handleRequest( event.getSystemTextClassifierMetadata(), - /* verifyCallingPackage= */ false, + /* verifyCallingPackage= */ true, /* attemptToBind= */ false, service -> service.onSelectionEvent(sessionId, event), "onSelectionEvent", @@ -253,7 +253,7 @@ public final class TextClassificationManagerService extends ITextClassifierServi handleRequest( systemTcMetadata, - /* verifyCallingPackage= */ false, + /* verifyCallingPackage= */ true, /* attemptToBind= */ false, service -> service.onTextClassifierEvent(sessionId, event), "onTextClassifierEvent", diff --git a/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java b/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java index bd63b2daad83..25585b3ae794 100644 --- a/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java +++ b/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java @@ -16,7 +16,6 @@ package com.android.server.tv.tunerresourcemanager; -import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; @@ -41,8 +40,6 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.server.SystemService; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; import java.util.HashMap; import java.util.HashSet; import java.util.Map; @@ -79,25 +76,6 @@ public class TunerResourceManagerService extends SystemService { // Used to synchronize the access to the service. private final Object mLock = new Object(); - /** - * Tuner resource type to help generate resource handle - */ - @IntDef({ - TUNER_RESOURCE_TYPE_FRONTEND, - TUNER_RESOURCE_TYPE_DEMUX, - TUNER_RESOURCE_TYPE_DESCRAMBLER, - TUNER_RESOURCE_TYPE_LNB, - TUNER_RESOURCE_TYPE_CAS_SESSION, - }) - @Retention(RetentionPolicy.SOURCE) - public @interface TunerResourceType {} - - public static final int TUNER_RESOURCE_TYPE_FRONTEND = 0; - public static final int TUNER_RESOURCE_TYPE_DEMUX = 1; - public static final int TUNER_RESOURCE_TYPE_DESCRAMBLER = 2; - public static final int TUNER_RESOURCE_TYPE_LNB = 3; - public static final int TUNER_RESOURCE_TYPE_CAS_SESSION = 4; - public TunerResourceManagerService(@Nullable Context context) { super(context); } @@ -465,7 +443,7 @@ public class TunerResourceManagerService extends SystemService { // Grant frontend when there is unused resource. if (grantingFrontendId > -1) { frontendHandle[0] = generateResourceHandle( - TUNER_RESOURCE_TYPE_FRONTEND, grantingFrontendId); + TunerResourceManager.TUNER_RESOURCE_TYPE_FRONTEND, grantingFrontendId); updateFrontendClientMappingOnNewGrant(grantingFrontendId, request.getClientId()); return true; } @@ -474,7 +452,7 @@ public class TunerResourceManagerService extends SystemService { // request client has higher priority. if (inUseLowestPriorityFrId > -1 && (requestClient.getPriority() > currentLowestPriority)) { frontendHandle[0] = generateResourceHandle( - TUNER_RESOURCE_TYPE_FRONTEND, inUseLowestPriorityFrId); + TunerResourceManager.TUNER_RESOURCE_TYPE_FRONTEND, inUseLowestPriorityFrId); reclaimFrontendResource(getFrontendResource( inUseLowestPriorityFrId).getOwnerClientId()); updateFrontendClientMappingOnNewGrant(inUseLowestPriorityFrId, request.getClientId()); @@ -489,7 +467,7 @@ public class TunerResourceManagerService extends SystemService { if (DEBUG) { Slog.d(TAG, "requestDemux(request=" + request + ")"); } - demuxHandle[0] = generateResourceHandle(TUNER_RESOURCE_TYPE_DEMUX, 0); + demuxHandle[0] = generateResourceHandle(TunerResourceManager.TUNER_RESOURCE_TYPE_DEMUX, 0); return true; } @@ -498,7 +476,8 @@ public class TunerResourceManagerService extends SystemService { if (DEBUG) { Slog.d(TAG, "requestDescrambler(request=" + request + ")"); } - descramblerHandle[0] = generateResourceHandle(TUNER_RESOURCE_TYPE_DESCRAMBLER, 0); + descramblerHandle[0] = + generateResourceHandle(TunerResourceManager.TUNER_RESOURCE_TYPE_DESCRAMBLER, 0); return true; } @@ -664,7 +643,8 @@ public class TunerResourceManagerService extends SystemService { return mClientProfiles.keySet().contains(clientId); } - private int generateResourceHandle(@TunerResourceType int resourceType, int resourceId) { + private int generateResourceHandle( + @TunerResourceManager.TunerResourceType int resourceType, int resourceId) { return (resourceType & 0x000000ff) << 24 | (resourceId << 16) | (mResourceRequestCount++ & 0xffff); diff --git a/services/core/java/com/android/server/wm/SurfaceAnimator.java b/services/core/java/com/android/server/wm/SurfaceAnimator.java index 19f8ca912449..aa817fd38b25 100644 --- a/services/core/java/com/android/server/wm/SurfaceAnimator.java +++ b/services/core/java/com/android/server/wm/SurfaceAnimator.java @@ -36,6 +36,7 @@ import com.android.internal.annotations.VisibleForTesting; import java.io.PrintWriter; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.util.function.Supplier; /** * A class that can run animations on objects that have a set of child surfaces. We do this by @@ -145,7 +146,7 @@ class SurfaceAnimator { if (mLeash == null) { mLeash = createAnimationLeash(mAnimatable, surface, t, type, mAnimatable.getSurfaceWidth(), mAnimatable.getSurfaceHeight(), 0 /* x */, - 0 /* y */, hidden); + 0 /* y */, hidden, mService.mTransactionFactory); mAnimatable.onAnimationLeashCreated(t, mLeash); } mAnimatable.onLeashAnimationStarting(t, mLeash); @@ -374,13 +375,21 @@ class SurfaceAnimator { static SurfaceControl createAnimationLeash(Animatable animatable, SurfaceControl surface, Transaction t, @AnimationType int type, int width, int height, int x, int y, - boolean hidden) { + boolean hidden, Supplier<Transaction> transactionFactory) { if (DEBUG_ANIM) Slog.i(TAG, "Reparenting to leash"); final SurfaceControl.Builder builder = animatable.makeAnimationLeash() .setParent(animatable.getAnimationLeashParent()) - .setHidden(hidden) .setName(surface + " - animation-leash"); final SurfaceControl leash = builder.build(); + if (!hidden) { + // TODO(b/151665759) Defer reparent calls + // We want the leash to be visible immediately but we want to set the effects on + // the layer. Since the transaction used in this function may be deferred, we apply + // another transaction immediately with the correct visibility and effects. + // If this doesn't work, you will can see the 2/3 button nav bar flicker during + // seamless rotation. + transactionFactory.get().unsetColor(leash).show(leash).apply(); + } t.setWindowCrop(leash, width, height); t.setPosition(leash, x, y); t.show(leash); diff --git a/services/core/java/com/android/server/wm/SurfaceFreezer.java b/services/core/java/com/android/server/wm/SurfaceFreezer.java index a696dafa7dd3..8ab5043dc5d9 100644 --- a/services/core/java/com/android/server/wm/SurfaceFreezer.java +++ b/services/core/java/com/android/server/wm/SurfaceFreezer.java @@ -75,7 +75,8 @@ class SurfaceFreezer { mLeash = SurfaceAnimator.createAnimationLeash(mAnimatable, mAnimatable.getSurfaceControl(), t, ANIMATION_TYPE_SCREEN_ROTATION, startBounds.width(), startBounds.height(), - startBounds.left, startBounds.top, false /* hidden */); + startBounds.left, startBounds.top, false /* hidden */, + mWmService.mTransactionFactory); mAnimatable.onAnimationLeashCreated(t, mLeash); SurfaceControl freezeTarget = mAnimatable.getFreezeSnapshotTarget(); diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 1a778079668d..7400d17b21ce 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -186,7 +186,6 @@ import android.os.SystemService; import android.os.Trace; import android.os.UserHandle; import android.os.WorkSource; -import android.provider.DeviceConfig; import android.provider.Settings; import android.service.vr.IVrManager; import android.service.vr.IVrStateCallbacks; @@ -1162,9 +1161,7 @@ public class WindowManagerService extends IWindowManager.Stub mAnimator = new WindowAnimator(this); mRoot = new RootWindowContainer(this); - mUseBLAST = DeviceConfig.getBoolean( - DeviceConfig.NAMESPACE_WINDOW_MANAGER_NATIVE_BOOT, - WM_USE_BLAST_ADAPTER_FLAG, false); + mUseBLAST = true; mWindowPlacerLocked = new WindowSurfacePlacer(this); mTaskSnapshotController = new TaskSnapshotController(this); diff --git a/services/incremental/IncrementalService.cpp b/services/incremental/IncrementalService.cpp index 727593664895..4da0091af0db 100644 --- a/services/incremental/IncrementalService.cpp +++ b/services/incremental/IncrementalService.cpp @@ -1090,7 +1090,9 @@ bool IncrementalService::prepareDataLoader(IncrementalService::IncFsMount& ifs, base::unique_fd(::dup(ifs.control.pendingReads))); fsControlParcel.incremental->log.reset(base::unique_fd(::dup(ifs.control.logs))); sp<IncrementalDataLoaderListener> listener = - new IncrementalDataLoaderListener(*this, *externalListener); + new IncrementalDataLoaderListener(*this, + externalListener ? *externalListener + : DataLoaderStatusListener()); bool created = false; auto status = mDataLoaderManager->initializeDataLoader(ifs.mountId, *dlp, fsControlParcel, listener, &created); @@ -1230,8 +1232,8 @@ binder::Status IncrementalService::IncrementalDataLoaderListener::onStatusChange std::unique_lock l(incrementalService.mLock); const auto& ifs = incrementalService.getIfsLocked(mountId); if (!ifs) { - LOG(WARNING) << "Received data loader status " << int(newStatus) << " for unknown mount " - << mountId; + LOG(WARNING) << "Received data loader status " << int(newStatus) + << " for unknown mount " << mountId; return binder::Status::ok(); } ifs->dataLoaderStatus = newStatus; diff --git a/services/robotests/backup/src/com/android/server/backup/testing/BackupManagerServiceTestUtils.java b/services/robotests/backup/src/com/android/server/backup/testing/BackupManagerServiceTestUtils.java index 84421ef178c9..77b5b61b8f01 100644 --- a/services/robotests/backup/src/com/android/server/backup/testing/BackupManagerServiceTestUtils.java +++ b/services/robotests/backup/src/com/android/server/backup/testing/BackupManagerServiceTestUtils.java @@ -166,7 +166,7 @@ public class BackupManagerServiceTestUtils { PowerManager powerManager = (PowerManager) application.getSystemService(Context.POWER_SERVICE); return new UserBackupManagerService.BackupWakeLock( - powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*backup*")); + powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*backup*"), 0); } /** diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java index 7e3cfc8fb2a5..128177b073b0 100644 --- a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java @@ -1084,7 +1084,7 @@ public class NetworkPolicyManagerServiceTest { // pretend that 512 bytes total have happened stats = new NetworkStats(getElapsedRealtime(), 1) - .addIfaceValues(TEST_IFACE, 256L, 2L, 256L, 2L); + .insertEntry(TEST_IFACE, 256L, 2L, 256L, 2L); when(mStatsService.getNetworkTotalBytes(sTemplateWifi, CYCLE_START, CYCLE_END)) .thenReturn(stats.getTotalBytes()); @@ -1276,11 +1276,11 @@ public class NetworkPolicyManagerServiceTest { history.recordData(start, end, new NetworkStats.Entry(DataUnit.MEGABYTES.toBytes(1440), 0L, 0L, 0L, 0)); stats.clear(); - stats.addEntry(IFACE_ALL, UID_A, SET_ALL, TAG_ALL, + stats.insertEntry(IFACE_ALL, UID_A, SET_ALL, TAG_ALL, DataUnit.MEGABYTES.toBytes(480), 0, 0, 0, 0); - stats.addEntry(IFACE_ALL, UID_B, SET_ALL, TAG_ALL, + stats.insertEntry(IFACE_ALL, UID_B, SET_ALL, TAG_ALL, DataUnit.MEGABYTES.toBytes(480), 0, 0, 0, 0); - stats.addEntry(IFACE_ALL, UID_C, SET_ALL, TAG_ALL, + stats.insertEntry(IFACE_ALL, UID_C, SET_ALL, TAG_ALL, DataUnit.MEGABYTES.toBytes(480), 0, 0, 0, 0); reset(mNotifManager); @@ -1304,9 +1304,9 @@ public class NetworkPolicyManagerServiceTest { history.recordData(start, end, new NetworkStats.Entry(DataUnit.MEGABYTES.toBytes(1440), 0L, 0L, 0L, 0)); stats.clear(); - stats.addEntry(IFACE_ALL, UID_A, SET_ALL, TAG_ALL, + stats.insertEntry(IFACE_ALL, UID_A, SET_ALL, TAG_ALL, DataUnit.MEGABYTES.toBytes(960), 0, 0, 0, 0); - stats.addEntry(IFACE_ALL, UID_B, SET_ALL, TAG_ALL, + stats.insertEntry(IFACE_ALL, UID_B, SET_ALL, TAG_ALL, DataUnit.MEGABYTES.toBytes(480), 0, 0, 0, 0); reset(mNotifManager); @@ -1338,7 +1338,7 @@ public class NetworkPolicyManagerServiceTest { // bring up wifi network with metered policy state = new NetworkState[] { buildWifi() }; stats = new NetworkStats(getElapsedRealtime(), 1) - .addIfaceValues(TEST_IFACE, 0L, 0L, 0L, 0L); + .insertEntry(TEST_IFACE, 0L, 0L, 0L, 0L); { when(mConnManager.getAllNetworkState()).thenReturn(state); @@ -1769,7 +1769,7 @@ public class NetworkPolicyManagerServiceTest { final int CYCLE_DAY = 15; final NetworkStats stats = new NetworkStats(0L, 1); - stats.addEntry(TEST_IFACE, UID_A, SET_ALL, TAG_NONE, + stats.insertEntry(TEST_IFACE, UID_A, SET_ALL, TAG_NONE, 2999, 1, 2000, 1, 0); when(mStatsService.getNetworkTotalBytes(any(), anyLong(), anyLong())) .thenReturn(stats.getTotalBytes()); @@ -1793,7 +1793,7 @@ public class NetworkPolicyManagerServiceTest { reset(mStatsService); // Increase the usage. - stats.addEntry(TEST_IFACE, UID_A, SET_ALL, TAG_NONE, + stats.insertEntry(TEST_IFACE, UID_A, SET_ALL, TAG_NONE, 1000, 1, 999, 1, 0); when(mStatsService.getNetworkTotalBytes(any(), anyLong(), anyLong())) .thenReturn(stats.getTotalBytes()); diff --git a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java index 6c769485f6ad..6a882985d305 100644 --- a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java @@ -94,6 +94,8 @@ import com.android.server.LocalServices; import com.android.server.SystemService; import com.android.server.pm.LauncherAppsService.LauncherAppsImpl; import com.android.server.pm.ShortcutUser.PackageWithUser; +import com.android.server.uri.UriGrantsManagerInternal; +import com.android.server.uri.UriPermissionOwner; import com.android.server.wm.ActivityTaskManagerInternal; import org.junit.Assert; @@ -630,6 +632,9 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { protected UsageStatsManagerInternal mMockUsageStatsManagerInternal; protected ActivityManagerInternal mMockActivityManagerInternal; protected ActivityTaskManagerInternal mMockActivityTaskManagerInternal; + protected UriGrantsManagerInternal mMockUriGrantsManagerInternal; + + protected UriPermissionOwner mUriPermissionOwner; protected static final String CALLING_PACKAGE_1 = "com.android.test.1"; protected static final int CALLING_UID_1 = 10001; @@ -771,6 +776,7 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { mMockUsageStatsManagerInternal = mock(UsageStatsManagerInternal.class); mMockActivityManagerInternal = mock(ActivityManagerInternal.class); mMockActivityTaskManagerInternal = mock(ActivityTaskManagerInternal.class); + mMockUriGrantsManagerInternal = mock(UriGrantsManagerInternal.class); LocalServices.removeServiceForTest(PackageManagerInternal.class); LocalServices.addService(PackageManagerInternal.class, mMockPackageManagerInternal); @@ -782,6 +788,10 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { LocalServices.addService(ActivityTaskManagerInternal.class, mMockActivityTaskManagerInternal); LocalServices.removeServiceForTest(UserManagerInternal.class); LocalServices.addService(UserManagerInternal.class, mMockUserManagerInternal); + LocalServices.removeServiceForTest(UriGrantsManagerInternal.class); + LocalServices.addService(UriGrantsManagerInternal.class, mMockUriGrantsManagerInternal); + + mUriPermissionOwner = new UriPermissionOwner(mMockUriGrantsManagerInternal, TAG); // Prepare injection values. @@ -2193,6 +2203,7 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { for (ShortcutInfo s : actualShortcuts) { assertTrue("ID " + s.getId() + " not have icon res ID", s.hasIconResource()); assertFalse("ID " + s.getId() + " shouldn't have icon FD", s.hasIconFile()); + assertFalse("ID " + s.getId() + " shouldn't have icon URI", s.hasIconUri()); } return actualShortcuts; } @@ -2202,6 +2213,17 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { for (ShortcutInfo s : actualShortcuts) { assertFalse("ID " + s.getId() + " shouldn't have icon res ID", s.hasIconResource()); assertTrue("ID " + s.getId() + " not have icon FD", s.hasIconFile()); + assertFalse("ID " + s.getId() + " shouldn't have icon URI", s.hasIconUri()); + } + return actualShortcuts; + } + + public static List<ShortcutInfo> assertAllHaveIconUri( + List<ShortcutInfo> actualShortcuts) { + for (ShortcutInfo s : actualShortcuts) { + assertFalse("ID " + s.getId() + " shouldn't have icon res ID", s.hasIconResource()); + assertFalse("ID " + s.getId() + " shouldn't have have icon FD", s.hasIconFile()); + assertTrue("ID " + s.getId() + " not have icon URI", s.hasIconUri()); } return actualShortcuts; } diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java index 56460fb6f0a0..2cbb6d5c5bd6 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java +++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java @@ -114,8 +114,11 @@ import org.xmlpull.v1.XmlSerializer; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; +import java.io.FileOutputStream; import java.io.IOException; +import java.io.InputStream; import java.io.InputStreamReader; +import java.io.OutputStream; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; @@ -133,6 +136,16 @@ import java.util.function.BiConsumer; */ @SmallTest public class ShortcutManagerTest1 extends BaseShortcutManagerTest { + + @Override + protected void tearDown() throws Exception { + deleteUriFile("file32x32.jpg"); + deleteUriFile("file64x64.jpg"); + deleteUriFile("file512x512.jpg"); + + super.tearDown(); + } + /** * Test for the first launch path, no settings file available. */ @@ -724,6 +737,17 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { final Icon bmp512x512 = Icon.createWithBitmap(BitmapFactory.decodeResource( getTestContext().getResources(), R.drawable.black_512x512)); + // The corresponding files will be deleted in tearDown() + final Icon uri32x32 = Icon.createWithContentUri( + getFileUriFromResource("file32x32.jpg", R.drawable.black_32x32)); + final Icon uri64x64_maskable = Icon.createWithAdaptiveBitmapContentUri( + getFileUriFromResource("file64x64.jpg", R.drawable.black_64x64)); + final Icon uri512x512 = Icon.createWithContentUri( + getFileUriFromResource("file512x512.jpg", R.drawable.black_512x512)); + + doReturn(mUriPermissionOwner.getExternalToken()) + .when(mMockUriGrantsManagerInternal).newUriPermissionOwner(anyString()); + // Set from package 1 setCaller(CALLING_PACKAGE_1); assertTrue(mManager.setDynamicShortcuts(list( @@ -732,6 +756,9 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { makeShortcutWithIcon("bmp32x32", bmp32x32), makeShortcutWithIcon("bmp64x64", bmp64x64_maskable), makeShortcutWithIcon("bmp512x512", bmp512x512), + makeShortcutWithIcon("uri32x32", uri32x32), + makeShortcutWithIcon("uri64x64", uri64x64_maskable), + makeShortcutWithIcon("uri512x512", uri512x512), makeShortcut("none") ))); @@ -742,6 +769,9 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { "bmp32x32", "bmp64x64", "bmp512x512", + "uri32x32", + "uri64x64", + "uri512x512", "none"); // Call from another caller with the same ID, just to make sure storage is per-package. @@ -749,11 +779,15 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { assertTrue(mManager.setDynamicShortcuts(list( makeShortcutWithIcon("res32x32", res512x512), makeShortcutWithIcon("res64x64", res512x512), + makeShortcutWithIcon("uri32x32", uri512x512), + makeShortcutWithIcon("uri64x64", uri512x512), makeShortcutWithIcon("none", res512x512) ))); assertShortcutIds(assertAllNotHaveIcon(mManager.getDynamicShortcuts()), "res32x32", "res64x64", + "uri32x32", + "uri64x64", "none"); // Different profile. Note the names and the contents don't match. @@ -795,6 +829,18 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { list(getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "bmp512x512", USER_0))), "bmp512x512"); + assertShortcutIds(assertAllHaveIconUri( + list(getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "uri32x32", USER_0))), + "uri32x32"); + + assertShortcutIds(assertAllHaveIconUri( + list(getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "uri64x64", USER_0))), + "uri64x64"); + + assertShortcutIds(assertAllHaveIconUri( + list(getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "uri512x512", USER_0))), + "uri512x512"); + assertShortcutIds(assertAllHaveIconResId( list(getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "res32x32", USER_P0))), "res32x32"); @@ -860,15 +906,37 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { bmp = pfdToBitmap( mLauncherApps.getShortcutIconFd(CALLING_PACKAGE_1, "bmp32x32", HANDLE_USER_P0)); assertBitmapSize(128, 128, bmp); +/* + bmp = pfdToBitmap(mLauncherApps.getUriShortcutIconFd( + getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "uri32x32", USER_0))); + assertBitmapSize(32, 32, bmp); + + bmp = pfdToBitmap(mLauncherApps.getUriShortcutIconFd( + getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "uri64x64", USER_0))); + assertBitmapSize(64, 64, bmp); + + bmp = pfdToBitmap(mLauncherApps.getUriShortcutIconFd( + getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "uri512x512", USER_0))); + assertBitmapSize(512, 512, bmp); +*/ - Drawable dr = mLauncherApps.getShortcutIconDrawable( + Drawable dr_bmp = mLauncherApps.getShortcutIconDrawable( makeShortcutWithIcon("bmp64x64", bmp64x64_maskable), 0); - assertTrue(dr instanceof AdaptiveIconDrawable); + assertTrue(dr_bmp instanceof AdaptiveIconDrawable); float viewportPercentage = 1 / (1 + 2 * AdaptiveIconDrawable.getExtraInsetFraction()); assertEquals((int) (bmp64x64_maskable.getBitmap().getWidth() * viewportPercentage), - dr.getIntrinsicWidth()); + dr_bmp.getIntrinsicWidth()); + assertEquals((int) (bmp64x64_maskable.getBitmap().getHeight() * viewportPercentage), + dr_bmp.getIntrinsicHeight()); +/* + Drawable dr_uri = mLauncherApps.getShortcutIconDrawable( + makeShortcutWithIcon("uri64x64", uri64x64_maskable), 0); + assertTrue(dr_uri instanceof AdaptiveIconDrawable); + assertEquals((int) (bmp64x64_maskable.getBitmap().getWidth() * viewportPercentage), + dr_uri.getIntrinsicWidth()); assertEquals((int) (bmp64x64_maskable.getBitmap().getHeight() * viewportPercentage), - dr.getIntrinsicHeight()); + dr_uri.getIntrinsicHeight()); +*/ } public void testCleanupDanglingBitmaps() throws Exception { @@ -1274,6 +1342,18 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { makeShortcut("s1") ))); + // Set uri icon + assertTrue(mManager.updateShortcuts(list( + new ShortcutInfo.Builder(mClientContext, "s1") + .setIcon(Icon.createWithContentUri("test_uri")) + .build() + ))); + mService.waitForBitmapSavesForTest(); + assertWith(getCallerShortcuts()) + .forShortcutWithId("s1", si -> { + assertTrue(si.hasIconUri()); + assertEquals("test_uri", si.getIconUri()); + }); // Set resource icon assertTrue(mManager.updateShortcuts(list( new ShortcutInfo.Builder(mClientContext, "s1") @@ -1287,6 +1367,9 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { assertEquals(R.drawable.black_32x32, si.getIconResourceId()); }); mService.waitForBitmapSavesForTest(); + + mInjectedCurrentTimeMillis += INTERVAL; // reset throttling + // Set bitmap icon assertTrue(mManager.updateShortcuts(list( new ShortcutInfo.Builder(mClientContext, "s1") @@ -1300,9 +1383,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { assertTrue(si.hasIconFile()); }); - mInjectedCurrentTimeMillis += INTERVAL; // reset throttling - - // Do it again, with the reverse order (bitmap -> icon) + // Do it again, with the reverse order (bitmap -> resource -> uri) assertTrue(mManager.setDynamicShortcuts(list( makeShortcut("s1") ))); @@ -1320,6 +1401,8 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { assertTrue(si.hasIconFile()); }); + mInjectedCurrentTimeMillis += INTERVAL; // reset throttling + // Set resource icon assertTrue(mManager.updateShortcuts(list( new ShortcutInfo.Builder(mClientContext, "s1") @@ -1332,6 +1415,18 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { assertTrue(si.hasIconResource()); assertEquals(R.drawable.black_32x32, si.getIconResourceId()); }); + // Set uri icon + assertTrue(mManager.updateShortcuts(list( + new ShortcutInfo.Builder(mClientContext, "s1") + .setIcon(Icon.createWithContentUri("test_uri")) + .build() + ))); + mService.waitForBitmapSavesForTest(); + assertWith(getCallerShortcuts()) + .forShortcutWithId("s1", si -> { + assertTrue(si.hasIconUri()); + assertEquals("test_uri", si.getIconUri()); + }); }); } @@ -8499,4 +8594,26 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { } } } + + private Uri getFileUriFromResource(String fileName, int resId) throws IOException { + File file = new File(getTestContext().getFilesDir(), fileName); + // Make sure we are not leaving phantom files behind. + assertFalse(file.exists()); + try (InputStream source = getTestContext().getResources().openRawResource(resId); + OutputStream target = new FileOutputStream(file)) { + byte[] buffer = new byte[1024]; + for (int len = source.read(buffer); len >= 0; len = source.read(buffer)) { + target.write(buffer, 0, len); + } + } + assertTrue(file.exists()); + return Uri.fromFile(file); + } + + private void deleteUriFile(String fileName) { + File file = new File(getTestContext().getFilesDir(), fileName); + if (file.exists()) { + file.delete(); + } + } } diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java index 7b101c728d0f..ca7704950b51 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java +++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java @@ -257,6 +257,7 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { si.addFlags(ShortcutInfo.FLAG_PINNED); si.setBitmapPath("abc"); si.setIconResourceId(456); + si.setIconUri("test_uri"); si = parceled(si); @@ -279,6 +280,7 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { assertEquals(ShortcutInfo.FLAG_PINNED | ShortcutInfo.FLAG_LONG_LIVED, si.getFlags()); assertEquals("abc", si.getBitmapPath()); assertEquals(456, si.getIconResourceId()); + assertEquals("test_uri", si.getIconUri()); assertEquals(0, si.getTitleResId()); assertEquals(null, si.getTitleResName()); @@ -310,6 +312,7 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { si.addFlags(ShortcutInfo.FLAG_PINNED); si.setBitmapPath("abc"); si.setIconResourceId(456); + si.setIconUri("test_uri"); lookupAndFillInResourceNames(si); @@ -335,6 +338,7 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { assertEquals("abc", si.getBitmapPath()); assertEquals(456, si.getIconResourceId()); assertEquals("string/r456", si.getIconResName()); + assertEquals("test_uri", si.getIconUri()); } public void testShortcutInfoClone() { @@ -359,6 +363,7 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { sorig.addFlags(ShortcutInfo.FLAG_PINNED); sorig.setBitmapPath("abc"); sorig.setIconResourceId(456); + sorig.setIconUri("test_uri"); lookupAndFillInResourceNames(sorig); @@ -386,6 +391,7 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { assertEquals("abc", si.getBitmapPath()); assertEquals(456, si.getIconResourceId()); assertEquals("string/r456", si.getIconResName()); + assertEquals("test_uri", si.getIconUri()); si = sorig.clone(ShortcutInfo.CLONE_REMOVE_FOR_CREATOR); @@ -407,6 +413,7 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { assertEquals(ShortcutInfo.FLAG_PINNED | ShortcutInfo.FLAG_LONG_LIVED, si.getFlags()); assertEquals(null, si.getBitmapPath()); + assertNull(si.getIconUri()); assertEquals(456, si.getIconResourceId()); assertEquals(null, si.getIconResName()); @@ -428,6 +435,7 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { assertEquals(ShortcutInfo.FLAG_PINNED | ShortcutInfo.FLAG_LONG_LIVED, si.getFlags()); assertEquals(null, si.getBitmapPath()); + assertNull(si.getIconUri()); assertEquals(456, si.getIconResourceId()); assertEquals(null, si.getIconResName()); @@ -450,6 +458,7 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { assertEquals(ShortcutInfo.FLAG_PINNED | ShortcutInfo.FLAG_KEY_FIELDS_ONLY | ShortcutInfo.FLAG_LONG_LIVED, si.getFlags()); assertEquals(null, si.getBitmapPath()); + assertNull(si.getIconUri()); assertEquals(456, si.getIconResourceId()); assertEquals(null, si.getIconResName()); @@ -474,6 +483,7 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { assertEquals(ShortcutInfo.FLAG_PINNED | ShortcutInfo.FLAG_LONG_LIVED, si.getFlags()); assertEquals(null, si.getBitmapPath()); + assertNull(si.getIconUri()); assertEquals(456, si.getIconResourceId()); assertEquals(null, si.getIconResName()); @@ -499,6 +509,7 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { sorig.addFlags(ShortcutInfo.FLAG_PINNED); sorig.setBitmapPath("abc"); sorig.setIconResourceId(456); + sorig.setIconUri("test_uri"); lookupAndFillInResourceNames(sorig); @@ -526,6 +537,7 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { assertEquals("abc", si.getBitmapPath()); assertEquals(456, si.getIconResourceId()); assertEquals("string/r456", si.getIconResName()); + assertEquals("test_uri", si.getIconUri()); si = sorig.clone(ShortcutInfo.CLONE_REMOVE_FOR_CREATOR); @@ -547,6 +559,7 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags()); assertEquals(null, si.getBitmapPath()); + assertNull(si.getIconUri()); assertEquals(456, si.getIconResourceId()); assertEquals(null, si.getIconResName()); @@ -570,6 +583,7 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags()); assertEquals(null, si.getBitmapPath()); + assertNull(si.getIconUri()); assertEquals(456, si.getIconResourceId()); assertEquals(null, si.getIconResName()); @@ -593,6 +607,7 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { assertEquals(ShortcutInfo.FLAG_PINNED | ShortcutInfo.FLAG_KEY_FIELDS_ONLY, si.getFlags()); assertEquals(null, si.getBitmapPath()); + assertNull(si.getIconUri()); assertEquals(456, si.getIconResourceId()); assertEquals(null, si.getIconResName()); @@ -657,6 +672,7 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { sorig.addFlags(ShortcutInfo.FLAG_PINNED); sorig.setBitmapPath("abc"); sorig.setIconResourceId(456); + sorig.setIconUri("test_uri"); lookupAndFillInResourceNames(sorig); @@ -677,6 +693,7 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { assertEquals(0, si.getIconResourceId()); assertEquals(null, si.getIconResName()); assertEquals(null, si.getBitmapPath()); + assertNull(si.getIconUri()); si = sorig.clone(/* flags=*/ 0); si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id") @@ -787,6 +804,7 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { sorig.addFlags(ShortcutInfo.FLAG_PINNED); sorig.setBitmapPath("abc"); sorig.setIconResourceId(456); + sorig.setIconUri("test_uri"); ShortcutInfo si; @@ -804,6 +822,7 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { assertEquals(0, si.getIconResourceId()); assertEquals(null, si.getIconResName()); assertEquals(null, si.getBitmapPath()); + assertNull(si.getIconUri()); si = sorig.clone(/* flags=*/ 0); si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id") @@ -977,6 +996,7 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { | ShortcutInfo.FLAG_STRINGS_RESOLVED, si.getFlags()); assertNotNull(si.getBitmapPath()); // Something should be set. assertEquals(0, si.getIconResourceId()); + assertNull(si.getIconUri()); assertTrue(si.getLastChangedTimestamp() < now); // Make sure ranks are saved too. Because of the auto-adjusting, we need two shortcuts @@ -1053,6 +1073,7 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { si.getFlags()); assertNotNull(si.getBitmapPath()); // Something should be set. assertEquals(0, si.getIconResourceId()); + assertNull(si.getIconUri()); assertTrue(si.getLastChangedTimestamp() < now); dumpUserFile(USER_10); @@ -1125,6 +1146,7 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { assertEquals(ShortcutInfo.FLAG_DYNAMIC | ShortcutInfo.FLAG_HAS_ICON_RES | ShortcutInfo.FLAG_STRINGS_RESOLVED, si.getFlags()); assertNull(si.getBitmapPath()); + assertNull(si.getIconUri()); assertEquals(R.drawable.black_32x32, si.getIconResourceId()); assertTrue(si.getLastChangedTimestamp() < now); @@ -1134,6 +1156,94 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { assertEquals(1, si.getRank()); } + public void testShortcutInfoSaveAndLoad_uri() throws InterruptedException { + mRunningUsers.put(USER_10, true); + + setCaller(CALLING_PACKAGE_1, USER_10); + + final Icon uriIcon = Icon.createWithContentUri("test_uri"); + + PersistableBundle pb = new PersistableBundle(); + pb.putInt("k", 1); + ShortcutInfo sorig = new ShortcutInfo.Builder(mClientContext) + .setId("id") + .setActivity(new ComponentName(mClientContext, ShortcutActivity2.class)) + .setIcon(uriIcon) + .setTitleResId(10) + .setTextResId(11) + .setDisabledMessageResId(12) + .setCategories(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz")) + .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val")) + .setRank(123) + .setExtras(pb) + .build(); + sorig.setTimestamp(mInjectedCurrentTimeMillis); + + final Icon uriMaskableIcon = Icon.createWithAdaptiveBitmapContentUri("uri_maskable"); + + ShortcutInfo sorig2 = new ShortcutInfo.Builder(mClientContext) + .setId("id2") + .setTitle("x") + .setActivity(new ComponentName(mClientContext, ShortcutActivity2.class)) + .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val")) + .setRank(456) + .setIcon(uriMaskableIcon) + .build(); + sorig2.setTimestamp(mInjectedCurrentTimeMillis); + + mManager.addDynamicShortcuts(list(sorig, sorig2)); + + mInjectedCurrentTimeMillis += 1; + final long now = mInjectedCurrentTimeMillis; + mInjectedCurrentTimeMillis += 1; + + // Save and load. + mService.saveDirtyInfo(); + initService(); + mService.handleUnlockUser(USER_10); + + ShortcutInfo si; + si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id", USER_10); + + assertEquals(USER_10, si.getUserId()); + assertEquals(HANDLE_USER_10, si.getUserHandle()); + assertEquals(CALLING_PACKAGE_1, si.getPackage()); + assertEquals("id", si.getId()); + assertEquals(ShortcutActivity2.class.getName(), si.getActivity().getClassName()); + assertEquals(null, si.getIcon()); + assertEquals(10, si.getTitleResId()); + assertEquals("r10", si.getTitleResName()); + assertEquals(11, si.getTextResId()); + assertEquals("r11", si.getTextResName()); + assertEquals(12, si.getDisabledMessageResourceId()); + assertEquals("r12", si.getDisabledMessageResName()); + assertEquals(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories()); + assertEquals("action", si.getIntent().getAction()); + assertEquals("val", si.getIntent().getStringExtra("key")); + assertEquals(0, si.getRank()); + assertEquals(1, si.getExtras().getInt("k")); + + assertEquals(ShortcutInfo.FLAG_DYNAMIC | ShortcutInfo.FLAG_HAS_ICON_URI + | ShortcutInfo.FLAG_STRINGS_RESOLVED, si.getFlags()); + assertNull(si.getBitmapPath()); + assertNull(si.getIconResName()); + assertEquals(0, si.getIconResourceId()); + assertEquals("test_uri", si.getIconUri()); + assertTrue(si.getLastChangedTimestamp() < now); + + // Make sure ranks are saved too. Because of the auto-adjusting, we need two shortcuts + // to test it. + si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id2", USER_10); + assertEquals(1, si.getRank()); + assertEquals(ShortcutInfo.FLAG_DYNAMIC | ShortcutInfo.FLAG_HAS_ICON_URI + | ShortcutInfo.FLAG_STRINGS_RESOLVED | ShortcutInfo.FLAG_ADAPTIVE_BITMAP, + si.getFlags()); + assertNull(si.getBitmapPath()); + assertNull(si.getIconResName()); + assertEquals(0, si.getIconResourceId()); + assertEquals("uri_maskable", si.getIconUri()); + } + public void testShortcutInfoSaveAndLoad_forBackup() { setCaller(CALLING_PACKAGE_1, USER_0); @@ -1196,6 +1306,7 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { | ShortcutInfo.FLAG_SHADOW , si.getFlags()); assertNull(si.getBitmapPath()); // No icon. assertEquals(0, si.getIconResourceId()); + assertNull(si.getIconUri()); // Note when restored from backup, it's no longer dynamic, so shouldn't have a rank. si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id2", USER_0); @@ -1265,6 +1376,77 @@ public class ShortcutManagerTest2 extends BaseShortcutManagerTest { assertNull(si.getBitmapPath()); // No icon. assertEquals(0, si.getIconResourceId()); assertEquals(null, si.getIconResName()); + assertNull(si.getIconUri()); + + // Note when restored from backup, it's no longer dynamic, so shouldn't have a rank. + si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id2", USER_0); + assertEquals(0, si.getRank()); + } + + public void testShortcutInfoSaveAndLoad_forBackup_uri() { + setCaller(CALLING_PACKAGE_1, USER_0); + + final Icon uriIcon = Icon.createWithContentUri("test_uri"); + + PersistableBundle pb = new PersistableBundle(); + pb.putInt("k", 1); + ShortcutInfo sorig = new ShortcutInfo.Builder(mClientContext) + .setId("id") + .setActivity(new ComponentName(mClientContext, ShortcutActivity2.class)) + .setIcon(uriIcon) + .setTitleResId(10) + .setTextResId(11) + .setDisabledMessageResId(12) + .setCategories(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz")) + .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val")) + .setRank(123) + .setExtras(pb) + .build(); + + ShortcutInfo sorig2 = new ShortcutInfo.Builder(mClientContext) + .setId("id2") + .setTitle("x") + .setActivity(new ComponentName(mClientContext, ShortcutActivity2.class)) + .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val")) + .setRank(456) + .build(); + + mManager.addDynamicShortcuts(list(sorig, sorig2)); + + // Dynamic shortcuts won't be backed up, so we need to pin it. + setCaller(LAUNCHER_1, USER_0); + mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("id", "id2"), HANDLE_USER_0); + + // Do backup & restore. + backupAndRestore(); + + mService.handleUnlockUser(USER_0); // Load user-0. + + ShortcutInfo si; + si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id", USER_0); + + assertEquals(CALLING_PACKAGE_1, si.getPackage()); + assertEquals("id", si.getId()); + assertEquals(ShortcutActivity2.class.getName(), si.getActivity().getClassName()); + assertEquals(null, si.getIcon()); + assertEquals(10, si.getTitleResId()); + assertEquals("r10", si.getTitleResName()); + assertEquals(11, si.getTextResId()); + assertEquals("r11", si.getTextResName()); + assertEquals(12, si.getDisabledMessageResourceId()); + assertEquals("r12", si.getDisabledMessageResName()); + assertEquals(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories()); + assertEquals("action", si.getIntent().getAction()); + assertEquals("val", si.getIntent().getStringExtra("key")); + assertEquals(0, si.getRank()); + assertEquals(1, si.getExtras().getInt("k")); + + assertEquals(ShortcutInfo.FLAG_PINNED | ShortcutInfo.FLAG_STRINGS_RESOLVED + | ShortcutInfo.FLAG_SHADOW , si.getFlags()); + assertNull(si.getBitmapPath()); // No icon. + assertEquals(0, si.getIconResourceId()); + assertEquals(null, si.getIconResName()); + assertNull(si.getIconUri()); // Note when restored from backup, it's no longer dynamic, so shouldn't have a rank. si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id2", USER_0); diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java index 8e7804786b38..010f8ac334a7 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java @@ -390,7 +390,7 @@ public class NotificationListenerServiceTest extends UiServiceTestCase { "title", 0, "titleResName", "text", 0, "textResName", "disabledMessage", 0, "disabledMessageResName", null, null, 0, null, 0, 0, - 0, "iconResName", "bitmapPath", 0, + 0, "iconResName", "bitmapPath", null, 0, null, null); return si; } diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java index 8e85bb23b5c7..747c8d9d0890 100644 --- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java +++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java @@ -445,7 +445,6 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser abstract static class UsbHandler extends Handler { // current USB state - private boolean mConnected; private boolean mHostConnected; private boolean mSourcePower; private boolean mSinkPower; @@ -473,6 +472,7 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser private final UsbPermissionManager mPermissionManager; private NotificationManager mNotificationManager; + protected boolean mConnected; protected long mScreenUnlockedFunctions; protected boolean mBootCompleted; protected boolean mCurrentFunctionsApplied; @@ -1794,7 +1794,8 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser case MSG_SET_FUNCTIONS_TIMEOUT: Slog.e(TAG, "Set functions timed out! no reply from usb hal"); if (msg.arg1 != 1) { - setEnabledFunctions(UsbManager.FUNCTION_NONE, false); + // Set this since default function may be selected from Developer options + setEnabledFunctions(mScreenUnlockedFunctions, false); } break; case MSG_GET_CURRENT_USB_FUNCTIONS: @@ -1816,7 +1817,8 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser * Dont force to default when the configuration is already set to default. */ if (msg.arg1 != 1) { - setEnabledFunctions(UsbManager.FUNCTION_NONE, !isAdbEnabled()); + // Set this since default function may be selected from Developer options + setEnabledFunctions(mScreenUnlockedFunctions, false); } break; case MSG_GADGET_HAL_REGISTERED: @@ -1936,8 +1938,11 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser SET_FUNCTIONS_TIMEOUT_MS - SET_FUNCTIONS_LEEWAY_MS); sendMessageDelayed(MSG_SET_FUNCTIONS_TIMEOUT, chargingFunctions, SET_FUNCTIONS_TIMEOUT_MS); - sendMessageDelayed(MSG_FUNCTION_SWITCH_TIMEOUT, chargingFunctions, - SET_FUNCTIONS_TIMEOUT_MS + ENUMERATION_TIME_OUT_MS); + if (mConnected) { + // Only queue timeout of enumeration when the USB is connected + sendMessageDelayed(MSG_FUNCTION_SWITCH_TIMEOUT, chargingFunctions, + SET_FUNCTIONS_TIMEOUT_MS + ENUMERATION_TIME_OUT_MS); + } if (DEBUG) Slog.d(TAG, "timeout message queued"); } catch (RemoteException e) { Slog.e(TAG, "Remoteexception while calling setCurrentUsbFunctions", e); diff --git a/telephony/java/android/telephony/Annotation.java b/telephony/java/android/telephony/Annotation.java index dcd4eb519b74..28cc7d0378a1 100644 --- a/telephony/java/android/telephony/Annotation.java +++ b/telephony/java/android/telephony/Annotation.java @@ -598,48 +598,6 @@ public class Annotation { } /** - * Call forwarding function status - */ - @IntDef(prefix = { "STATUS_" }, value = { - CallForwardingInfo.STATUS_ACTIVE, - CallForwardingInfo.STATUS_INACTIVE, - CallForwardingInfo.STATUS_UNKNOWN_ERROR, - CallForwardingInfo.STATUS_NOT_SUPPORTED, - CallForwardingInfo.STATUS_FDN_CHECK_FAILURE - }) - @Retention(RetentionPolicy.SOURCE) - public @interface CallForwardingStatus { - } - - /** - * Call forwarding reason types - */ - @IntDef(flag = true, prefix = { "REASON_" }, value = { - CallForwardingInfo.REASON_UNCONDITIONAL, - CallForwardingInfo.REASON_BUSY, - CallForwardingInfo.REASON_NO_REPLY, - CallForwardingInfo.REASON_NOT_REACHABLE, - CallForwardingInfo.REASON_ALL, - CallForwardingInfo.REASON_ALL_CONDITIONAL - }) - @Retention(RetentionPolicy.SOURCE) - public @interface CallForwardingReason { - } - - /** - * Call waiting function status - */ - @IntDef(prefix = { "CALL_WAITING_STATUS_" }, value = { - TelephonyManager.CALL_WAITING_STATUS_ACTIVE, - TelephonyManager.CALL_WAITING_STATUS_INACTIVE, - TelephonyManager.CALL_WAITING_STATUS_NOT_SUPPORTED, - TelephonyManager.CALL_WAITING_STATUS_UNKNOWN_ERROR - }) - @Retention(RetentionPolicy.SOURCE) - public @interface CallWaitingStatus { - } - - /** * UICC SIM Application Types */ @IntDef(prefix = { "APPTYPE_" }, value = { diff --git a/telephony/java/android/telephony/CallForwardingInfo.java b/telephony/java/android/telephony/CallForwardingInfo.java index 1dd7539420ac..7e777fae46eb 100644 --- a/telephony/java/android/telephony/CallForwardingInfo.java +++ b/telephony/java/android/telephony/CallForwardingInfo.java @@ -15,24 +15,24 @@ */ package android.telephony; + +import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SuppressLint; -import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; -import android.telephony.Annotation.CallForwardingReason; -import android.telephony.Annotation.CallForwardingStatus; import com.android.telephony.Rlog; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.Objects; /** * Defines the call forwarding information. * @hide */ -@SystemApi public final class CallForwardingInfo implements Parcelable { private static final String TAG = "CallForwardingInfo"; @@ -41,7 +41,6 @@ public final class CallForwardingInfo implements Parcelable { * * @hide */ - @SystemApi public static final int STATUS_INACTIVE = 0; /** @@ -49,7 +48,6 @@ public final class CallForwardingInfo implements Parcelable { * * @hide */ - @SystemApi public static final int STATUS_ACTIVE = 1; /** @@ -58,7 +56,6 @@ public final class CallForwardingInfo implements Parcelable { * * @hide */ - @SystemApi public static final int STATUS_FDN_CHECK_FAILURE = 2; /** @@ -66,7 +63,6 @@ public final class CallForwardingInfo implements Parcelable { * * @hide */ - @SystemApi public static final int STATUS_UNKNOWN_ERROR = 3; /** @@ -74,7 +70,6 @@ public final class CallForwardingInfo implements Parcelable { * * @hide */ - @SystemApi public static final int STATUS_NOT_SUPPORTED = 4; /** @@ -83,7 +78,6 @@ public final class CallForwardingInfo implements Parcelable { * and conditions +CCFC * @hide */ - @SystemApi public static final int REASON_UNCONDITIONAL = 0; /** @@ -92,7 +86,6 @@ public final class CallForwardingInfo implements Parcelable { * and conditions +CCFC * @hide */ - @SystemApi public static final int REASON_BUSY = 1; /** @@ -101,7 +94,6 @@ public final class CallForwardingInfo implements Parcelable { * and conditions +CCFC * @hide */ - @SystemApi public static final int REASON_NO_REPLY = 2; /** @@ -110,7 +102,6 @@ public final class CallForwardingInfo implements Parcelable { * and conditions +CCFC * @hide */ - @SystemApi public static final int REASON_NOT_REACHABLE = 3; /** @@ -120,7 +111,6 @@ public final class CallForwardingInfo implements Parcelable { * and conditions +CCFC * @hide */ - @SystemApi public static final int REASON_ALL = 4; /** @@ -130,20 +120,48 @@ public final class CallForwardingInfo implements Parcelable { * and conditions +CCFC * @hide */ - @SystemApi public static final int REASON_ALL_CONDITIONAL = 5; /** + * Call forwarding function status + */ + @IntDef(prefix = { "STATUS_" }, value = { + STATUS_ACTIVE, + STATUS_INACTIVE, + STATUS_UNKNOWN_ERROR, + STATUS_NOT_SUPPORTED, + STATUS_FDN_CHECK_FAILURE + }) + @Retention(RetentionPolicy.SOURCE) + public @interface CallForwardingStatus { + } + + /** + * Call forwarding reason types + */ + @IntDef(flag = true, prefix = { "REASON_" }, value = { + REASON_UNCONDITIONAL, + REASON_BUSY, + REASON_NO_REPLY, + REASON_NOT_REACHABLE, + REASON_ALL, + REASON_ALL_CONDITIONAL + }) + @Retention(RetentionPolicy.SOURCE) + public @interface CallForwardingReason { + } + + /** * The call forwarding status. */ - private @CallForwardingStatus int mStatus; + private int mStatus; /** * The call forwarding reason indicates the condition under which calls will be forwarded. * Reference: 3GPP TS 27.007 version 10.3.0 Release 10 - 7.11 Call forwarding number * and conditions +CCFC */ - private @CallForwardingReason int mReason; + private int mReason; /** * The phone number to which calls will be forwarded. @@ -166,7 +184,6 @@ public final class CallForwardingInfo implements Parcelable { * @param timeSeconds the timeout (in seconds) before the forwarding is attempted * @hide */ - @SystemApi public CallForwardingInfo(@CallForwardingStatus int status, @CallForwardingReason int reason, @Nullable String number, int timeSeconds) { mStatus = status; @@ -182,7 +199,6 @@ public final class CallForwardingInfo implements Parcelable { * * @hide */ - @SystemApi public @CallForwardingStatus int getStatus() { return mStatus; } @@ -196,7 +212,6 @@ public final class CallForwardingInfo implements Parcelable { * * @hide */ - @SystemApi public @CallForwardingReason int getReason() { return mReason; } @@ -209,7 +224,6 @@ public final class CallForwardingInfo implements Parcelable { * * @hide */ - @SystemApi @Nullable public String getNumber() { return mNumber; @@ -227,7 +241,6 @@ public final class CallForwardingInfo implements Parcelable { * * @hide */ - @SystemApi @SuppressLint("MethodNameUnits") public int getTimeoutSeconds() { return mTimeSeconds; diff --git a/telephony/java/android/telephony/PreciseDataConnectionState.java b/telephony/java/android/telephony/PreciseDataConnectionState.java index e37a9b9e7a8c..c2cfbef98740 100644 --- a/telephony/java/android/telephony/PreciseDataConnectionState.java +++ b/telephony/java/android/telephony/PreciseDataConnectionState.java @@ -95,7 +95,6 @@ public final class PreciseDataConnectionState implements Parcelable { * if there is no valid APN setting for the specific type, then this will be null * @hide */ - @SystemApi public PreciseDataConnectionState(@DataState int state, @NetworkType int networkType, @ApnType int apnTypes, @NonNull String apn, diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java index f6a305f4bf2b..6aea5eeca3fd 100644 --- a/telephony/java/android/telephony/SmsManager.java +++ b/telephony/java/android/telephony/SmsManager.java @@ -2894,7 +2894,7 @@ public final class SmsManager { getSubscriptionId(), null); } } catch (RemoteException ex) { - // ignore it + throw new RuntimeException(ex); } return smsc; } @@ -2916,7 +2916,7 @@ public final class SmsManager { * </p> * * @param smsc the SMSC address string. - * @return true for success, false otherwise. + * @return true for success, false otherwise. Failure can be due modem returning an error. */ @SuppressAutoDoc // for carrier privileges and default SMS application. @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @@ -2928,7 +2928,7 @@ public final class SmsManager { smsc, getSubscriptionId(), null); } } catch (RemoteException ex) { - // ignore it + throw new RuntimeException(ex); } return false; } diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 27723efd34da..5339fb900480 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -70,13 +70,12 @@ import android.telecom.PhoneAccount; import android.telecom.PhoneAccountHandle; import android.telecom.TelecomManager; import android.telephony.Annotation.ApnType; -import android.telephony.Annotation.CallForwardingReason; import android.telephony.Annotation.CallState; -import android.telephony.Annotation.CallWaitingStatus; import android.telephony.Annotation.NetworkType; import android.telephony.Annotation.RadioPowerState; import android.telephony.Annotation.SimActivationState; import android.telephony.Annotation.UiccAppType; +import android.telephony.CallForwardingInfo.CallForwardingReason; import android.telephony.VisualVoicemailService.VisualVoicemailTask; import android.telephony.data.ApnSetting; import android.telephony.data.ApnSetting.MvnoType; @@ -12716,7 +12715,6 @@ public class TelephonyManager { * * @hide */ - @SystemApi @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @NonNull public CallForwardingInfo getCallForwarding(@CallForwardingReason int callForwardingReason) { @@ -12763,7 +12761,6 @@ public class TelephonyManager { * * @hide */ - @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setCallForwarding(@NonNull CallForwardingInfo callForwardingInfo) { if (callForwardingInfo == null) { @@ -12804,7 +12801,6 @@ public class TelephonyManager { * * @hide */ - @SystemApi public static final int CALL_WAITING_STATUS_ACTIVE = 1; /** @@ -12812,7 +12808,6 @@ public class TelephonyManager { * * @hide */ - @SystemApi public static final int CALL_WAITING_STATUS_INACTIVE = 2; /** @@ -12820,7 +12815,6 @@ public class TelephonyManager { * * @hide */ - @SystemApi public static final int CALL_WAITING_STATUS_UNKNOWN_ERROR = 3; /** @@ -12828,10 +12822,24 @@ public class TelephonyManager { * * @hide */ - @SystemApi public static final int CALL_WAITING_STATUS_NOT_SUPPORTED = 4; /** + * Call waiting function status + * + * @hide + */ + @IntDef(prefix = { "CALL_WAITING_STATUS_" }, value = { + CALL_WAITING_STATUS_ACTIVE, + CALL_WAITING_STATUS_INACTIVE, + CALL_WAITING_STATUS_NOT_SUPPORTED, + CALL_WAITING_STATUS_UNKNOWN_ERROR + }) + @Retention(RetentionPolicy.SOURCE) + public @interface CallWaitingStatus { + } + + /** * Gets the status of voice call waiting function. Call waiting function enables the waiting * for the incoming call when it reaches the user who is busy to make another call and allows * users to decide whether to switch to the incoming call. @@ -12839,7 +12847,6 @@ public class TelephonyManager { * @return the status of call waiting function. * @hide */ - @SystemApi @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public @CallWaitingStatus int getCallWaitingStatus() { try { @@ -12865,7 +12872,6 @@ public class TelephonyManager { * * @hide */ - @SystemApi @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setCallWaitingStatus(boolean isEnable) { try { diff --git a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java index dfaac2cde91d..2957192ecf0f 100644 --- a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java +++ b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java @@ -1077,6 +1077,52 @@ public class PackageWatchdogTest { assertThat(observer1.mMitigatedPackages).isEmpty(); } + /** + * Test to verify that Package Watchdog syncs health check requests with the controller + * correctly, and that the requests are only synced when the set of observed packages + * changes. + */ + @Test + public void testSyncHealthCheckRequests() { + TestController testController = spy(TestController.class); + testController.setSupportedPackages(List.of(APP_A, APP_B, APP_C)); + PackageWatchdog watchdog = createWatchdog(testController, true); + + TestObserver testObserver1 = new TestObserver(OBSERVER_NAME_1); + watchdog.registerHealthObserver(testObserver1); + watchdog.startObservingHealth(testObserver1, List.of(APP_A), LONG_DURATION); + mTestLooper.dispatchAll(); + + TestObserver testObserver2 = new TestObserver(OBSERVER_NAME_2); + watchdog.registerHealthObserver(testObserver2); + watchdog.startObservingHealth(testObserver2, List.of(APP_B), LONG_DURATION); + mTestLooper.dispatchAll(); + + TestObserver testObserver3 = new TestObserver(OBSERVER_NAME_3); + watchdog.registerHealthObserver(testObserver3); + watchdog.startObservingHealth(testObserver3, List.of(APP_C), LONG_DURATION); + mTestLooper.dispatchAll(); + + watchdog.unregisterHealthObserver(testObserver1); + mTestLooper.dispatchAll(); + + watchdog.unregisterHealthObserver(testObserver2); + mTestLooper.dispatchAll(); + + watchdog.unregisterHealthObserver(testObserver3); + mTestLooper.dispatchAll(); + + List<Set> expectedSyncRequests = List.of( + Set.of(APP_A), + Set.of(APP_A, APP_B), + Set.of(APP_A, APP_B, APP_C), + Set.of(APP_B, APP_C), + Set.of(APP_C), + Set.of() + ); + assertThat(testController.getSyncRequests()).isEqualTo(expectedSyncRequests); + } + private void adoptShellPermissions(String... permissions) { InstrumentationRegistry .getInstrumentation() @@ -1233,6 +1279,7 @@ public class PackageWatchdogTest { private Consumer<String> mPassedConsumer; private Consumer<List<PackageConfig>> mSupportedConsumer; private Runnable mNotifySyncRunnable; + private List<Set> mSyncRequests = new ArrayList<>(); @Override public void setEnabled(boolean enabled) { @@ -1252,6 +1299,7 @@ public class PackageWatchdogTest { @Override public void syncRequests(Set<String> packages) { + mSyncRequests.add(packages); mRequestedPackages.clear(); if (mIsEnabled) { packages.retainAll(mSupportedPackages); @@ -1282,6 +1330,10 @@ public class PackageWatchdogTest { return Collections.emptyList(); } } + + public List<Set> getSyncRequests() { + return mSyncRequests; + } } private static class TestClock implements PackageWatchdog.SystemClock { diff --git a/tests/net/AndroidManifest.xml b/tests/net/AndroidManifest.xml index 480b12be91c8..009f817af407 100644 --- a/tests/net/AndroidManifest.xml +++ b/tests/net/AndroidManifest.xml @@ -47,6 +47,7 @@ <uses-permission android:name="android.permission.NETWORK_STACK" /> <uses-permission android:name="android.permission.OBSERVE_NETWORK_POLICY" /> <uses-permission android:name="android.permission.NETWORK_FACTORY" /> + <uses-permission android:name="android.permission.NETWORK_STATS_PROVIDER" /> <application> <uses-library android:name="android.test.runner" /> diff --git a/tests/net/common/java/android/net/KeepalivePacketDataTest.kt b/tests/net/common/java/android/net/KeepalivePacketDataTest.kt new file mode 100644 index 000000000000..f464ec6cf0e5 --- /dev/null +++ b/tests/net/common/java/android/net/KeepalivePacketDataTest.kt @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.net + +import android.net.InvalidPacketException.ERROR_INVALID_IP_ADDRESS +import android.net.InvalidPacketException.ERROR_INVALID_PORT +import android.os.Build +import androidx.test.filters.SmallTest +import androidx.test.runner.AndroidJUnit4 +import com.android.testutils.DevSdkIgnoreRule +import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo +import java.net.InetAddress +import java.util.Arrays +import org.junit.Assert.assertEquals +import org.junit.Assert.assertTrue +import org.junit.Assert.fail +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +@SmallTest +class KeepalivePacketDataTest { + @Rule @JvmField + val ignoreRule: DevSdkIgnoreRule = DevSdkIgnoreRule() + + private val INVALID_PORT = 65537 + private val TEST_DST_PORT = 4244 + private val TEST_SRC_PORT = 4243 + + private val TESTBYTES = byteArrayOf(12, 31, 22, 44) + private val TEST_SRC_ADDRV4 = "198.168.0.2".address() + private val TEST_DST_ADDRV4 = "198.168.0.1".address() + private val TEST_ADDRV6 = "2001:db8::1".address() + + private fun String.address() = InetAddresses.parseNumericAddress(this) + + // Add for test because constructor of KeepalivePacketData is protected. + private inner class TestKeepalivePacketData( + srcAddress: InetAddress? = TEST_SRC_ADDRV4, + srcPort: Int = TEST_SRC_PORT, + dstAddress: InetAddress? = TEST_DST_ADDRV4, + dstPort: Int = TEST_DST_PORT, + data: ByteArray = TESTBYTES + ) : KeepalivePacketData(srcAddress, srcPort, dstAddress, dstPort, data) + + @Test + @IgnoreUpTo(Build.VERSION_CODES.Q) + fun testConstructor() { + var data: TestKeepalivePacketData + + try { + data = TestKeepalivePacketData(srcAddress = null) + fail("Null src address should cause exception") + } catch (e: InvalidPacketException) { + assertEquals(e.error, ERROR_INVALID_IP_ADDRESS) + } + + try { + data = TestKeepalivePacketData(dstAddress = null) + fail("Null dst address should cause exception") + } catch (e: InvalidPacketException) { + assertEquals(e.error, ERROR_INVALID_IP_ADDRESS) + } + + try { + data = TestKeepalivePacketData(dstAddress = TEST_ADDRV6) + fail("Ip family mismatched should cause exception") + } catch (e: InvalidPacketException) { + assertEquals(e.error, ERROR_INVALID_IP_ADDRESS) + } + + try { + data = TestKeepalivePacketData(srcPort = INVALID_PORT) + fail("Invalid srcPort should cause exception") + } catch (e: InvalidPacketException) { + assertEquals(e.error, ERROR_INVALID_PORT) + } + + try { + data = TestKeepalivePacketData(dstPort = INVALID_PORT) + fail("Invalid dstPort should cause exception") + } catch (e: InvalidPacketException) { + assertEquals(e.error, ERROR_INVALID_PORT) + } + } + + @Test + @IgnoreUpTo(Build.VERSION_CODES.Q) + fun testSrcAddress() = assertEquals(TEST_SRC_ADDRV4, TestKeepalivePacketData().srcAddress) + + @Test + @IgnoreUpTo(Build.VERSION_CODES.Q) + fun testDstAddress() = assertEquals(TEST_DST_ADDRV4, TestKeepalivePacketData().dstAddress) + + @Test + @IgnoreUpTo(Build.VERSION_CODES.Q) + fun testSrcPort() = assertEquals(TEST_SRC_PORT, TestKeepalivePacketData().srcPort) + + @Test + @IgnoreUpTo(Build.VERSION_CODES.Q) + fun testDstPort() = assertEquals(TEST_DST_PORT, TestKeepalivePacketData().dstPort) + + @Test + @IgnoreUpTo(Build.VERSION_CODES.Q) + fun testPacket() = assertTrue(Arrays.equals(TESTBYTES, TestKeepalivePacketData().packet)) +}
\ No newline at end of file diff --git a/tests/net/common/java/android/net/NattKeepalivePacketDataTest.kt b/tests/net/common/java/android/net/NattKeepalivePacketDataTest.kt new file mode 100644 index 000000000000..46f39dd016fd --- /dev/null +++ b/tests/net/common/java/android/net/NattKeepalivePacketDataTest.kt @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net + +import android.net.InvalidPacketException.ERROR_INVALID_IP_ADDRESS +import android.net.InvalidPacketException.ERROR_INVALID_PORT +import android.net.NattSocketKeepalive.NATT_PORT +import android.os.Build +import androidx.test.filters.SmallTest +import androidx.test.runner.AndroidJUnit4 +import com.android.testutils.assertEqualBothWays +import com.android.testutils.assertFieldCountEquals +import com.android.testutils.assertParcelSane +import com.android.testutils.DevSdkIgnoreRule +import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo +import com.android.testutils.parcelingRoundTrip +import java.net.InetAddress +import org.junit.Assert.assertEquals +import org.junit.Assert.assertNotEquals +import org.junit.Assert.fail +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidJUnit4::class) +@SmallTest +class NattKeepalivePacketDataTest { + @Rule @JvmField + val ignoreRule: DevSdkIgnoreRule = DevSdkIgnoreRule() + + /* Refer to the definition in {@code NattKeepalivePacketData} */ + private val IPV4_HEADER_LENGTH = 20 + private val UDP_HEADER_LENGTH = 8 + + private val TEST_PORT = 4243 + private val TEST_PORT2 = 4244 + private val TEST_SRC_ADDRV4 = "198.168.0.2".address() + private val TEST_DST_ADDRV4 = "198.168.0.1".address() + private val TEST_ADDRV6 = "2001:db8::1".address() + + private fun String.address() = InetAddresses.parseNumericAddress(this) + private fun nattKeepalivePacket( + srcAddress: InetAddress? = TEST_SRC_ADDRV4, + srcPort: Int = TEST_PORT, + dstAddress: InetAddress? = TEST_DST_ADDRV4, + dstPort: Int = NATT_PORT + ) = NattKeepalivePacketData.nattKeepalivePacket(srcAddress, srcPort, dstAddress, dstPort) + + @Test @IgnoreUpTo(Build.VERSION_CODES.Q) + fun testConstructor() { + try { + nattKeepalivePacket(dstPort = TEST_PORT) + fail("Dst port is not NATT port should cause exception") + } catch (e: InvalidPacketException) { + assertEquals(e.error, ERROR_INVALID_PORT) + } + + try { + nattKeepalivePacket(srcAddress = TEST_ADDRV6) + fail("A v6 srcAddress should cause exception") + } catch (e: InvalidPacketException) { + assertEquals(e.error, ERROR_INVALID_IP_ADDRESS) + } + + try { + nattKeepalivePacket(dstAddress = TEST_ADDRV6) + fail("A v6 dstAddress should cause exception") + } catch (e: InvalidPacketException) { + assertEquals(e.error, ERROR_INVALID_IP_ADDRESS) + } + + try { + parcelingRoundTrip( + NattKeepalivePacketData(TEST_SRC_ADDRV4, TEST_PORT, TEST_DST_ADDRV4, TEST_PORT, + byteArrayOf(12, 31, 22, 44))) + fail("Invalid data should cause exception") + } catch (e: IllegalArgumentException) { } + } + + @Test @IgnoreUpTo(Build.VERSION_CODES.Q) + fun testParcel() { + assertParcelSane(nattKeepalivePacket(), 0) + } + + @Test @IgnoreUpTo(Build.VERSION_CODES.Q) + fun testEquals() { + assertEqualBothWays(nattKeepalivePacket(), nattKeepalivePacket()) + assertNotEquals(nattKeepalivePacket(dstAddress = TEST_SRC_ADDRV4), nattKeepalivePacket()) + assertNotEquals(nattKeepalivePacket(srcAddress = TEST_DST_ADDRV4), nattKeepalivePacket()) + // Test src port only because dst port have to be NATT_PORT + assertNotEquals(nattKeepalivePacket(srcPort = TEST_PORT2), nattKeepalivePacket()) + // Make sure the parceling test is updated if fields are added in the base class. + assertFieldCountEquals(5, KeepalivePacketData::class.java) + } + + @Test @IgnoreUpTo(Build.VERSION_CODES.Q) + fun testHashCode() { + assertEquals(nattKeepalivePacket().hashCode(), nattKeepalivePacket().hashCode()) + } +}
\ No newline at end of file diff --git a/tests/net/java/android/net/NetworkStatsTest.java b/tests/net/java/android/net/NetworkStatsTest.java index 33d77d288e15..e71d5995255d 100644 --- a/tests/net/java/android/net/NetworkStatsTest.java +++ b/tests/net/java/android/net/NetworkStatsTest.java @@ -64,15 +64,15 @@ public class NetworkStatsTest { @Test public void testFindIndex() throws Exception { final NetworkStats stats = new NetworkStats(TEST_START, 5) - .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + .insertEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, 1024L, 8L, 0L, 0L, 10) - .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + .insertEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 0L, 0L, 1024L, 8L, 11) - .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO, + .insertEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO, DEFAULT_NETWORK_YES, 0L, 0L, 1024L, 8L, 11) - .addEntry(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + .insertEntry(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 1024L, 8L, 1024L, 8L, 12) - .addEntry(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_YES, + .insertEntry(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_YES, DEFAULT_NETWORK_YES, 1024L, 8L, 1024L, 8L, 12); assertEquals(4, stats.findIndex(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, METERED_YES, @@ -94,21 +94,21 @@ public class NetworkStatsTest { @Test public void testFindIndexHinted() { final NetworkStats stats = new NetworkStats(TEST_START, 3) - .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + .insertEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, 1024L, 8L, 0L, 0L, 10) - .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + .insertEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 0L, 0L, 1024L, 8L, 11) - .addEntry(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + .insertEntry(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, 1024L, 8L, 1024L, 8L, 12) - .addEntry(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, + .insertEntry(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 1024L, 8L, 0L, 0L, 10) - .addEntry(TEST_IFACE2, 101, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO, + .insertEntry(TEST_IFACE2, 101, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, 0L, 0L, 1024L, 8L, 11) - .addEntry(TEST_IFACE2, 101, SET_DEFAULT, 0xF00D, METERED_YES, ROAMING_NO, + .insertEntry(TEST_IFACE2, 101, SET_DEFAULT, 0xF00D, METERED_YES, ROAMING_NO, DEFAULT_NETWORK_NO, 0L, 0L, 1024L, 8L, 11) - .addEntry(TEST_IFACE2, 102, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + .insertEntry(TEST_IFACE2, 102, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, 1024L, 8L, 1024L, 8L, 12) - .addEntry(TEST_IFACE2, 102, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_YES, + .insertEntry(TEST_IFACE2, 102, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_YES, DEFAULT_NETWORK_NO, 1024L, 8L, 1024L, 8L, 12); // verify that we correctly find across regardless of hinting @@ -143,27 +143,27 @@ public class NetworkStatsTest { assertEquals(0, stats.size()); assertEquals(4, stats.internalSize()); - stats.addEntry(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + stats.insertEntry(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, 1L, 1L, 2L, 2L, 3); - stats.addEntry(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + stats.insertEntry(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 2L, 2L, 2L, 2L, 4); - stats.addEntry(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES, + stats.insertEntry(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES, DEFAULT_NETWORK_YES, 3L, 3L, 2L, 2L, 5); - stats.addEntry(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_YES, + stats.insertEntry(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_YES, DEFAULT_NETWORK_NO, 3L, 3L, 2L, 2L, 5); assertEquals(4, stats.size()); assertEquals(4, stats.internalSize()); - stats.addEntry(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + stats.insertEntry(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 4L, 40L, 4L, 40L, 7); - stats.addEntry(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + stats.insertEntry(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, 5L, 50L, 4L, 40L, 8); - stats.addEntry(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + stats.insertEntry(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 6L, 60L, 5L, 50L, 10); - stats.addEntry(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES, + stats.insertEntry(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES, DEFAULT_NETWORK_YES, 7L, 70L, 5L, 50L, 11); - stats.addEntry(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_YES, + stats.insertEntry(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_YES, DEFAULT_NETWORK_NO, 7L, 70L, 5L, 50L, 11); assertEquals(9, stats.size()); @@ -193,8 +193,8 @@ public class NetworkStatsTest { public void testCombineExisting() throws Exception { final NetworkStats stats = new NetworkStats(TEST_START, 10); - stats.addEntry(TEST_IFACE, 1001, SET_DEFAULT, TAG_NONE, 512L, 4L, 256L, 2L, 10); - stats.addEntry(TEST_IFACE, 1001, SET_DEFAULT, 0xff, 128L, 1L, 128L, 1L, 2); + stats.insertEntry(TEST_IFACE, 1001, SET_DEFAULT, TAG_NONE, 512L, 4L, 256L, 2L, 10); + stats.insertEntry(TEST_IFACE, 1001, SET_DEFAULT, 0xff, 128L, 1L, 128L, 1L, 2); stats.combineValues(TEST_IFACE, 1001, SET_DEFAULT, TAG_NONE, -128L, -1L, -128L, -1L, -1); @@ -215,12 +215,12 @@ public class NetworkStatsTest { @Test public void testSubtractIdenticalData() throws Exception { final NetworkStats before = new NetworkStats(TEST_START, 2) - .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1024L, 8L, 0L, 0L, 11) - .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 0L, 0L, 1024L, 8L, 12); + .insertEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1024L, 8L, 0L, 0L, 11) + .insertEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 0L, 0L, 1024L, 8L, 12); final NetworkStats after = new NetworkStats(TEST_START, 2) - .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1024L, 8L, 0L, 0L, 11) - .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 0L, 0L, 1024L, 8L, 12); + .insertEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1024L, 8L, 0L, 0L, 11) + .insertEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 0L, 0L, 1024L, 8L, 12); final NetworkStats result = after.subtract(before); @@ -234,12 +234,12 @@ public class NetworkStatsTest { @Test public void testSubtractIdenticalRows() throws Exception { final NetworkStats before = new NetworkStats(TEST_START, 2) - .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1024L, 8L, 0L, 0L, 11) - .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 0L, 0L, 1024L, 8L, 12); + .insertEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1024L, 8L, 0L, 0L, 11) + .insertEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 0L, 0L, 1024L, 8L, 12); final NetworkStats after = new NetworkStats(TEST_START, 2) - .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1025L, 9L, 2L, 1L, 15) - .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 3L, 1L, 1028L, 9L, 20); + .insertEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1025L, 9L, 2L, 1L, 15) + .insertEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 3L, 1L, 1028L, 9L, 20); final NetworkStats result = after.subtract(before); @@ -253,13 +253,13 @@ public class NetworkStatsTest { @Test public void testSubtractNewRows() throws Exception { final NetworkStats before = new NetworkStats(TEST_START, 2) - .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1024L, 8L, 0L, 0L, 11) - .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 0L, 0L, 1024L, 8L, 12); + .insertEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1024L, 8L, 0L, 0L, 11) + .insertEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 0L, 0L, 1024L, 8L, 12); final NetworkStats after = new NetworkStats(TEST_START, 3) - .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1024L, 8L, 0L, 0L, 11) - .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 0L, 0L, 1024L, 8L, 12) - .addEntry(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 20); + .insertEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1024L, 8L, 0L, 0L, 11) + .insertEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 0L, 0L, 1024L, 8L, 12) + .insertEntry(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 20); final NetworkStats result = after.subtract(before); @@ -275,11 +275,11 @@ public class NetworkStatsTest { @Test public void testSubtractMissingRows() throws Exception { final NetworkStats before = new NetworkStats(TEST_START, 2) - .addEntry(TEST_IFACE, UID_ALL, SET_DEFAULT, TAG_NONE, 1024L, 0L, 0L, 0L, 0) - .addEntry(TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, 2048L, 0L, 0L, 0L, 0); + .insertEntry(TEST_IFACE, UID_ALL, SET_DEFAULT, TAG_NONE, 1024L, 0L, 0L, 0L, 0) + .insertEntry(TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, 2048L, 0L, 0L, 0L, 0); final NetworkStats after = new NetworkStats(TEST_START, 1) - .addEntry(TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, 2049L, 2L, 3L, 4L, 0); + .insertEntry(TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, 2049L, 2L, 3L, 4L, 0); final NetworkStats result = after.subtract(before); @@ -293,40 +293,40 @@ public class NetworkStatsTest { @Test public void testTotalBytes() throws Exception { final NetworkStats iface = new NetworkStats(TEST_START, 2) - .addEntry(TEST_IFACE, UID_ALL, SET_DEFAULT, TAG_NONE, 128L, 0L, 0L, 0L, 0L) - .addEntry(TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, 256L, 0L, 0L, 0L, 0L); + .insertEntry(TEST_IFACE, UID_ALL, SET_DEFAULT, TAG_NONE, 128L, 0L, 0L, 0L, 0L) + .insertEntry(TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, 256L, 0L, 0L, 0L, 0L); assertEquals(384L, iface.getTotalBytes()); final NetworkStats uidSet = new NetworkStats(TEST_START, 3) - .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 32L, 0L, 0L, 0L, 0L) - .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 32L, 0L, 0L, 0L, 0L) - .addEntry(TEST_IFACE, 101, SET_FOREGROUND, TAG_NONE, 32L, 0L, 0L, 0L, 0L); + .insertEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 32L, 0L, 0L, 0L, 0L) + .insertEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 32L, 0L, 0L, 0L, 0L) + .insertEntry(TEST_IFACE, 101, SET_FOREGROUND, TAG_NONE, 32L, 0L, 0L, 0L, 0L); assertEquals(96L, uidSet.getTotalBytes()); final NetworkStats uidTag = new NetworkStats(TEST_START, 6) - .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 16L, 0L, 0L, 0L, 0L) - .addEntry(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, 16L, 0L, 0L, 0L, 0L) - .addEntry(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, 8L, 0L, 0L, 0L, 0L) - .addEntry(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, 16L, 0L, 0L, 0L, 0L) - .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 16L, 0L, 0L, 0L, 0L) - .addEntry(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, 8L, 0L, 0L, 0L, 0L); + .insertEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 16L, 0L, 0L, 0L, 0L) + .insertEntry(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, 16L, 0L, 0L, 0L, 0L) + .insertEntry(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, 8L, 0L, 0L, 0L, 0L) + .insertEntry(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, 16L, 0L, 0L, 0L, 0L) + .insertEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 16L, 0L, 0L, 0L, 0L) + .insertEntry(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, 8L, 0L, 0L, 0L, 0L); assertEquals(64L, uidTag.getTotalBytes()); final NetworkStats uidMetered = new NetworkStats(TEST_START, 3) - .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + .insertEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, 32L, 0L, 0L, 0L, 0L) - .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO, + .insertEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO, DEFAULT_NETWORK_NO, 32L, 0L, 0L, 0L, 0L) - .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO, + .insertEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO, DEFAULT_NETWORK_YES, 32L, 0L, 0L, 0L, 0L); assertEquals(96L, uidMetered.getTotalBytes()); final NetworkStats uidRoaming = new NetworkStats(TEST_START, 3) - .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + .insertEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, 32L, 0L, 0L, 0L, 0L) - .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO, + .insertEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO, DEFAULT_NETWORK_NO, 32L, 0L, 0L, 0L, 0L) - .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES, + .insertEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES, DEFAULT_NETWORK_YES, 32L, 0L, 0L, 0L, 0L); assertEquals(96L, uidRoaming.getTotalBytes()); } @@ -343,11 +343,11 @@ public class NetworkStatsTest { @Test public void testGroupedByIfaceAll() throws Exception { final NetworkStats uidStats = new NetworkStats(TEST_START, 3) - .addEntry(IFACE_ALL, 100, SET_ALL, TAG_NONE, METERED_NO, ROAMING_NO, + .insertEntry(IFACE_ALL, 100, SET_ALL, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, 128L, 8L, 0L, 2L, 20L) - .addEntry(IFACE_ALL, 101, SET_FOREGROUND, TAG_NONE, METERED_YES, ROAMING_NO, + .insertEntry(IFACE_ALL, 101, SET_FOREGROUND, TAG_NONE, METERED_YES, ROAMING_NO, DEFAULT_NETWORK_NO, 128L, 8L, 0L, 2L, 20L) - .addEntry(IFACE_ALL, 101, SET_ALL, TAG_NONE, METERED_NO, ROAMING_YES, + .insertEntry(IFACE_ALL, 101, SET_ALL, TAG_NONE, METERED_NO, ROAMING_YES, DEFAULT_NETWORK_YES, 128L, 8L, 0L, 2L, 20L); final NetworkStats grouped = uidStats.groupedByIface(); @@ -361,19 +361,19 @@ public class NetworkStatsTest { @Test public void testGroupedByIface() throws Exception { final NetworkStats uidStats = new NetworkStats(TEST_START, 7) - .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + .insertEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, 128L, 8L, 0L, 2L, 20L) - .addEntry(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + .insertEntry(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 512L, 32L, 0L, 0L, 0L) - .addEntry(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO, + .insertEntry(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, 64L, 4L, 0L, 0L, 0L) - .addEntry(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, + .insertEntry(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 512L, 32L, 0L, 0L, 0L) - .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + .insertEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, 128L, 8L, 0L, 0L, 0L) - .addEntry(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, METERED_YES, ROAMING_NO, + .insertEntry(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, METERED_YES, ROAMING_NO, DEFAULT_NETWORK_NO, 128L, 8L, 0L, 0L, 0L) - .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES, + .insertEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES, DEFAULT_NETWORK_YES, 128L, 8L, 0L, 0L, 0L); final NetworkStats grouped = uidStats.groupedByIface(); @@ -390,19 +390,19 @@ public class NetworkStatsTest { @Test public void testAddAllValues() { final NetworkStats first = new NetworkStats(TEST_START, 5) - .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO, + .insertEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO, DEFAULT_NETWORK_YES, 32L, 0L, 0L, 0L, 0L) - .addEntry(TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, + .insertEntry(TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 32L, 0L, 0L, 0L, 0L) - .addEntry(TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, METERED_YES, ROAMING_YES, + .insertEntry(TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, METERED_YES, ROAMING_YES, DEFAULT_NETWORK_YES, 32L, 0L, 0L, 0L, 0L); final NetworkStats second = new NetworkStats(TEST_START, 2) - .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO, + .insertEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO, DEFAULT_NETWORK_YES, 32L, 0L, 0L, 0L, 0L) - .addEntry(TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + .insertEntry(TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 32L, 0L, 0L, 0L, 0L) - .addEntry(TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, METERED_YES, ROAMING_YES, + .insertEntry(TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, METERED_YES, ROAMING_YES, DEFAULT_NETWORK_YES, 32L, 0L, 0L, 0L, 0L); first.combineAllValues(second); @@ -421,19 +421,19 @@ public class NetworkStatsTest { @Test public void testGetTotal() { final NetworkStats stats = new NetworkStats(TEST_START, 7) - .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + .insertEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, 128L, 8L, 0L, 2L, 20L) - .addEntry(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + .insertEntry(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 512L, 32L, 0L, 0L, 0L) - .addEntry(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO, + .insertEntry(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, 64L, 4L, 0L, 0L, 0L) - .addEntry(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, + .insertEntry(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 512L,32L, 0L, 0L, 0L) - .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO, + .insertEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO, DEFAULT_NETWORK_YES, 128L, 8L, 0L, 0L, 0L) - .addEntry(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO, + .insertEntry(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 128L, 8L, 0L, 0L, 0L) - .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES, + .insertEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_YES, DEFAULT_NETWORK_NO, 128L, 8L, 0L, 0L, 0L); assertValues(stats.getTotal(null), 1408L, 88L, 0L, 2L, 20L); @@ -459,7 +459,7 @@ public class NetworkStatsTest { assertEquals(0, after.size()); // Test 1 item stats. - before.addEntry(TEST_IFACE, 99, SET_DEFAULT, TAG_NONE, 1L, 128L, 0L, 2L, 20L); + before.insertEntry(TEST_IFACE, 99, SET_DEFAULT, TAG_NONE, 1L, 128L, 0L, 2L, 20L); after = before.clone(); after.removeUids(new int[0]); assertEquals(1, after.size()); @@ -469,12 +469,12 @@ public class NetworkStatsTest { assertEquals(0, after.size()); // Append remaining test items. - before.addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 2L, 64L, 0L, 2L, 20L) - .addEntry(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, 4L, 32L, 0L, 0L, 0L) - .addEntry(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, 8L, 16L, 0L, 0L, 0L) - .addEntry(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, 16L, 8L, 0L, 0L, 0L) - .addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 32L, 4L, 0L, 0L, 0L) - .addEntry(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, 64L, 2L, 0L, 0L, 0L); + before.insertEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 2L, 64L, 0L, 2L, 20L) + .insertEntry(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, 4L, 32L, 0L, 0L, 0L) + .insertEntry(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, 8L, 16L, 0L, 0L, 0L) + .insertEntry(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, 16L, 8L, 0L, 0L, 0L) + .insertEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 32L, 4L, 0L, 0L, 0L) + .insertEntry(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, 64L, 2L, 0L, 0L, 0L); assertEquals(7, before.size()); // Test remove with empty uid list. @@ -505,12 +505,12 @@ public class NetworkStatsTest { @Test public void testClone() throws Exception { final NetworkStats original = new NetworkStats(TEST_START, 5) - .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 128L, 8L, 0L, 2L, 20L) - .addEntry(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, 512L, 32L, 0L, 0L, 0L); + .insertEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 128L, 8L, 0L, 2L, 20L) + .insertEntry(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, 512L, 32L, 0L, 0L, 0L); // make clone and mutate original final NetworkStats clone = original.clone(); - original.addEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 128L, 8L, 0L, 0L, 0L); + original.insertEntry(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 128L, 8L, 0L, 0L, 0L); assertEquals(3, original.size()); assertEquals(2, clone.size()); @@ -523,8 +523,8 @@ public class NetworkStatsTest { public void testAddWhenEmpty() throws Exception { final NetworkStats red = new NetworkStats(TEST_START, -1); final NetworkStats blue = new NetworkStats(TEST_START, 5) - .addEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 128L, 8L, 0L, 2L, 20L) - .addEntry(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, 512L, 32L, 0L, 0L, 0L); + .insertEntry(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 128L, 8L, 0L, 2L, 20L) + .insertEntry(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, 512L, 32L, 0L, 0L, 0L); // We're mostly checking that we don't crash red.combineAllValues(blue); @@ -537,37 +537,37 @@ public class NetworkStatsTest { final String underlyingIface = "wlan0"; final int testTag1 = 8888; NetworkStats delta = new NetworkStats(TEST_START, 17) - .addEntry(tunIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + .insertEntry(tunIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 39605L, 46L, 12259L, 55L, 0L) - .addEntry(tunIface, 10100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, + .insertEntry(tunIface, 10100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0L) - .addEntry(tunIface, 10120, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + .insertEntry(tunIface, 10120, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 72667L, 197L, 43909L, 241L, 0L) - .addEntry(tunIface, 10120, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, + .insertEntry(tunIface, 10120, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 9297L, 17L, 4128L, 21L, 0L) // VPN package also uses some traffic through unprotected network. - .addEntry(tunIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + .insertEntry(tunIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 4983L, 10L, 1801L, 12L, 0L) - .addEntry(tunIface, tunUid, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, + .insertEntry(tunIface, tunUid, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0L) // Tag entries - .addEntry(tunIface, 10120, SET_DEFAULT, testTag1, METERED_NO, ROAMING_NO, + .insertEntry(tunIface, 10120, SET_DEFAULT, testTag1, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 21691L, 41L, 13820L, 51L, 0L) - .addEntry(tunIface, 10120, SET_FOREGROUND, testTag1, METERED_NO, ROAMING_NO, + .insertEntry(tunIface, 10120, SET_FOREGROUND, testTag1, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 1281L, 2L, 665L, 2L, 0L) // Irrelevant entries - .addEntry(TEST_IFACE, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + .insertEntry(TEST_IFACE, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 1685L, 5L, 2070L, 6L, 0L) // Underlying Iface entries - .addEntry(underlyingIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + .insertEntry(underlyingIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 5178L, 8L, 2139L, 11L, 0L) - .addEntry(underlyingIface, 10100, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, - DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0L) - .addEntry(underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + .insertEntry(underlyingIface, 10100, SET_FOREGROUND, TAG_NONE, METERED_NO, + ROAMING_NO, DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0L) + .insertEntry(underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 149873L, 287L, 59217L /* smaller than sum(tun0) */, 299L /* smaller than sum(tun0) */, 0L) - .addEntry(underlyingIface, tunUid, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, - DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0L); + .insertEntry(underlyingIface, tunUid, SET_FOREGROUND, TAG_NONE, METERED_NO, + ROAMING_NO, DEFAULT_NETWORK_NO, 0L, 0L, 0L, 0L, 0L); delta.migrateTun(tunUid, tunIface, new String[]{underlyingIface}); assertEquals(20, delta.size()); @@ -635,19 +635,19 @@ public class NetworkStatsTest { final String underlyingIface = "wlan0"; NetworkStats delta = new NetworkStats(TEST_START, 9) // 2 different apps sent/receive data via tun0. - .addEntry(tunIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + .insertEntry(tunIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L) - .addEntry(tunIface, 20100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + .insertEntry(tunIface, 20100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 500L, 2L, 200L, 5L, 0L) // VPN package resends data through the tunnel (with exaggerated overhead) - .addEntry(tunIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + .insertEntry(tunIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 240000, 100L, 120000L, 60L, 0L) // 1 app already has some traffic on the underlying interface, the other doesn't yet - .addEntry(underlyingIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + .insertEntry(underlyingIface, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 1000L, 10L, 2000L, 20L, 0L) // Traffic through the underlying interface via the vpn app. // This test should redistribute this data correctly. - .addEntry(underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + .insertEntry(underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, 75500L, 37L, 130000L, 70L, 0L); delta.migrateTun(tunUid, tunIface, new String[]{underlyingIface}); @@ -697,9 +697,9 @@ public class NetworkStatsTest { DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L); NetworkStats stats = new NetworkStats(TEST_START, 3) - .addEntry(entry1) - .addEntry(entry2) - .addEntry(entry3); + .insertEntry(entry1) + .insertEntry(entry2) + .insertEntry(entry3); stats.filter(UID_ALL, INTERFACES_ALL, TAG_ALL); assertEquals(3, stats.size()); @@ -724,9 +724,9 @@ public class NetworkStatsTest { DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L); NetworkStats stats = new NetworkStats(TEST_START, 3) - .addEntry(entry1) - .addEntry(entry2) - .addEntry(entry3); + .insertEntry(entry1) + .insertEntry(entry2) + .insertEntry(entry3); stats.filter(testUid, INTERFACES_ALL, TAG_ALL); assertEquals(2, stats.size()); @@ -755,10 +755,10 @@ public class NetworkStatsTest { DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L); NetworkStats stats = new NetworkStats(TEST_START, 4) - .addEntry(entry1) - .addEntry(entry2) - .addEntry(entry3) - .addEntry(entry4); + .insertEntry(entry1) + .insertEntry(entry2) + .insertEntry(entry3) + .insertEntry(entry4); stats.filter(UID_ALL, new String[] { testIf1, testIf2 }, TAG_ALL); assertEquals(3, stats.size()); @@ -778,8 +778,8 @@ public class NetworkStatsTest { DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L); NetworkStats stats = new NetworkStats(TEST_START, 3) - .addEntry(entry1) - .addEntry(entry2); + .insertEntry(entry1) + .insertEntry(entry2); stats.filter(UID_ALL, new String[] { }, TAG_ALL); assertEquals(0, stats.size()); @@ -802,9 +802,9 @@ public class NetworkStatsTest { DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L); NetworkStats stats = new NetworkStats(TEST_START, 3) - .addEntry(entry1) - .addEntry(entry2) - .addEntry(entry3); + .insertEntry(entry1) + .insertEntry(entry2) + .insertEntry(entry3); stats.filter(UID_ALL, INTERFACES_ALL, testTag); assertEquals(2, stats.size()); @@ -831,10 +831,10 @@ public class NetworkStatsTest { DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L); NetworkStats stats = new NetworkStats(TEST_START, 4) - .addEntry(entry1) - .addEntry(entry2) - .addEntry(entry3) - .addEntry(entry4); + .insertEntry(entry1) + .insertEntry(entry2) + .insertEntry(entry3) + .insertEntry(entry4); stats.filterDebugEntries(); @@ -891,14 +891,14 @@ public class NetworkStatsTest { 0 /* operations */); final NetworkStats statsXt = new NetworkStats(TEST_START, 3) - .addEntry(appEntry) - .addEntry(xtRootUidEntry) - .addEntry(otherEntry); + .insertEntry(appEntry) + .insertEntry(xtRootUidEntry) + .insertEntry(otherEntry); final NetworkStats statsEbpf = new NetworkStats(TEST_START, 3) - .addEntry(appEntry) - .addEntry(ebpfRootUidEntry) - .addEntry(otherEntry); + .insertEntry(appEntry) + .insertEntry(ebpfRootUidEntry) + .insertEntry(otherEntry); statsXt.apply464xlatAdjustments(stackedIface, false); statsEbpf.apply464xlatAdjustments(stackedIface, true); @@ -945,8 +945,8 @@ public class NetworkStatsTest { 0 /* operations */); NetworkStats stats = new NetworkStats(TEST_START, 2) - .addEntry(firstEntry) - .addEntry(secondEntry); + .insertEntry(firstEntry) + .insertEntry(secondEntry); // Empty map: no adjustment stats.apply464xlatAdjustments(new ArrayMap<>(), false); diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index c21772a5d177..44216e804f6f 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -2464,8 +2464,8 @@ public class ConnectivityServiceTest { final MockNetworkFactory testFactory = new MockNetworkFactory(handlerThread.getLooper(), mServiceContext, "testFactory", filter); // Register the factory and don't be surprised when the default request arrives. - testFactory.register(); testFactory.expectAddRequestsWithScores(0); + testFactory.register(); testFactory.waitForNetworkRequests(1); testFactory.setScoreFilter(42); diff --git a/tests/net/java/com/android/server/net/NetworkStatsObserversTest.java b/tests/net/java/com/android/server/net/NetworkStatsObserversTest.java index f0e5774a5dea..a6f7a36ff01b 100644 --- a/tests/net/java/com/android/server/net/NetworkStatsObserversTest.java +++ b/tests/net/java/com/android/server/net/NetworkStatsObserversTest.java @@ -240,7 +240,7 @@ public class NetworkStatsObserversTest { // Baseline NetworkStats xtSnapshot = new NetworkStats(TEST_START, 1 /* initialSize */) - .addIfaceValues(TEST_IFACE, BASE_BYTES, 8L, BASE_BYTES, 16L); + .insertEntry(TEST_IFACE, BASE_BYTES, 8L, BASE_BYTES, 16L); NetworkStats uidSnapshot = null; mStatsObservers.updateStats( @@ -264,14 +264,14 @@ public class NetworkStatsObserversTest { // Baseline NetworkStats xtSnapshot = new NetworkStats(TEST_START, 1 /* initialSize */) - .addIfaceValues(TEST_IFACE, BASE_BYTES, 8L, BASE_BYTES, 16L); + .insertEntry(TEST_IFACE, BASE_BYTES, 8L, BASE_BYTES, 16L); NetworkStats uidSnapshot = null; mStatsObservers.updateStats( xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces, TEST_START); // Delta xtSnapshot = new NetworkStats(TEST_START, 1 /* initialSize */) - .addIfaceValues(TEST_IFACE, BASE_BYTES + 1024L, 10L, BASE_BYTES + 2048L, 20L); + .insertEntry(TEST_IFACE, BASE_BYTES + 1024L, 10L, BASE_BYTES + 2048L, 20L); mStatsObservers.updateStats( xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces, TEST_START); waitForObserverToIdle(); @@ -294,14 +294,14 @@ public class NetworkStatsObserversTest { // Baseline NetworkStats xtSnapshot = new NetworkStats(TEST_START, 1 /* initialSize */) - .addIfaceValues(TEST_IFACE, BASE_BYTES, 8L, BASE_BYTES, 16L); + .insertEntry(TEST_IFACE, BASE_BYTES, 8L, BASE_BYTES, 16L); NetworkStats uidSnapshot = null; mStatsObservers.updateStats( xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces, TEST_START); // Delta xtSnapshot = new NetworkStats(TEST_START + MINUTE_IN_MILLIS, 1 /* initialSize */) - .addIfaceValues(TEST_IFACE, BASE_BYTES + THRESHOLD_BYTES, 12L, + .insertEntry(TEST_IFACE, BASE_BYTES + THRESHOLD_BYTES, 12L, BASE_BYTES + THRESHOLD_BYTES, 22L); mStatsObservers.updateStats( xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces, TEST_START); @@ -326,14 +326,14 @@ public class NetworkStatsObserversTest { // Baseline NetworkStats xtSnapshot = null; NetworkStats uidSnapshot = new NetworkStats(TEST_START, 2 /* initialSize */) - .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, BASE_BYTES, 2L, BASE_BYTES, 2L, 0L); mStatsObservers.updateStats( xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces, TEST_START); // Delta uidSnapshot = new NetworkStats(TEST_START + 2 * MINUTE_IN_MILLIS, 2 /* initialSize */) - .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, BASE_BYTES + THRESHOLD_BYTES, 2L, BASE_BYTES + THRESHOLD_BYTES, 2L, 0L); mStatsObservers.updateStats( @@ -359,14 +359,14 @@ public class NetworkStatsObserversTest { // Baseline NetworkStats xtSnapshot = null; NetworkStats uidSnapshot = new NetworkStats(TEST_START, 2 /* initialSize */) - .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, BASE_BYTES, 2L, BASE_BYTES, 2L, 0L); mStatsObservers.updateStats( xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces, TEST_START); // Delta uidSnapshot = new NetworkStats(TEST_START + 2 * MINUTE_IN_MILLIS, 2 /* initialSize */) - .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, BASE_BYTES + THRESHOLD_BYTES, 2L, BASE_BYTES + THRESHOLD_BYTES, 2L, 0L); mStatsObservers.updateStats( @@ -391,14 +391,14 @@ public class NetworkStatsObserversTest { // Baseline NetworkStats xtSnapshot = null; NetworkStats uidSnapshot = new NetworkStats(TEST_START, 2 /* initialSize */) - .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, BASE_BYTES, 2L, BASE_BYTES, 2L, 0L); mStatsObservers.updateStats( xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces, TEST_START); // Delta uidSnapshot = new NetworkStats(TEST_START + 2 * MINUTE_IN_MILLIS, 2 /* initialSize */) - .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, BASE_BYTES + THRESHOLD_BYTES, 2L, BASE_BYTES + THRESHOLD_BYTES, 2L, 0L); mStatsObservers.updateStats( @@ -424,14 +424,14 @@ public class NetworkStatsObserversTest { // Baseline NetworkStats xtSnapshot = null; NetworkStats uidSnapshot = new NetworkStats(TEST_START, 2 /* initialSize */) - .addEntry(TEST_IFACE, UID_ANOTHER_USER, SET_DEFAULT, TAG_NONE, METERED_NO, + .insertEntry(TEST_IFACE, UID_ANOTHER_USER, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, BASE_BYTES, 2L, BASE_BYTES, 2L, 0L); mStatsObservers.updateStats( xtSnapshot, uidSnapshot, mActiveIfaces, mActiveUidIfaces, TEST_START); // Delta uidSnapshot = new NetworkStats(TEST_START + 2 * MINUTE_IN_MILLIS, 2 /* initialSize */) - .addEntry(TEST_IFACE, UID_ANOTHER_USER, SET_DEFAULT, TAG_NONE, METERED_NO, + .insertEntry(TEST_IFACE, UID_ANOTHER_USER, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, BASE_BYTES + THRESHOLD_BYTES, 2L, BASE_BYTES + THRESHOLD_BYTES, 2L, 0L); mStatsObservers.updateStats( diff --git a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java index 36deca3e37b7..b346c923914e 100644 --- a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java +++ b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java @@ -263,7 +263,7 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { incrementCurrentTime(HOUR_IN_MILLIS); expectDefaultSettings(); expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1) - .addIfaceValues(TEST_IFACE, 1024L, 1L, 2048L, 2L)); + .insertEntry(TEST_IFACE, 1024L, 1L, 2048L, 2L)); expectNetworkStatsUidDetail(buildEmptyStats()); forcePollAndWaitForIdle(); @@ -276,7 +276,7 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { incrementCurrentTime(DAY_IN_MILLIS); expectDefaultSettings(); expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1) - .addIfaceValues(TEST_IFACE, 4096L, 4L, 8192L, 8L)); + .insertEntry(TEST_IFACE, 4096L, 4L, 8192L, 8L)); expectNetworkStatsUidDetail(buildEmptyStats()); forcePollAndWaitForIdle(); @@ -306,13 +306,13 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { incrementCurrentTime(HOUR_IN_MILLIS); expectDefaultSettings(); expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1) - .addIfaceValues(TEST_IFACE, 1024L, 8L, 2048L, 16L)); + .insertEntry(TEST_IFACE, 1024L, 8L, 2048L, 16L)); expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 2) - .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 512L, 4L, 256L, 2L, 0L) - .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xFAAD, 256L, 2L, 128L, 1L, 0L) - .addEntry(TEST_IFACE, UID_RED, SET_FOREGROUND, TAG_NONE, 512L, 4L, 256L, 2L, 0L) - .addEntry(TEST_IFACE, UID_RED, SET_FOREGROUND, 0xFAAD, 256L, 2L, 128L, 1L, 0L) - .addEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 128L, 1L, 128L, 1L, 0L)); + .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 512L, 4L, 256L, 2L, 0L) + .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xFAAD, 256L, 2L, 128L, 1L, 0L) + .insertEntry(TEST_IFACE, UID_RED, SET_FOREGROUND, TAG_NONE, 512L, 4L, 256L, 2L, 0L) + .insertEntry(TEST_IFACE, UID_RED, SET_FOREGROUND, 0xFAAD, 256L, 2L, 128L, 1L, 0L) + .insertEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 128L, 1L, 128L, 1L, 0L)); mService.setUidForeground(UID_RED, false); mService.incrementOperationCount(UID_RED, 0xFAAD, 4); mService.setUidForeground(UID_RED, true); @@ -375,7 +375,7 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { incrementCurrentTime(2 * HOUR_IN_MILLIS); expectSettings(0L, HOUR_IN_MILLIS, WEEK_IN_MILLIS); expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1) - .addIfaceValues(TEST_IFACE, 512L, 4L, 512L, 4L)); + .insertEntry(TEST_IFACE, 512L, 4L, 512L, 4L)); expectNetworkStatsUidDetail(buildEmptyStats()); forcePollAndWaitForIdle(); @@ -415,11 +415,11 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { incrementCurrentTime(HOUR_IN_MILLIS); expectDefaultSettings(); expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1) - .addIfaceValues(TEST_IFACE, 2048L, 16L, 512L, 4L)); + .insertEntry(TEST_IFACE, 2048L, 16L, 512L, 4L)); expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 3) - .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1536L, 12L, 512L, 4L, 0L) - .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L) - .addEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 512L, 4L, 0L, 0L, 0L)); + .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1536L, 12L, 512L, 4L, 0L) + .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L) + .insertEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 512L, 4L, 0L, 0L, 0L)); mService.incrementOperationCount(UID_RED, 0xF00D, 10); forcePollAndWaitForIdle(); @@ -437,11 +437,11 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { expectDefaultSettings(); states = new NetworkState[] {buildMobile3gState(IMSI_2)}; expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1) - .addIfaceValues(TEST_IFACE, 2048L, 16L, 512L, 4L)); + .insertEntry(TEST_IFACE, 2048L, 16L, 512L, 4L)); expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 3) - .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1536L, 12L, 512L, 4L, 0L) - .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L) - .addEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 512L, 4L, 0L, 0L, 0L)); + .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1536L, 12L, 512L, 4L, 0L) + .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L) + .insertEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 512L, 4L, 0L, 0L, 0L)); mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states), new VpnInfo[0]); forcePollAndWaitForIdle(); @@ -451,12 +451,12 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { incrementCurrentTime(HOUR_IN_MILLIS); expectDefaultSettings(); expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1) - .addIfaceValues(TEST_IFACE, 2176L, 17L, 1536L, 12L)); + .insertEntry(TEST_IFACE, 2176L, 17L, 1536L, 12L)); expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1) - .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1536L, 12L, 512L, 4L, 0L) - .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L) - .addEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 640L, 5L, 1024L, 8L, 0L) - .addEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, 0xFAAD, 128L, 1L, 1024L, 8L, 0L)); + .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1536L, 12L, 512L, 4L, 0L) + .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L) + .insertEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 640L, 5L, 1024L, 8L, 0L) + .insertEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, 0xFAAD, 128L, 1L, 1024L, 8L, 0L)); mService.incrementOperationCount(UID_BLUE, 0xFAAD, 10); forcePollAndWaitForIdle(); @@ -488,12 +488,13 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { incrementCurrentTime(HOUR_IN_MILLIS); expectDefaultSettings(); expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1) - .addIfaceValues(TEST_IFACE, 4128L, 258L, 544L, 34L)); + .insertEntry(TEST_IFACE, 4128L, 258L, 544L, 34L)); expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1) - .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 16L, 1L, 16L, 1L, 0L) - .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xFAAD, 16L, 1L, 16L, 1L, 0L) - .addEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 4096L, 258L, 512L, 32L, 0L) - .addEntry(TEST_IFACE, UID_GREEN, SET_DEFAULT, TAG_NONE, 16L, 1L, 16L, 1L, 0L)); + .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 16L, 1L, 16L, 1L, 0L) + .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xFAAD, 16L, 1L, 16L, 1L, 0L) + .insertEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, + 4096L, 258L, 512L, 32L, 0L) + .insertEntry(TEST_IFACE, UID_GREEN, SET_DEFAULT, TAG_NONE, 16L, 1L, 16L, 1L, 0L)); mService.incrementOperationCount(UID_RED, 0xFAAD, 10); forcePollAndWaitForIdle(); @@ -509,12 +510,13 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { // special "removed" bucket. expectDefaultSettings(); expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1) - .addIfaceValues(TEST_IFACE, 4128L, 258L, 544L, 34L)); + .insertEntry(TEST_IFACE, 4128L, 258L, 544L, 34L)); expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1) - .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 16L, 1L, 16L, 1L, 0L) - .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xFAAD, 16L, 1L, 16L, 1L, 0L) - .addEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 4096L, 258L, 512L, 32L, 0L) - .addEntry(TEST_IFACE, UID_GREEN, SET_DEFAULT, TAG_NONE, 16L, 1L, 16L, 1L, 0L)); + .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 16L, 1L, 16L, 1L, 0L) + .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xFAAD, 16L, 1L, 16L, 1L, 0L) + .insertEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, + 4096L, 258L, 512L, 32L, 0L) + .insertEntry(TEST_IFACE, UID_GREEN, SET_DEFAULT, TAG_NONE, 16L, 1L, 16L, 1L, 0L)); final Intent intent = new Intent(ACTION_UID_REMOVED); intent.putExtra(EXTRA_UID, UID_BLUE); mServiceContext.sendBroadcast(intent); @@ -546,8 +548,8 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { expectDefaultSettings(); expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1) - .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 0L) - .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L)); + .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 0L) + .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L)); mService.incrementOperationCount(UID_RED, 0xF00D, 5); forcePollAndWaitForIdle(); @@ -562,8 +564,8 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { states = new NetworkState[] {buildMobile4gState(TEST_IFACE2)}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1) - .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 0L) - .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L)); + .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 0L) + .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L)); mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states), new VpnInfo[0]); forcePollAndWaitForIdle(); @@ -574,10 +576,10 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { expectDefaultSettings(); expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1) - .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 0L) - .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L) - .addEntry(TEST_IFACE2, UID_RED, SET_DEFAULT, TAG_NONE, 512L, 4L, 256L, 2L, 0L) - .addEntry(TEST_IFACE2, UID_RED, SET_DEFAULT, 0xFAAD, 512L, 4L, 256L, 2L, 0L)); + .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 0L) + .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L) + .insertEntry(TEST_IFACE2, UID_RED, SET_DEFAULT, TAG_NONE, 512L, 4L, 256L, 2L, 0L) + .insertEntry(TEST_IFACE2, UID_RED, SET_DEFAULT, 0xFAAD, 512L, 4L, 256L, 2L, 0L)); mService.incrementOperationCount(UID_RED, 0xFAAD, 5); forcePollAndWaitForIdle(); @@ -601,9 +603,9 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { expectDefaultSettings(); expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1) - .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 50L, 5L, 50L, 5L, 0L) - .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 10L, 1L, 10L, 1L, 0L) - .addEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 1024L, 8L, 512L, 4L, 0L)); + .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 50L, 5L, 50L, 5L, 0L) + .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 10L, 1L, 10L, 1L, 0L) + .insertEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 1024L, 8L, 512L, 4L, 0L)); mService.incrementOperationCount(UID_RED, 0xF00D, 1); forcePollAndWaitForIdle(); @@ -618,9 +620,10 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { expectDefaultSettings(); expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1) - .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 50L, 5L, 50L, 5L, 0L) - .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 10L, 1L, 10L, 1L, 0L) - .addEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 2048L, 16L, 1024L, 8L, 0L)); + .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 50L, 5L, 50L, 5L, 0L) + .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 10L, 1L, 10L, 1L, 0L) + .insertEntry(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, + 2048L, 16L, 1024L, 8L, 0L)); forcePollAndWaitForIdle(); // first verify entire history present @@ -664,9 +667,9 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { expectDefaultSettings(); expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 3) - .addEntry(entry1) - .addEntry(entry2) - .addEntry(entry3)); + .insertEntry(entry1) + .insertEntry(entry2) + .insertEntry(entry3)); mService.incrementOperationCount(UID_RED, 0xF00D, 1); NetworkStats stats = mService.getDetailedUidStats(INTERFACES_ALL); @@ -714,11 +717,11 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { .thenReturn(augmentedIfaceFilter); when(mStatsFactory.readNetworkStatsDetail(eq(UID_ALL), any(), eq(TAG_ALL))) .thenReturn(new NetworkStats(getElapsedRealtime(), 1) - .addEntry(uidStats)); + .insertEntry(uidStats)); when(mNetManager.getNetworkStatsTethering(STATS_PER_UID)) .thenReturn(new NetworkStats(getElapsedRealtime(), 2) - .addEntry(tetheredStats1) - .addEntry(tetheredStats2)); + .insertEntry(tetheredStats1) + .insertEntry(tetheredStats2)); NetworkStats stats = mService.getDetailedUidStats(ifaceFilter); @@ -755,8 +758,8 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { expectDefaultSettings(); expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1) - .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 128L, 2L, 128L, 2L, 0L) - .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 64L, 1L, 64L, 1L, 0L)); + .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 128L, 2L, 128L, 2L, 0L) + .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 64L, 1L, 64L, 1L, 0L)); mService.incrementOperationCount(UID_RED, 0xF00D, 1); forcePollAndWaitForIdle(); @@ -770,10 +773,10 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { expectDefaultSettings(); expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1) - .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 128L, 2L, 128L, 2L, 0L) - .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 64L, 1L, 64L, 1L, 0L) - .addEntry(TEST_IFACE, UID_RED, SET_FOREGROUND, TAG_NONE, 32L, 2L, 32L, 2L, 0L) - .addEntry(TEST_IFACE, UID_RED, SET_FOREGROUND, 0xFAAD, 1L, 1L, 1L, 1L, 0L)); + .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 128L, 2L, 128L, 2L, 0L) + .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 64L, 1L, 64L, 1L, 0L) + .insertEntry(TEST_IFACE, UID_RED, SET_FOREGROUND, TAG_NONE, 32L, 2L, 32L, 2L, 0L) + .insertEntry(TEST_IFACE, UID_RED, SET_FOREGROUND, 0xFAAD, 1L, 1L, 1L, 1L, 0L)); mService.setUidForeground(UID_RED, true); mService.incrementOperationCount(UID_RED, 0xFAAD, 1); @@ -814,9 +817,9 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { // and DEFAULT_NETWORK_YES, because these three properties aren't tracked at that layer. // We layer them on top by inspecting the iface properties. expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1) - .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, 128L, 2L, 128L, 2L, 0L) - .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO, + .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_YES, 64L, 1L, 64L, 1L, 0L)); mService.incrementOperationCount(UID_RED, 0xF00D, 1); @@ -853,9 +856,9 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { // ROAMING_NO, because metered and roaming isn't tracked at that layer. We layer it // on top by inspecting the iface properties. expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1) - .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_ALL, ROAMING_NO, + .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_ALL, ROAMING_NO, DEFAULT_NETWORK_YES, 128L, 2L, 128L, 2L, 0L) - .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, METERED_ALL, ROAMING_NO, + .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, METERED_ALL, ROAMING_NO, DEFAULT_NETWORK_YES, 64L, 1L, 64L, 1L, 0L)); forcePollAndWaitForIdle(); @@ -888,17 +891,17 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { // Traffic seen by kernel counters (includes software tethering). final NetworkStats ifaceStats = new NetworkStats(getElapsedRealtime(), 1) - .addIfaceValues(TEST_IFACE, 1536L, 12L, 384L, 3L); + .insertEntry(TEST_IFACE, 1536L, 12L, 384L, 3L); // Hardware tethering traffic, not seen by kernel counters. final NetworkStats tetherStatsHardware = new NetworkStats(getElapsedRealtime(), 1) - .addIfaceValues(TEST_IFACE, 512L, 4L, 128L, 1L); + .insertEntry(TEST_IFACE, 512L, 4L, 128L, 1L); // Traffic for UID_RED. final NetworkStats uidStats = new NetworkStats(getElapsedRealtime(), 1) - .addEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 128L, 2L, 128L, 2L, 0L); + .insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 128L, 2L, 128L, 2L, 0L); // All tethering traffic, both hardware and software. final NetworkStats tetherStats = new NetworkStats(getElapsedRealtime(), 1) - .addEntry(TEST_IFACE, UID_TETHERING, SET_DEFAULT, TAG_NONE, 1920L, 14L, 384L, 2L, + .insertEntry(TEST_IFACE, UID_TETHERING, SET_DEFAULT, TAG_NONE, 1920L, 14L, 384L, 2L, 0L); expectNetworkStatsSummary(ifaceStats, tetherStatsHardware); @@ -957,7 +960,7 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { incrementCurrentTime(HOUR_IN_MILLIS); expectDefaultSettings(); expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1) - .addIfaceValues(TEST_IFACE, 1024L, 1L, 2048L, 2L)); + .insertEntry(TEST_IFACE, 1024L, 1L, 2048L, 2L)); expectNetworkStatsUidDetail(buildEmptyStats()); forcePollAndWaitForIdle(); @@ -972,7 +975,7 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { incrementCurrentTime(DAY_IN_MILLIS); expectDefaultSettings(); expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1) - .addIfaceValues(TEST_IFACE, 4096000L, 4L, 8192000L, 8L)); + .insertEntry(TEST_IFACE, 4096000L, 4L, 8192000L, 8L)); expectNetworkStatsUidDetail(buildEmptyStats()); forcePollAndWaitForIdle(); @@ -1026,18 +1029,18 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { mService.forceUpdateIfaces(NETWORKS_WIFI, states, getActiveIface(states), new VpnInfo[0]); // Verifies that one requestStatsUpdate will be called during iface update. - provider.expectStatsUpdate(0 /* unused */); + provider.expectOnRequestStatsUpdate(0 /* unused */); // Create some initial traffic and report to the service. incrementCurrentTime(HOUR_IN_MILLIS); final NetworkStats expectedStats = new NetworkStats(0L, 1) - .addValues(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_DEFAULT, + .addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO, DEFAULT_NETWORK_YES, 128L, 2L, 128L, 2L, 1L)) - .addValues(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_DEFAULT, + .addEntry(new NetworkStats.Entry(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, METERED_YES, ROAMING_NO, DEFAULT_NETWORK_YES, 64L, 1L, 64L, 1L, 1L)); - cb.onStatsUpdated(0 /* unused */, expectedStats, expectedStats); + cb.notifyStatsUpdated(0 /* unused */, expectedStats, expectedStats); // Make another empty mutable stats object. This is necessary since the new NetworkStats // object will be used to compare with the old one in NetworkStatsRecoder, two of them @@ -1047,8 +1050,8 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { forcePollAndWaitForIdle(); // Verifies that one requestStatsUpdate and setAlert will be called during polling. - provider.expectStatsUpdate(0 /* unused */); - provider.expectSetAlert(MB_IN_BYTES); + provider.expectOnRequestStatsUpdate(0 /* unused */); + provider.expectOnSetAlert(MB_IN_BYTES); // Verifies that service recorded history, does not verify uid tag part. assertUidTotal(sTemplateWifi, UID_RED, 128L, 2L, 128L, 2L, 1); @@ -1082,13 +1085,13 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest { assertNotNull(cb); // Simulates alert quota of the provider has been reached. - cb.onAlertReached(); + cb.notifyAlertReached(); HandlerUtilsKt.waitForIdle(mHandlerThread, WAIT_TIMEOUT); // Verifies that polling is triggered by alert reached. - provider.expectStatsUpdate(0 /* unused */); + provider.expectOnRequestStatsUpdate(0 /* unused */); // Verifies that global alert will be re-armed. - provider.expectSetAlert(MB_IN_BYTES); + provider.expectOnSetAlert(MB_IN_BYTES); } private static File getBaseDir(File statsDir) { diff --git a/wifi/Android.bp b/wifi/Android.bp index f4d28817a7f2..70c274128266 100644 --- a/wifi/Android.bp +++ b/wifi/Android.bp @@ -72,8 +72,7 @@ test_access_hidden_api_whitelist = [ // classes before they are renamed. java_library { name: "framework-wifi-pre-jarjar", - // TODO(b/146757305): sdk_version should be "module_lib_current" - sdk_version: "core_current", + sdk_version: "module_current", static_libs: [ "framework-wifi-util-lib", "android.hardware.wifi-V1.0-java-constants", @@ -83,9 +82,6 @@ java_library { "unsupportedappusage", // for android.compat.annotation.UnsupportedAppUsage "unsupportedappusage-annotation", // for dalvik.annotation.compat.UnsupportedAppUsage "framework-telephony-stubs", - // TODO(b/146757305): should be unnecessary once - // sdk_version="module_lib_current" - "android_system_stubs_current", ], srcs: [ ":framework-wifi-updatable-sources", @@ -98,21 +94,12 @@ java_library { "//frameworks/opt/net/wifi/service", "//frameworks/opt/net/wifi/tests/wifitests", ], - - // TODO(b/146757305): should be unnecessary once - // sdk_version="module_lib_current" - aidl: { - include_dirs: [ - "frameworks/base/core/java", - ], - }, } // post-jarjar version of framework-wifi java_library { name: "framework-wifi", - // TODO(b/146757305): sdk_version should be "module_lib_current" - sdk_version: "core_current", + sdk_version: "module_current", static_libs: [ "framework-wifi-pre-jarjar", ], diff --git a/wifi/java/android/net/wifi/WifiMigration.java b/wifi/java/android/net/wifi/WifiMigration.java index 008b18bf04c3..f2a1aec550b1 100755 --- a/wifi/java/android/net/wifi/WifiMigration.java +++ b/wifi/java/android/net/wifi/WifiMigration.java @@ -16,25 +16,252 @@ package android.net.wifi; +import static android.os.Environment.getDataMiscCeDirectory; +import static android.os.Environment.getDataMiscDirectory; + +import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.content.Context; import android.os.Parcel; import android.os.Parcelable; +import android.os.UserHandle; import android.provider.Settings; +import android.util.AtomicFile; +import android.util.SparseArray; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.InputStream; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.Objects; /** * Class used to provide one time hooks for existing OEM devices to migrate their config store - * data and other settings to the wifi mainline module. + * data and other settings to the wifi apex. * @hide */ @SystemApi public final class WifiMigration { + /** + * Directory to read the wifi config store files from under. + */ + private static final String LEGACY_WIFI_STORE_DIRECTORY_NAME = "wifi"; + /** + * Config store file for general shared store file. + * AOSP Path on Android 10: /data/misc/wifi/WifiConfigStore.xml + */ + public static final int STORE_FILE_SHARED_GENERAL = 0; + /** + * Config store file for softap shared store file. + * AOSP Path on Android 10: /data/misc/wifi/softap.conf + */ + public static final int STORE_FILE_SHARED_SOFTAP = 1; + /** + * Config store file for general user store file. + * AOSP Path on Android 10: /data/misc_ce/<userId>/wifi/WifiConfigStore.xml + */ + public static final int STORE_FILE_USER_GENERAL = 2; + /** + * Config store file for network suggestions user store file. + * AOSP Path on Android 10: /data/misc_ce/<userId>/wifi/WifiConfigStoreNetworkSuggestions.xml + */ + public static final int STORE_FILE_USER_NETWORK_SUGGESTIONS = 3; + + /** @hide */ + @IntDef(prefix = { "STORE_FILE_SHARED_" }, value = { + STORE_FILE_SHARED_GENERAL, + STORE_FILE_SHARED_SOFTAP, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface SharedStoreFileId { } + + /** @hide */ + @IntDef(prefix = { "STORE_FILE_USER_" }, value = { + STORE_FILE_USER_GENERAL, + STORE_FILE_USER_NETWORK_SUGGESTIONS + }) + @Retention(RetentionPolicy.SOURCE) + public @interface UserStoreFileId { } + + /** + * Mapping of Store file Id to Store file names. + * + * NOTE: This is the default path for the files on AOSP devices. If the OEM has modified + * the path or renamed the files, please edit this appropriately. + */ + private static final SparseArray<String> STORE_ID_TO_FILE_NAME = + new SparseArray<String>() {{ + put(STORE_FILE_SHARED_GENERAL, "WifiConfigStore.xml"); + put(STORE_FILE_SHARED_SOFTAP, "softap.conf"); + put(STORE_FILE_USER_GENERAL, "WifiConfigStore.xml"); + put(STORE_FILE_USER_NETWORK_SUGGESTIONS, "WifiConfigStoreNetworkSuggestions.xml"); + }}; + + /** + * Pre-apex wifi shared folder. + */ + private static File getLegacyWifiSharedDirectory() { + return new File(getDataMiscDirectory(), LEGACY_WIFI_STORE_DIRECTORY_NAME); + } + + /** + * Pre-apex wifi user folder. + */ + private static File getLegacyWifiUserDirectory(int userId) { + return new File(getDataMiscCeDirectory(userId), LEGACY_WIFI_STORE_DIRECTORY_NAME); + } + + /** + * Legacy files were stored as AtomicFile. So, always use AtomicFile to operate on it to ensure + * data integrity. + */ + private static AtomicFile getSharedAtomicFile(@SharedStoreFileId int storeFileId) { + return new AtomicFile(new File( + getLegacyWifiSharedDirectory(), + STORE_ID_TO_FILE_NAME.get(storeFileId))); + } + + /** + * Legacy files were stored as AtomicFile. So, always use AtomicFile to operate on it to ensure + * data integrity. + */ + private static AtomicFile getUserAtomicFile(@UserStoreFileId int storeFileId, int userId) { + return new AtomicFile(new File( + getLegacyWifiUserDirectory(userId), + STORE_ID_TO_FILE_NAME.get(storeFileId))); + } private WifiMigration() { } /** + * Load data from legacy shared wifi config store file. + * TODO(b/149418926): Add XSD for the AOSP file format for each file from R. + * <p> + * Note: + * <li>OEMs need to change the implementation of + * {@link #convertAndRetrieveSharedConfigStoreFile(int)} only if their existing config store + * format or file locations differs from the vanilla AOSP implementation.</li> + * <li>The wifi apex will invoke + * {@link #convertAndRetrieveSharedConfigStoreFile(int)} + * method on every bootup, it is the responsibility of the OEM implementation to ensure that + * they perform the necessary in place conversion of their config store file to conform to the + * AOSP format. The OEM should ensure that the method should only return the + * {@link InputStream} stream for the data to be migrated only on the first bootup.</li> + * <li>Once the migration is done, the apex will invoke + * {@link #removeSharedConfigStoreFile(int)} to delete the store file.</li> + * <li>The only relevant invocation of {@link #convertAndRetrieveSharedConfigStoreFile(int)} + * occurs when a previously released device upgrades to the wifi apex from an OEM + * implementation of the wifi stack. + * <li>Ensure that the legacy file paths are accessible to the wifi module (sepolicy rules, file + * permissions, etc). Since the wifi service continues to run inside system_server process, this + * method will be called from the same context (so ideally the file should still be accessible). + * </li> + * + * @param storeFileId Identifier for the config store file. One of + * {@link #STORE_FILE_SHARED_GENERAL} or {@link #STORE_FILE_SHARED_GENERAL} + * @return Instance of {@link InputStream} for migrating data, null if no migration is + * necessary. + * @throws IllegalArgumentException on invalid storeFileId. + */ + @Nullable + public static InputStream convertAndRetrieveSharedConfigStoreFile( + @SharedStoreFileId int storeFileId) { + if (storeFileId != STORE_FILE_SHARED_GENERAL && storeFileId != STORE_FILE_SHARED_SOFTAP) { + throw new IllegalArgumentException("Invalid shared store file id"); + } + try { + // OEMs should do conversions necessary here before returning the stream. + return getSharedAtomicFile(storeFileId).openRead(); + } catch (FileNotFoundException e) { + return null; + } + } + + /** + * Remove the legacy shared wifi config store file. + * + * @param storeFileId Identifier for the config store file. One of + * {@link #STORE_FILE_SHARED_GENERAL} or {@link #STORE_FILE_SHARED_GENERAL} + * @throws IllegalArgumentException on invalid storeFileId. + */ + public static void removeSharedConfigStoreFile(@SharedStoreFileId int storeFileId) { + if (storeFileId != STORE_FILE_SHARED_GENERAL && storeFileId != STORE_FILE_SHARED_SOFTAP) { + throw new IllegalArgumentException("Invalid shared store file id"); + } + getSharedAtomicFile(storeFileId).delete(); + } + + /** + * Load data from legacy user wifi config store file. + * TODO(b/149418926): Add XSD for the AOSP file format for each file from R. + * <p> + * Note: + * <li>OEMs need to change the implementation of + * {@link #convertAndRetrieveUserConfigStoreFile(int, UserHandle)} only if their existing config + * store format or file locations differs from the vanilla AOSP implementation.</li> + * <li>The wifi apex will invoke + * {@link #convertAndRetrieveUserConfigStoreFile(int, UserHandle)} + * method on every bootup, it is the responsibility of the OEM implementation to ensure that + * they perform the necessary in place conversion of their config store file to conform to the + * AOSP format. The OEM should ensure that the method should only return the + * {@link InputStream} stream for the data to be migrated only on the first bootup.</li> + * <li>Once the migration is done, the apex will invoke + * {@link #removeUserConfigStoreFile(int, UserHandle)} to delete the store file.</li> + * <li>The only relevant invocation of + * {@link #convertAndRetrieveUserConfigStoreFile(int, UserHandle)} occurs when a previously + * released device upgrades to the wifi apex from an OEM implementation of the wifi + * stack. + * </li> + * <li>Ensure that the legacy file paths are accessible to the wifi module (sepolicy rules, file + * permissions, etc). Since the wifi service continues to run inside system_server process, this + * method will be called from the same context (so ideally the file should still be accessible). + * </li> + * + * @param storeFileId Identifier for the config store file. One of + * {@link #STORE_FILE_USER_GENERAL} or {@link #STORE_FILE_USER_NETWORK_SUGGESTIONS} + * @param userHandle User handle. + * @return Instance of {@link InputStream} for migrating data, null if no migration is + * necessary. + * @throws IllegalArgumentException on invalid storeFileId or userHandle. + */ + @Nullable + public static InputStream convertAndRetrieveUserConfigStoreFile( + @UserStoreFileId int storeFileId, @NonNull UserHandle userHandle) { + if (storeFileId != STORE_FILE_USER_GENERAL + && storeFileId != STORE_FILE_USER_NETWORK_SUGGESTIONS) { + throw new IllegalArgumentException("Invalid user store file id"); + } + Objects.requireNonNull(userHandle); + try { + // OEMs should do conversions necessary here before returning the stream. + return getUserAtomicFile(storeFileId, userHandle.getIdentifier()).openRead(); + } catch (FileNotFoundException e) { + return null; + } + } + + /** + * Remove the legacy user wifi config store file. + * + * @param storeFileId Identifier for the config store file. One of + * {@link #STORE_FILE_USER_GENERAL} or {@link #STORE_FILE_USER_NETWORK_SUGGESTIONS} + * @param userHandle User handle. + * @throws IllegalArgumentException on invalid storeFileId or userHandle. + */ + public static void removeUserConfigStoreFile( + @UserStoreFileId int storeFileId, @NonNull UserHandle userHandle) { + if (storeFileId != STORE_FILE_USER_GENERAL + && storeFileId != STORE_FILE_USER_NETWORK_SUGGESTIONS) { + throw new IllegalArgumentException("Invalid user store file id"); + } + Objects.requireNonNull(userHandle); + getUserAtomicFile(storeFileId, userHandle.getIdentifier()).delete(); + } + + /** * Container for all the wifi settings data to migrate. */ public static final class SettingsMigrationData implements Parcelable { @@ -260,7 +487,7 @@ public final class WifiMigration { * <li> This is method is invoked once on the first bootup. OEM can safely delete these settings * once the migration is complete. The first & only relevant invocation of * {@link #loadFromSettings(Context)} ()} occurs when a previously released - * device upgrades to the wifi mainline module from an OEM implementation of the wifi stack. + * device upgrades to the wifi apex from an OEM implementation of the wifi stack. * </li> * * @param context Context to use for loading the settings provider. |