diff options
156 files changed, 6420 insertions, 1580 deletions
diff --git a/StubLibraries.bp b/StubLibraries.bp index ed8781e2ff86..64ee09cf5e05 100644 --- a/StubLibraries.bp +++ b/StubLibraries.bp @@ -120,6 +120,20 @@ droidstubs { new_since: ":android-non-updatable.api.public.latest", }, }, + dists: [ + { + targets: ["sdk", "win_sdk"], + dir: "apistubs/android/public/api", + dest: "android-non-updatable.txt", + tag: ".api.txt", + }, + { + targets: ["sdk", "win_sdk"], + dir: "apistubs/android/public/api", + dest: "android-non-updatable-removed.txt", + tag: ".removed-api.txt", + }, + ], } priv_apps = @@ -159,6 +173,20 @@ droidstubs { baseline_file: "core/api/system-lint-baseline.txt", }, }, + dists: [ + { + targets: ["sdk", "win_sdk"], + dir: "apistubs/android/system/api", + dest: "android-non-updatable.txt", + tag: ".api.txt", + }, + { + targets: ["sdk", "win_sdk"], + dir: "apistubs/android/system/api", + dest: "android-non-updatable-removed.txt", + tag: ".removed-api.txt", + }, + ], } droidstubs { @@ -175,11 +203,32 @@ droidstubs { baseline_file: "core/api/test-lint-baseline.txt", }, }, - dist: { - targets: ["sdk", "win_sdk"], - dir: "apistubs/android/test/api", - dest: "android.txt", - }, + dists: [ + { + targets: ["sdk", "win_sdk"], + dir: "apistubs/android/test/api", + dest: "android.txt", + tag: ".api.txt", + }, + { + targets: ["sdk", "win_sdk"], + dir: "apistubs/android/test/api", + dest: "removed.txt", + tag: ".removed-api.txt", + }, + { + targets: ["sdk", "win_sdk"], + dir: "apistubs/android/test/api", + dest: "android-non-updatable.txt", + tag: ".api.txt", + }, + { + targets: ["sdk", "win_sdk"], + dir: "apistubs/android/test/api", + dest: "android-non-updatable-removed.txt", + tag: ".removed-api.txt", + }, + ], } droidstubs { @@ -200,6 +249,20 @@ droidstubs { new_since: ":android-non-updatable.api.module-lib.latest", }, }, + dists: [ + { + targets: ["sdk", "win_sdk"], + dir: "apistubs/android/module-lib/api", + dest: "android-non-updatable.txt", + tag: ".api.txt", + }, + { + targets: ["sdk", "win_sdk"], + dir: "apistubs/android/module-lib/api", + dest: "android-non-updatable-removed.txt", + tag: ".removed-api.txt", + }, + ], } ///////////////////////////////////////////////////////////////////// diff --git a/apct-tests/perftests/OWNERS b/apct-tests/perftests/OWNERS index a060ad9a5a7e..7e7feafdc5a5 100644 --- a/apct-tests/perftests/OWNERS +++ b/apct-tests/perftests/OWNERS @@ -1,2 +1,11 @@ -timmurray@google.com +balejs@google.com +carmenjackson@google.com +cfijalkovich@google.com +dualli@google.com +edgararriaga@google.com +jpakaravoor@google.com +kevinjeon@google.com philipcuadra@google.com +shombert@google.com +timmurray@google.com +wessam@google.com diff --git a/apex/OWNERS b/apex/OWNERS index 97600135a103..bde2bec0816b 100644 --- a/apex/OWNERS +++ b/apex/OWNERS @@ -1,7 +1,8 @@ -# Shared module build rule owners -per-file *.bp=hansson@google.com -per-file *.bp=jiyong@google.com +# Mainline modularization team -# This file, and all other OWNERS files -per-file OWNERS=dariofreni@google.com -per-file OWNERS=hansson@google.com +andreionea@google.com +dariofreni@google.com +hansson@google.com +mathewi@google.com +pedroql@google.com +satayev@google.com diff --git a/api/Android.bp b/api/Android.bp index 9a157b8a0578..fdfef4cb8a74 100644 --- a/api/Android.bp +++ b/api/Android.bp @@ -50,10 +50,7 @@ genrule { dest: "current.txt", }, { - targets: [ - "sdk", - "win_sdk", - ], + targets: ["sdk", "win_sdk"], dir: "apistubs/android/public/api", dest: "android.txt", }, @@ -106,6 +103,11 @@ genrule { dir: "api", dest: "removed.txt", }, + { + targets: ["sdk", "win_sdk"], + dir: "apistubs/android/public/api", + dest: "removed.txt", + }, ], } @@ -131,10 +133,7 @@ genrule { dest: "system-current.txt", }, { - targets: [ - "sdk", - "win_sdk", - ], + targets: ["sdk", "win_sdk"], dir: "apistubs/android/system/api", dest: "android.txt", }, @@ -163,6 +162,11 @@ genrule { dir: "api", dest: "system-removed.txt", }, + { + targets: ["sdk", "win_sdk"], + dir: "apistubs/android/system/api", + dest: "removed.txt", + }, ], visibility: ["//visibility:public"], } @@ -189,10 +193,7 @@ genrule { dest: "module-lib-current.txt", }, { - targets: [ - "sdk", - "win_sdk", - ], + targets: ["sdk", "win_sdk"], dir: "apistubs/android/module-lib/api", dest: "android.txt", }, @@ -220,6 +221,11 @@ genrule { dir: "api", dest: "module-lib-removed.txt", }, + { + targets: ["sdk", "win_sdk"], + dir: "apistubs/android/module-lib/api", + dest: "removed.txt", + }, ], } diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java index bdb83804d903..846a34eb41c9 100644 --- a/cmds/am/src/com/android/commands/am/Am.java +++ b/cmds/am/src/com/android/commands/am/Am.java @@ -174,10 +174,6 @@ public class Am extends BaseCommand { instrument.noWindowAnimation = true; } else if (opt.equals("--no-hidden-api-checks")) { instrument.disableHiddenApiChecks = true; - } else if (opt.equals("--no-test-api-checks")) { - // TODO(satayev): remove this option, only kept for backwards compatibility with - // cached tradefed instance - instrument.disableTestApiChecks = false; } else if (opt.equals("--no-test-api-access")) { instrument.disableTestApiChecks = false; } else if (opt.equals("--no-isolated-storage")) { @@ -198,7 +194,6 @@ public class Am extends BaseCommand { } instrument.componentNameArg = nextArgRequired(); - instrument.run(); } } diff --git a/cmds/app_process/Android.bp b/cmds/app_process/Android.bp index 07221f97c72b..14ebb713b6ae 100644 --- a/cmds/app_process/Android.bp +++ b/cmds/app_process/Android.bp @@ -62,4 +62,13 @@ cc_binary { // Create a symlink from app_process to app_process32 or 64 // depending on the target configuration. symlink_preferred_arch: true, + + // Enable ASYNC MTE in the zygote, in order to allow apps and the system + // server to use MTE. We use ASYNC because we don't expect the pre-fork + // zygote to have substantial memory corruption bugs (as it's primarily Java + // code), and we don't want to waste memory recording malloc/free stack + // traces (which happens in SYNC mode). + sanitize: { + memtag_heap: true, + }, } diff --git a/cmds/sm/src/com/android/commands/sm/Sm.java b/cmds/sm/src/com/android/commands/sm/Sm.java index c2ee6dcd13b2..405d6f6f5f63 100644 --- a/cmds/sm/src/com/android/commands/sm/Sm.java +++ b/cmds/sm/src/com/android/commands/sm/Sm.java @@ -107,6 +107,8 @@ public final class Sm { runStartCheckpoint(); } else if ("supports-checkpoint".equals(op)) { runSupportsCheckpoint(); + } else if ("unmount-app-data-dirs".equals(op)) { + runDisableAppDataIsolation(); } else { throw new IllegalArgumentException(); } @@ -253,6 +255,13 @@ public final class Sm { System.out.println(result.get()); } + public void runDisableAppDataIsolation() throws RemoteException { + final String pkgName = nextArg(); + final int pid = Integer.parseInt(nextArg()); + final int userId = Integer.parseInt(nextArg()); + mSm.disableAppDataIsolation(pkgName, pid, userId); + } + public void runForget() throws RemoteException { final String fsUuid = nextArg(); if ("all".equals(fsUuid)) { @@ -373,6 +382,8 @@ public final class Sm { System.err.println(""); System.err.println(" sm supports-checkpoint"); System.err.println(""); + System.err.println(" sm unmount-app-data-dirs PACKAGE_NAME PID USER_ID"); + System.err.println(""); return 1; } } diff --git a/core/api/current.txt b/core/api/current.txt index 60fe4882d51a..047761a0cbe9 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -10145,6 +10145,7 @@ package android.content { method public void sendOrderedBroadcast(@NonNull android.content.Intent, @Nullable String, @Nullable String, @Nullable android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle); method @RequiresPermission("android.permission.INTERACT_ACROSS_USERS") public abstract void sendOrderedBroadcastAsUser(@RequiresPermission android.content.Intent, android.os.UserHandle, @Nullable String, android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle); method @Deprecated @RequiresPermission(android.Manifest.permission.BROADCAST_STICKY) public abstract void sendStickyBroadcast(@RequiresPermission android.content.Intent); + method @Deprecated @RequiresPermission(android.Manifest.permission.BROADCAST_STICKY) public void sendStickyBroadcast(@NonNull @RequiresPermission android.content.Intent, @Nullable android.os.Bundle); method @Deprecated @RequiresPermission(allOf={"android.permission.INTERACT_ACROSS_USERS", android.Manifest.permission.BROADCAST_STICKY}) public abstract void sendStickyBroadcastAsUser(@RequiresPermission android.content.Intent, android.os.UserHandle); method @Deprecated @RequiresPermission(android.Manifest.permission.BROADCAST_STICKY) public abstract void sendStickyOrderedBroadcast(@RequiresPermission android.content.Intent, android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle); method @Deprecated @RequiresPermission(allOf={"android.permission.INTERACT_ACROSS_USERS", android.Manifest.permission.BROADCAST_STICKY}) public abstract void sendStickyOrderedBroadcastAsUser(@RequiresPermission android.content.Intent, android.os.UserHandle, android.content.BroadcastReceiver, @Nullable android.os.Handler, int, @Nullable String, @Nullable android.os.Bundle); @@ -10187,6 +10188,7 @@ package android.content { field public static final String BIOMETRIC_SERVICE = "biometric"; field public static final String BLOB_STORE_SERVICE = "blob_store"; field public static final String BLUETOOTH_SERVICE = "bluetooth"; + field public static final String BUGREPORT_SERVICE = "bugreport"; field public static final String CAMERA_SERVICE = "camera"; field public static final String CAPTIONING_SERVICE = "captioning"; field public static final String CARRIER_CONFIG_SERVICE = "carrier_config"; @@ -29596,6 +29598,24 @@ package android.os { method public boolean unlinkToDeath(@NonNull android.os.IBinder.DeathRecipient, int); } + public final class BugreportManager { + method public void cancelBugreport(); + method public void startConnectivityBugreport(@NonNull android.os.ParcelFileDescriptor, @NonNull java.util.concurrent.Executor, @NonNull android.os.BugreportManager.BugreportCallback); + } + + public abstract static class BugreportManager.BugreportCallback { + ctor public BugreportManager.BugreportCallback(); + method public void onEarlyReportFinished(); + method public void onError(int); + method public void onFinished(); + method public void onProgress(@FloatRange(from=0.0f, to=100.0f) float); + field public static final int BUGREPORT_ERROR_ANOTHER_REPORT_IN_PROGRESS = 5; // 0x5 + field public static final int BUGREPORT_ERROR_INVALID_INPUT = 1; // 0x1 + field public static final int BUGREPORT_ERROR_RUNTIME = 2; // 0x2 + field public static final int BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT = 4; // 0x4 + field public static final int BUGREPORT_ERROR_USER_DENIED_CONSENT = 3; // 0x3 + } + public class Build { ctor public Build(); method @NonNull public static java.util.List<android.os.Build.Partition> getFingerprintedPartitions(); @@ -33927,6 +33947,7 @@ package android.provider { field public static final String ACTION_LOCATION_SOURCE_SETTINGS = "android.settings.LOCATION_SOURCE_SETTINGS"; field public static final String ACTION_MANAGE_ALL_APPLICATIONS_SETTINGS = "android.settings.MANAGE_ALL_APPLICATIONS_SETTINGS"; field public static final String ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION = "android.settings.MANAGE_ALL_FILES_ACCESS_PERMISSION"; + field public static final String ACTION_MANAGE_ALL_SUBSCRIPTIONS_SETTINGS = "android.settings.MANAGE_ALL_SUBSCRIPTIONS_SETTINGS"; field public static final String ACTION_MANAGE_APPLICATIONS_SETTINGS = "android.settings.MANAGE_APPLICATIONS_SETTINGS"; field public static final String ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION = "android.settings.MANAGE_APP_ALL_FILES_ACCESS_PERMISSION"; field public static final String ACTION_MANAGE_DEFAULT_APPS_SETTINGS = "android.settings.MANAGE_DEFAULT_APPS_SETTINGS"; @@ -39229,6 +39250,7 @@ package android.telephony { field public static final int BAND_25 = 25; // 0x19 field public static final int BAND_257 = 257; // 0x101 field public static final int BAND_258 = 258; // 0x102 + field public static final int BAND_26 = 26; // 0x1a field public static final int BAND_260 = 260; // 0x104 field public static final int BAND_261 = 261; // 0x105 field public static final int BAND_28 = 28; // 0x1c @@ -39240,10 +39262,12 @@ package android.telephony { field public static final int BAND_39 = 39; // 0x27 field public static final int BAND_40 = 40; // 0x28 field public static final int BAND_41 = 41; // 0x29 + field public static final int BAND_46 = 46; // 0x2e field public static final int BAND_48 = 48; // 0x30 field public static final int BAND_5 = 5; // 0x5 field public static final int BAND_50 = 50; // 0x32 field public static final int BAND_51 = 51; // 0x33 + field public static final int BAND_53 = 53; // 0x35 field public static final int BAND_65 = 65; // 0x41 field public static final int BAND_66 = 66; // 0x42 field public static final int BAND_7 = 7; // 0x7 @@ -39269,6 +39293,7 @@ package android.telephony { field public static final int BAND_93 = 93; // 0x5d field public static final int BAND_94 = 94; // 0x5e field public static final int BAND_95 = 95; // 0x5f + field public static final int BAND_96 = 96; // 0x60 } public static final class AccessNetworkConstants.UtranBand { @@ -40706,17 +40731,27 @@ package android.telephony { public final class PhysicalChannelConfig implements android.os.Parcelable { method public int describeContents(); - method public int getCellBandwidthDownlink(); - method public int getChannelNumber(); + method @IntRange(from=1, to=261) public int getBand(); + method @IntRange(from=1) public int getCellBandwidthDownlinkKhz(); + method @IntRange(from=1) public int getCellBandwidthUplinkKhz(); + method @Deprecated public int getChannelNumber(); method public int getConnectionStatus(); + method @IntRange(from=0) public int getDownlinkChannelNumber(); + method @IntRange(from=0) public int getDownlinkFrequencyKhz(); method public int getNetworkType(); method @IntRange(from=0, to=1007) public int getPhysicalCellId(); + method @IntRange(from=0) public int getUplinkChannelNumber(); + method @IntRange(from=0) public int getUplinkFrequencyKhz(); method public void writeToParcel(@NonNull android.os.Parcel, int); + field public static final int BAND_UNKNOWN = 0; // 0x0 + field public static final int CELL_BANDWIDTH_UNKNOWN = 0; // 0x0 field public static final int CHANNEL_NUMBER_UNKNOWN = -1; // 0xffffffff field public static final int CONNECTION_PRIMARY_SERVING = 1; // 0x1 field public static final int CONNECTION_SECONDARY_SERVING = 2; // 0x2 field public static final int CONNECTION_UNKNOWN = -1; // 0xffffffff field @NonNull public static final android.os.Parcelable.Creator<android.telephony.PhysicalChannelConfig> CREATOR; + field public static final int FREQUENCY_UNKNOWN = -1; // 0xffffffff + field public static final int PHYSICAL_CELL_ID_MAXIMUM_VALUE = 1007; // 0x3ef field public static final int PHYSICAL_CELL_ID_UNKNOWN = -1; // 0xffffffff } @@ -40799,8 +40834,26 @@ package android.telephony { field public static final int INVALID = 2147483647; // 0x7fffffff } + public final class SignalStrengthUpdateRequest implements android.os.Parcelable { + method public int describeContents(); + method @NonNull public android.os.IBinder getLiveToken(); + method @NonNull public java.util.Collection<android.telephony.SignalThresholdInfo> getSignalThresholdInfos(); + method public boolean isReportingRequestedWhileIdle(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.telephony.SignalStrengthUpdateRequest> CREATOR; + } + + public static final class SignalStrengthUpdateRequest.Builder { + ctor public SignalStrengthUpdateRequest.Builder(); + method @NonNull public android.telephony.SignalStrengthUpdateRequest build(); + method @NonNull public android.telephony.SignalStrengthUpdateRequest.Builder setReportingRequestedWhileIdle(boolean); + method @NonNull public android.telephony.SignalStrengthUpdateRequest.Builder setSignalThresholdInfos(@NonNull java.util.Collection<android.telephony.SignalThresholdInfo>); + } + public final class SignalThresholdInfo implements android.os.Parcelable { method public int describeContents(); + method public static int getMaximumNumberOfThresholdsAllowed(); + method public static int getMinimumNumberOfThresholdsAllowed(); method public int getRadioAccessNetworkType(); method public int getSignalMeasurementType(); method @NonNull public int[] getThresholds(); @@ -41161,6 +41214,7 @@ package android.telephony { public class TelephonyManager { method public boolean canChangeDtmfToneLength(); + method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void clearSignalStrengthUpdateRequest(@NonNull android.telephony.SignalStrengthUpdateRequest); method @Nullable public android.telephony.TelephonyManager createForPhoneAccountHandle(android.telecom.PhoneAccountHandle); method public android.telephony.TelephonyManager createForSubscriptionId(int); method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public boolean doesSwitchMultiSimConfigTriggerReboot(); @@ -41239,7 +41293,7 @@ package android.telephony { method @Deprecated public String iccTransmitApduLogicalChannel(int, int, int, int, int, int, String); method public boolean isConcurrentVoiceAndDataSupported(); method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_NETWORK_STATE, android.Manifest.permission.READ_PHONE_STATE, "android.permission.READ_PRIVILEGED_PHONE_STATE"}) public boolean isDataConnectionAllowed(); - method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_NETWORK_STATE, android.Manifest.permission.MODIFY_PHONE_STATE}) public boolean isDataEnabled(); + method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_NETWORK_STATE, android.Manifest.permission.MODIFY_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isDataEnabled(); method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_NETWORK_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isDataEnabledForReason(int); method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_NETWORK_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isDataRoamingEnabled(); method public boolean isEmergencyNumber(@NonNull String); @@ -41273,6 +41327,7 @@ package android.telephony { method public boolean setOperatorBrandOverride(String); method public boolean setPreferredNetworkTypeToGlobal(); method public void setPreferredOpportunisticDataSubscription(int, boolean, @Nullable java.util.concurrent.Executor, @Nullable java.util.function.Consumer<java.lang.Integer>); + method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setSignalStrengthUpdateRequest(@NonNull android.telephony.SignalStrengthUpdateRequest); method public void setVisualVoicemailSmsFilterSettings(android.telephony.VisualVoicemailSmsFilterSettings); method public boolean setVoiceMailNumber(String, String); method @Deprecated public void setVoicemailRingtoneUri(android.telecom.PhoneAccountHandle, android.net.Uri); diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt index 9349770ee4fd..c19dd4ca4a8e 100644 --- a/core/api/module-lib-current.txt +++ b/core/api/module-lib-current.txt @@ -20,6 +20,22 @@ package android.net { field public final int sndWnd; } + public final class TestNetworkInterface implements android.os.Parcelable { + ctor public TestNetworkInterface(@NonNull android.os.ParcelFileDescriptor, @NonNull String); + method public int describeContents(); + method @NonNull public android.os.ParcelFileDescriptor getFileDescriptor(); + method @NonNull public String getInterfaceName(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.net.TestNetworkInterface> CREATOR; + } + + public class TestNetworkManager { + method @NonNull public android.net.TestNetworkInterface createTapInterface(); + method @NonNull public android.net.TestNetworkInterface createTunInterface(@NonNull java.util.Collection<android.net.LinkAddress>); + method public void setupTestNetwork(@NonNull String, @NonNull android.os.IBinder); + method public void teardownTestNetwork(@NonNull android.net.Network); + } + } package android.os { diff --git a/core/api/system-current.txt b/core/api/system-current.txt index e768ea6ed560..21d820308230 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -126,6 +126,7 @@ package android { field public static final String MANAGE_SENSOR_PRIVACY = "android.permission.MANAGE_SENSOR_PRIVACY"; field public static final String MANAGE_SOUND_TRIGGER = "android.permission.MANAGE_SOUND_TRIGGER"; field public static final String MANAGE_SUBSCRIPTION_PLANS = "android.permission.MANAGE_SUBSCRIPTION_PLANS"; + field public static final String MANAGE_TEST_NETWORKS = "android.permission.MANAGE_TEST_NETWORKS"; field public static final String MANAGE_USB = "android.permission.MANAGE_USB"; field public static final String MANAGE_USERS = "android.permission.MANAGE_USERS"; field public static final String MANAGE_USER_OEM_UNLOCK_STATE = "android.permission.MANAGE_USER_OEM_UNLOCK_STATE"; @@ -1412,8 +1413,14 @@ package android.app.usage { package android.bluetooth { public final class BluetoothA2dp implements android.bluetooth.BluetoothProfile { + method @Nullable @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public android.bluetooth.BufferConstraints getBufferConstraints(); method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public int getConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice); + method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public int getDynamicBufferSupport(); + method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setBufferMillis(int, int); method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int); + field public static final int DYNAMIC_BUFFER_SUPPORT_A2DP_OFFLOAD = 1; // 0x1 + field public static final int DYNAMIC_BUFFER_SUPPORT_A2DP_SOFTWARE_ENCODING = 2; // 0x2 + field public static final int DYNAMIC_BUFFER_SUPPORT_NONE = 0; // 0x0 field public static final int OPTIONAL_CODECS_NOT_SUPPORTED = 0; // 0x0 field public static final int OPTIONAL_CODECS_PREF_DISABLED = 0; // 0x0 field public static final int OPTIONAL_CODECS_PREF_ENABLED = 1; // 0x1 @@ -1595,6 +1602,25 @@ package android.bluetooth { field public static final int UUID_BYTES_32_BIT = 4; // 0x4 } + public final class BufferConstraint implements android.os.Parcelable { + ctor public BufferConstraint(int, int, int); + method public int describeContents(); + method public int getDefaultMillis(); + method public int getMaxMillis(); + method public int getMinMillis(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.BufferConstraint> CREATOR; + } + + public final class BufferConstraints implements android.os.Parcelable { + ctor public BufferConstraints(@NonNull java.util.List<android.bluetooth.BufferConstraint>); + method public int describeContents(); + method @Nullable public android.bluetooth.BufferConstraint getCodec(int); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field public static final int BUFFER_CODEC_MAX_NUM = 32; // 0x20 + field @NonNull public static final android.os.Parcelable.Creator<android.bluetooth.BufferConstraints> CREATOR; + } + } package android.bluetooth.le { @@ -1684,7 +1710,6 @@ package android.content { field public static final String APP_PREDICTION_SERVICE = "app_prediction"; field public static final String BACKUP_SERVICE = "backup"; field public static final String BATTERY_STATS_SERVICE = "batterystats"; - field public static final String BUGREPORT_SERVICE = "bugreport"; field public static final String CONTENT_SUGGESTIONS_SERVICE = "content_suggestions"; field public static final String CONTEXTHUB_SERVICE = "contexthub"; field public static final String ETHERNET_SERVICE = "ethernet"; @@ -6505,157 +6530,157 @@ package android.net.apf { package android.net.metrics { - public final class ApfProgramEvent implements android.net.metrics.IpConnectivityLog.Event { - } - - public static final class ApfProgramEvent.Builder { - ctor public ApfProgramEvent.Builder(); - method @NonNull public android.net.metrics.ApfProgramEvent build(); - method @NonNull public android.net.metrics.ApfProgramEvent.Builder setActualLifetime(long); - method @NonNull public android.net.metrics.ApfProgramEvent.Builder setCurrentRas(int); - method @NonNull public android.net.metrics.ApfProgramEvent.Builder setFilteredRas(int); - method @NonNull public android.net.metrics.ApfProgramEvent.Builder setFlags(boolean, boolean); - method @NonNull public android.net.metrics.ApfProgramEvent.Builder setLifetime(long); - method @NonNull public android.net.metrics.ApfProgramEvent.Builder setProgramLength(int); - } - - public final class ApfStats implements android.net.metrics.IpConnectivityLog.Event { - } - - public static final class ApfStats.Builder { - ctor public ApfStats.Builder(); - method @NonNull public android.net.metrics.ApfStats build(); - method @NonNull public android.net.metrics.ApfStats.Builder setDroppedRas(int); - method @NonNull public android.net.metrics.ApfStats.Builder setDurationMs(long); - method @NonNull public android.net.metrics.ApfStats.Builder setMatchingRas(int); - method @NonNull public android.net.metrics.ApfStats.Builder setMaxProgramSize(int); - method @NonNull public android.net.metrics.ApfStats.Builder setParseErrors(int); - method @NonNull public android.net.metrics.ApfStats.Builder setProgramUpdates(int); - method @NonNull public android.net.metrics.ApfStats.Builder setProgramUpdatesAll(int); - method @NonNull public android.net.metrics.ApfStats.Builder setProgramUpdatesAllowingMulticast(int); - method @NonNull public android.net.metrics.ApfStats.Builder setReceivedRas(int); - method @NonNull public android.net.metrics.ApfStats.Builder setZeroLifetimeRas(int); - } - - public final class DhcpClientEvent implements android.net.metrics.IpConnectivityLog.Event { - } - - public static final class DhcpClientEvent.Builder { - ctor public DhcpClientEvent.Builder(); - method @NonNull public android.net.metrics.DhcpClientEvent build(); - method @NonNull public android.net.metrics.DhcpClientEvent.Builder setDurationMs(int); - method @NonNull public android.net.metrics.DhcpClientEvent.Builder setMsg(String); - } - - public final class DhcpErrorEvent implements android.net.metrics.IpConnectivityLog.Event { - ctor public DhcpErrorEvent(int); - method public static int errorCodeWithOption(int, int); - field public static final int BOOTP_TOO_SHORT = 67174400; // 0x4010000 - field public static final int BUFFER_UNDERFLOW = 83951616; // 0x5010000 - field public static final int DHCP_BAD_MAGIC_COOKIE = 67239936; // 0x4020000 - field public static final int DHCP_ERROR = 4; // 0x4 - field public static final int DHCP_INVALID_OPTION_LENGTH = 67305472; // 0x4030000 - field public static final int DHCP_NO_COOKIE = 67502080; // 0x4060000 - field public static final int DHCP_NO_MSG_TYPE = 67371008; // 0x4040000 - field public static final int DHCP_UNKNOWN_MSG_TYPE = 67436544; // 0x4050000 - field public static final int L2_ERROR = 1; // 0x1 - field public static final int L2_TOO_SHORT = 16842752; // 0x1010000 - field public static final int L2_WRONG_ETH_TYPE = 16908288; // 0x1020000 - field public static final int L3_ERROR = 2; // 0x2 - field public static final int L3_INVALID_IP = 33751040; // 0x2030000 - field public static final int L3_NOT_IPV4 = 33685504; // 0x2020000 - field public static final int L3_TOO_SHORT = 33619968; // 0x2010000 - field public static final int L4_ERROR = 3; // 0x3 - field public static final int L4_NOT_UDP = 50397184; // 0x3010000 - field public static final int L4_WRONG_PORT = 50462720; // 0x3020000 - field public static final int MISC_ERROR = 5; // 0x5 - field public static final int PARSING_ERROR = 84082688; // 0x5030000 - field public static final int RECEIVE_ERROR = 84017152; // 0x5020000 - } - - public class IpConnectivityLog { - ctor public IpConnectivityLog(); - method public boolean log(long, @NonNull android.net.metrics.IpConnectivityLog.Event); - method public boolean log(@NonNull String, @NonNull android.net.metrics.IpConnectivityLog.Event); - method public boolean log(@NonNull android.net.Network, @NonNull int[], @NonNull android.net.metrics.IpConnectivityLog.Event); - method public boolean log(int, @NonNull int[], @NonNull android.net.metrics.IpConnectivityLog.Event); - method public boolean log(@NonNull android.net.metrics.IpConnectivityLog.Event); - } - - public static interface IpConnectivityLog.Event extends android.os.Parcelable { - } - - public final class IpManagerEvent implements android.net.metrics.IpConnectivityLog.Event { - ctor public IpManagerEvent(int, long); - field public static final int COMPLETE_LIFECYCLE = 3; // 0x3 - field public static final int ERROR_INTERFACE_NOT_FOUND = 8; // 0x8 - field public static final int ERROR_INVALID_PROVISIONING = 7; // 0x7 - field public static final int ERROR_STARTING_IPREACHABILITYMONITOR = 6; // 0x6 - field public static final int ERROR_STARTING_IPV4 = 4; // 0x4 - field public static final int ERROR_STARTING_IPV6 = 5; // 0x5 - field public static final int PROVISIONING_FAIL = 2; // 0x2 - field public static final int PROVISIONING_OK = 1; // 0x1 - } - - public final class IpReachabilityEvent implements android.net.metrics.IpConnectivityLog.Event { - ctor public IpReachabilityEvent(int); - field public static final int NUD_FAILED = 512; // 0x200 - field public static final int NUD_FAILED_ORGANIC = 1024; // 0x400 - field public static final int PROBE = 256; // 0x100 - field public static final int PROVISIONING_LOST = 768; // 0x300 - field public static final int PROVISIONING_LOST_ORGANIC = 1280; // 0x500 - } - - public final class NetworkEvent implements android.net.metrics.IpConnectivityLog.Event { - ctor public NetworkEvent(int, long); - ctor public NetworkEvent(int); - field public static final int NETWORK_CAPTIVE_PORTAL_FOUND = 4; // 0x4 - field public static final int NETWORK_CONNECTED = 1; // 0x1 - field public static final int NETWORK_CONSECUTIVE_DNS_TIMEOUT_FOUND = 12; // 0xc - field public static final int NETWORK_DISCONNECTED = 7; // 0x7 - field public static final int NETWORK_FIRST_VALIDATION_PORTAL_FOUND = 10; // 0xa - field public static final int NETWORK_FIRST_VALIDATION_SUCCESS = 8; // 0x8 - field public static final int NETWORK_LINGER = 5; // 0x5 - field public static final int NETWORK_PARTIAL_CONNECTIVITY = 13; // 0xd - field public static final int NETWORK_REVALIDATION_PORTAL_FOUND = 11; // 0xb - field public static final int NETWORK_REVALIDATION_SUCCESS = 9; // 0x9 - field public static final int NETWORK_UNLINGER = 6; // 0x6 - field public static final int NETWORK_VALIDATED = 2; // 0x2 - field public static final int NETWORK_VALIDATION_FAILED = 3; // 0x3 - } - - public final class RaEvent implements android.net.metrics.IpConnectivityLog.Event { - } - - public static final class RaEvent.Builder { - ctor public RaEvent.Builder(); - method @NonNull public android.net.metrics.RaEvent build(); - method @NonNull public android.net.metrics.RaEvent.Builder updateDnsslLifetime(long); - method @NonNull public android.net.metrics.RaEvent.Builder updatePrefixPreferredLifetime(long); - method @NonNull public android.net.metrics.RaEvent.Builder updatePrefixValidLifetime(long); - method @NonNull public android.net.metrics.RaEvent.Builder updateRdnssLifetime(long); - method @NonNull public android.net.metrics.RaEvent.Builder updateRouteInfoLifetime(long); - method @NonNull public android.net.metrics.RaEvent.Builder updateRouterLifetime(long); - } - - public final class ValidationProbeEvent implements android.net.metrics.IpConnectivityLog.Event { - method @NonNull public static String getProbeName(int); - field public static final int DNS_FAILURE = 0; // 0x0 - field public static final int DNS_SUCCESS = 1; // 0x1 - field public static final int PROBE_DNS = 0; // 0x0 - field public static final int PROBE_FALLBACK = 4; // 0x4 - field public static final int PROBE_HTTP = 1; // 0x1 - field public static final int PROBE_HTTPS = 2; // 0x2 - field public static final int PROBE_PAC = 3; // 0x3 - field public static final int PROBE_PRIVDNS = 5; // 0x5 - } - - public static final class ValidationProbeEvent.Builder { - ctor public ValidationProbeEvent.Builder(); - method @NonNull public android.net.metrics.ValidationProbeEvent build(); - method @NonNull public android.net.metrics.ValidationProbeEvent.Builder setDurationMs(long); - method @NonNull public android.net.metrics.ValidationProbeEvent.Builder setProbeType(int, boolean); - method @NonNull public android.net.metrics.ValidationProbeEvent.Builder setReturnCode(int); + @Deprecated public final class ApfProgramEvent implements android.net.metrics.IpConnectivityLog.Event { + } + + @Deprecated public static final class ApfProgramEvent.Builder { + ctor @Deprecated public ApfProgramEvent.Builder(); + method @Deprecated @NonNull public android.net.metrics.ApfProgramEvent build(); + method @Deprecated @NonNull public android.net.metrics.ApfProgramEvent.Builder setActualLifetime(long); + method @Deprecated @NonNull public android.net.metrics.ApfProgramEvent.Builder setCurrentRas(int); + method @Deprecated @NonNull public android.net.metrics.ApfProgramEvent.Builder setFilteredRas(int); + method @Deprecated @NonNull public android.net.metrics.ApfProgramEvent.Builder setFlags(boolean, boolean); + method @Deprecated @NonNull public android.net.metrics.ApfProgramEvent.Builder setLifetime(long); + method @Deprecated @NonNull public android.net.metrics.ApfProgramEvent.Builder setProgramLength(int); + } + + @Deprecated public final class ApfStats implements android.net.metrics.IpConnectivityLog.Event { + } + + @Deprecated public static final class ApfStats.Builder { + ctor @Deprecated public ApfStats.Builder(); + method @Deprecated @NonNull public android.net.metrics.ApfStats build(); + method @Deprecated @NonNull public android.net.metrics.ApfStats.Builder setDroppedRas(int); + method @Deprecated @NonNull public android.net.metrics.ApfStats.Builder setDurationMs(long); + method @Deprecated @NonNull public android.net.metrics.ApfStats.Builder setMatchingRas(int); + method @Deprecated @NonNull public android.net.metrics.ApfStats.Builder setMaxProgramSize(int); + method @Deprecated @NonNull public android.net.metrics.ApfStats.Builder setParseErrors(int); + method @Deprecated @NonNull public android.net.metrics.ApfStats.Builder setProgramUpdates(int); + method @Deprecated @NonNull public android.net.metrics.ApfStats.Builder setProgramUpdatesAll(int); + method @Deprecated @NonNull public android.net.metrics.ApfStats.Builder setProgramUpdatesAllowingMulticast(int); + method @Deprecated @NonNull public android.net.metrics.ApfStats.Builder setReceivedRas(int); + method @Deprecated @NonNull public android.net.metrics.ApfStats.Builder setZeroLifetimeRas(int); + } + + @Deprecated public final class DhcpClientEvent implements android.net.metrics.IpConnectivityLog.Event { + } + + @Deprecated public static final class DhcpClientEvent.Builder { + ctor @Deprecated public DhcpClientEvent.Builder(); + method @Deprecated @NonNull public android.net.metrics.DhcpClientEvent build(); + method @Deprecated @NonNull public android.net.metrics.DhcpClientEvent.Builder setDurationMs(int); + method @Deprecated @NonNull public android.net.metrics.DhcpClientEvent.Builder setMsg(String); + } + + @Deprecated public final class DhcpErrorEvent implements android.net.metrics.IpConnectivityLog.Event { + ctor @Deprecated public DhcpErrorEvent(int); + method @Deprecated public static int errorCodeWithOption(int, int); + field @Deprecated public static final int BOOTP_TOO_SHORT = 67174400; // 0x4010000 + field @Deprecated public static final int BUFFER_UNDERFLOW = 83951616; // 0x5010000 + field @Deprecated public static final int DHCP_BAD_MAGIC_COOKIE = 67239936; // 0x4020000 + field @Deprecated public static final int DHCP_ERROR = 4; // 0x4 + field @Deprecated public static final int DHCP_INVALID_OPTION_LENGTH = 67305472; // 0x4030000 + field @Deprecated public static final int DHCP_NO_COOKIE = 67502080; // 0x4060000 + field @Deprecated public static final int DHCP_NO_MSG_TYPE = 67371008; // 0x4040000 + field @Deprecated public static final int DHCP_UNKNOWN_MSG_TYPE = 67436544; // 0x4050000 + field @Deprecated public static final int L2_ERROR = 1; // 0x1 + field @Deprecated public static final int L2_TOO_SHORT = 16842752; // 0x1010000 + field @Deprecated public static final int L2_WRONG_ETH_TYPE = 16908288; // 0x1020000 + field @Deprecated public static final int L3_ERROR = 2; // 0x2 + field @Deprecated public static final int L3_INVALID_IP = 33751040; // 0x2030000 + field @Deprecated public static final int L3_NOT_IPV4 = 33685504; // 0x2020000 + field @Deprecated public static final int L3_TOO_SHORT = 33619968; // 0x2010000 + field @Deprecated public static final int L4_ERROR = 3; // 0x3 + field @Deprecated public static final int L4_NOT_UDP = 50397184; // 0x3010000 + field @Deprecated public static final int L4_WRONG_PORT = 50462720; // 0x3020000 + field @Deprecated public static final int MISC_ERROR = 5; // 0x5 + field @Deprecated public static final int PARSING_ERROR = 84082688; // 0x5030000 + field @Deprecated public static final int RECEIVE_ERROR = 84017152; // 0x5020000 + } + + @Deprecated public class IpConnectivityLog { + ctor @Deprecated public IpConnectivityLog(); + method @Deprecated public boolean log(long, @NonNull android.net.metrics.IpConnectivityLog.Event); + method @Deprecated public boolean log(@NonNull String, @NonNull android.net.metrics.IpConnectivityLog.Event); + method @Deprecated public boolean log(@NonNull android.net.Network, @NonNull int[], @NonNull android.net.metrics.IpConnectivityLog.Event); + method @Deprecated public boolean log(int, @NonNull int[], @NonNull android.net.metrics.IpConnectivityLog.Event); + method @Deprecated public boolean log(@NonNull android.net.metrics.IpConnectivityLog.Event); + } + + @Deprecated public static interface IpConnectivityLog.Event extends android.os.Parcelable { + } + + @Deprecated public final class IpManagerEvent implements android.net.metrics.IpConnectivityLog.Event { + ctor @Deprecated public IpManagerEvent(int, long); + field @Deprecated public static final int COMPLETE_LIFECYCLE = 3; // 0x3 + field @Deprecated public static final int ERROR_INTERFACE_NOT_FOUND = 8; // 0x8 + field @Deprecated public static final int ERROR_INVALID_PROVISIONING = 7; // 0x7 + field @Deprecated public static final int ERROR_STARTING_IPREACHABILITYMONITOR = 6; // 0x6 + field @Deprecated public static final int ERROR_STARTING_IPV4 = 4; // 0x4 + field @Deprecated public static final int ERROR_STARTING_IPV6 = 5; // 0x5 + field @Deprecated public static final int PROVISIONING_FAIL = 2; // 0x2 + field @Deprecated public static final int PROVISIONING_OK = 1; // 0x1 + } + + @Deprecated public final class IpReachabilityEvent implements android.net.metrics.IpConnectivityLog.Event { + ctor @Deprecated public IpReachabilityEvent(int); + field @Deprecated public static final int NUD_FAILED = 512; // 0x200 + field @Deprecated public static final int NUD_FAILED_ORGANIC = 1024; // 0x400 + field @Deprecated public static final int PROBE = 256; // 0x100 + field @Deprecated public static final int PROVISIONING_LOST = 768; // 0x300 + field @Deprecated public static final int PROVISIONING_LOST_ORGANIC = 1280; // 0x500 + } + + @Deprecated public final class NetworkEvent implements android.net.metrics.IpConnectivityLog.Event { + ctor @Deprecated public NetworkEvent(int, long); + ctor @Deprecated public NetworkEvent(int); + field @Deprecated public static final int NETWORK_CAPTIVE_PORTAL_FOUND = 4; // 0x4 + field @Deprecated public static final int NETWORK_CONNECTED = 1; // 0x1 + field @Deprecated public static final int NETWORK_CONSECUTIVE_DNS_TIMEOUT_FOUND = 12; // 0xc + field @Deprecated public static final int NETWORK_DISCONNECTED = 7; // 0x7 + field @Deprecated public static final int NETWORK_FIRST_VALIDATION_PORTAL_FOUND = 10; // 0xa + field @Deprecated public static final int NETWORK_FIRST_VALIDATION_SUCCESS = 8; // 0x8 + field @Deprecated public static final int NETWORK_LINGER = 5; // 0x5 + field @Deprecated public static final int NETWORK_PARTIAL_CONNECTIVITY = 13; // 0xd + field @Deprecated public static final int NETWORK_REVALIDATION_PORTAL_FOUND = 11; // 0xb + field @Deprecated public static final int NETWORK_REVALIDATION_SUCCESS = 9; // 0x9 + field @Deprecated public static final int NETWORK_UNLINGER = 6; // 0x6 + field @Deprecated public static final int NETWORK_VALIDATED = 2; // 0x2 + field @Deprecated public static final int NETWORK_VALIDATION_FAILED = 3; // 0x3 + } + + @Deprecated public final class RaEvent implements android.net.metrics.IpConnectivityLog.Event { + } + + @Deprecated public static final class RaEvent.Builder { + ctor @Deprecated public RaEvent.Builder(); + method @Deprecated @NonNull public android.net.metrics.RaEvent build(); + method @Deprecated @NonNull public android.net.metrics.RaEvent.Builder updateDnsslLifetime(long); + method @Deprecated @NonNull public android.net.metrics.RaEvent.Builder updatePrefixPreferredLifetime(long); + method @Deprecated @NonNull public android.net.metrics.RaEvent.Builder updatePrefixValidLifetime(long); + method @Deprecated @NonNull public android.net.metrics.RaEvent.Builder updateRdnssLifetime(long); + method @Deprecated @NonNull public android.net.metrics.RaEvent.Builder updateRouteInfoLifetime(long); + method @Deprecated @NonNull public android.net.metrics.RaEvent.Builder updateRouterLifetime(long); + } + + @Deprecated public final class ValidationProbeEvent implements android.net.metrics.IpConnectivityLog.Event { + method @Deprecated @NonNull public static String getProbeName(int); + field @Deprecated public static final int DNS_FAILURE = 0; // 0x0 + field @Deprecated public static final int DNS_SUCCESS = 1; // 0x1 + field @Deprecated public static final int PROBE_DNS = 0; // 0x0 + field @Deprecated public static final int PROBE_FALLBACK = 4; // 0x4 + field @Deprecated public static final int PROBE_HTTP = 1; // 0x1 + field @Deprecated public static final int PROBE_HTTPS = 2; // 0x2 + field @Deprecated public static final int PROBE_PAC = 3; // 0x3 + field @Deprecated public static final int PROBE_PRIVDNS = 5; // 0x5 + } + + @Deprecated public static final class ValidationProbeEvent.Builder { + ctor @Deprecated public ValidationProbeEvent.Builder(); + method @Deprecated @NonNull public android.net.metrics.ValidationProbeEvent build(); + method @Deprecated @NonNull public android.net.metrics.ValidationProbeEvent.Builder setDurationMs(long); + method @Deprecated @NonNull public android.net.metrics.ValidationProbeEvent.Builder setProbeType(int, boolean); + method @Deprecated @NonNull public android.net.metrics.ValidationProbeEvent.Builder setReturnCode(int); } } @@ -6926,7 +6951,10 @@ package android.nfc { method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enable(); method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enableNdefPush(); method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enableSecureNfc(boolean); + method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean isAlwaysOnEnabled(); + method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean isAlwaysOnSupported(); method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean removeNfcUnlockHandler(android.nfc.NfcAdapter.NfcUnlockHandler); + method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean setAlwaysOn(boolean); method public void setNdefPushMessage(android.nfc.NdefMessage, android.app.Activity, int); field public static final int FLAG_NDEF_PUSH_NO_CONFIRM = 1; // 0x1 } @@ -7046,24 +7074,10 @@ package android.os { } public final class BugreportManager { - method @RequiresPermission(android.Manifest.permission.DUMP) public void cancelBugreport(); method @RequiresPermission(android.Manifest.permission.DUMP) public void requestBugreport(@NonNull android.os.BugreportParams, @Nullable CharSequence, @Nullable CharSequence); method @RequiresPermission(android.Manifest.permission.DUMP) public void startBugreport(@NonNull android.os.ParcelFileDescriptor, @Nullable android.os.ParcelFileDescriptor, @NonNull android.os.BugreportParams, @NonNull java.util.concurrent.Executor, @NonNull android.os.BugreportManager.BugreportCallback); } - public abstract static class BugreportManager.BugreportCallback { - ctor public BugreportManager.BugreportCallback(); - method public void onEarlyReportFinished(); - method public void onError(int); - method public void onFinished(); - method public void onProgress(@FloatRange(from=0.0f, to=100.0f) float); - field public static final int BUGREPORT_ERROR_ANOTHER_REPORT_IN_PROGRESS = 5; // 0x5 - field public static final int BUGREPORT_ERROR_INVALID_INPUT = 1; // 0x1 - field public static final int BUGREPORT_ERROR_RUNTIME = 2; // 0x2 - field public static final int BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT = 4; // 0x4 - field public static final int BUGREPORT_ERROR_USER_DENIED_CONSENT = 3; // 0x3 - } - public final class BugreportParams { ctor public BugreportParams(int); method public int getMode(); diff --git a/core/api/test-current.txt b/core/api/test-current.txt index 9cf9ce45602b..715a099fca4f 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -981,7 +981,7 @@ package android.media.tv { package android.net { public class ConnectivityManager { - method @RequiresPermission(anyOf={"android.permission.MANAGE_TEST_NETWORKS", android.Manifest.permission.NETWORK_STACK}) public void simulateDataStall(int, long, @NonNull android.net.Network, @NonNull android.os.PersistableBundle); + method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_TEST_NETWORKS, android.Manifest.permission.NETWORK_STACK}) public void simulateDataStall(int, long, @NonNull android.net.Network, @NonNull android.os.PersistableBundle); } public class EthernetManager { @@ -1001,22 +1001,6 @@ package android.net { method public static void setServiceForTest(@Nullable android.os.IBinder); } - public final class TestNetworkInterface implements android.os.Parcelable { - ctor public TestNetworkInterface(android.os.ParcelFileDescriptor, String); - method public int describeContents(); - method public android.os.ParcelFileDescriptor getFileDescriptor(); - method public String getInterfaceName(); - method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator<android.net.TestNetworkInterface> CREATOR; - } - - public class TestNetworkManager { - method public android.net.TestNetworkInterface createTapInterface(); - method public android.net.TestNetworkInterface createTunInterface(@NonNull android.net.LinkAddress[]); - method public void setupTestNetwork(@NonNull String, @NonNull android.os.IBinder); - method public void teardownTestNetwork(@NonNull android.net.Network); - } - public class TrafficStats { method public static long getLoopbackRxBytes(); method public static long getLoopbackRxPackets(); diff --git a/core/java/android/accessibilityservice/OWNERS b/core/java/android/accessibilityservice/OWNERS index c6f42f719caa..a31cfae995b2 100644 --- a/core/java/android/accessibilityservice/OWNERS +++ b/core/java/android/accessibilityservice/OWNERS @@ -1,4 +1,4 @@ svetoslavganov@google.com pweaver@google.com rhedjao@google.com -qasid@google.com +ryanlwlin@google.com diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index 602b835a03f8..12c9cd90222a 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -1428,6 +1428,45 @@ class ContextImpl extends Context { } } + /** + * <p>Perform a {@link #sendBroadcast(Intent)} that is "sticky," meaning the + * Intent you are sending stays around after the broadcast is complete, + * so that others can quickly retrieve that data through the return + * value of {@link #registerReceiver(BroadcastReceiver, IntentFilter)}. In + * all other ways, this behaves the same as + * {@link #sendBroadcast(Intent)}. + * + * @deprecated Sticky broadcasts should not be used. They provide no security (anyone + * can access them), no protection (anyone can modify them), and many other problems. + * The recommended pattern is to use a non-sticky broadcast to report that <em>something</em> + * has changed, with another mechanism for apps to retrieve the current value whenever + * desired. + * + * @param intent The Intent to broadcast; all receivers matching this + * Intent will receive the broadcast, and the Intent will be held to + * be re-broadcast to future receivers. + * @param options (optional) Additional sending options, generated from a + * {@link android.app.BroadcastOptions}. + * + * @see #sendBroadcast(Intent) + * @see #sendStickyOrderedBroadcast(Intent, BroadcastReceiver, Handler, int, String, Bundle) + */ + @Override + @Deprecated + public void sendStickyBroadcast(@NonNull Intent intent, @Nullable Bundle options) { + warnIfCallingFromSystemProcess(); + String resolvedType = intent.resolveTypeIfNeeded(getContentResolver()); + try { + intent.prepareToLeaveProcess(this); + ActivityManager.getService().broadcastIntentWithFeature( + mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType, + null, Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, options, + false, true, getUserId()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + @Override @Deprecated public void sendStickyOrderedBroadcast(Intent intent, diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl index be1681bc7cc6..66a832505ead 100644 --- a/core/java/android/app/IActivityTaskManager.aidl +++ b/core/java/android/app/IActivityTaskManager.aidl @@ -223,7 +223,7 @@ interface IActivityTaskManager { */ IBinder requestStartActivityPermissionToken(in IBinder delegatorToken); - void releaseSomeActivities(in IApplicationThread app); + oneway void releaseSomeActivities(in IApplicationThread app); Bitmap getTaskDescriptionIcon(in String filename, int userId); void registerTaskStackListener(in ITaskStackListener listener); void unregisterTaskStackListener(in ITaskStackListener listener); diff --git a/core/java/android/app/OWNERS b/core/java/android/app/OWNERS index 6d79e2d3c166..60bfac566879 100644 --- a/core/java/android/app/OWNERS +++ b/core/java/android/app/OWNERS @@ -42,8 +42,10 @@ per-file *AppOp* = file:/core/java/android/permission/OWNERS # Multiuser per-file *User* = file:/MULTIUSER_OWNERS -# Notification +# Notification, DND, Status bar per-file *Notification* = file:/packages/SystemUI/OWNERS +per-file *Zen* = file:/packages/SystemUI/OWNERS +per-file *StatusBar* = file:/packages/SystemUI/OWNERS # ResourcesManager per-file ResourcesManager = rtmitchell@google.com, toddke@google.com diff --git a/core/java/android/appwidget/OWNERS b/core/java/android/appwidget/OWNERS new file mode 100644 index 000000000000..439df4b86cf0 --- /dev/null +++ b/core/java/android/appwidget/OWNERS @@ -0,0 +1,3 @@ +pinyaoting@google.com +suprabh@google.com +sunnygoyal@google.com diff --git a/core/java/android/bluetooth/BluetoothA2dp.java b/core/java/android/bluetooth/BluetoothA2dp.java index 15daf1c59d1a..cd91aa9b16b7 100644 --- a/core/java/android/bluetooth/BluetoothA2dp.java +++ b/core/java/android/bluetooth/BluetoothA2dp.java @@ -225,6 +225,39 @@ public final class BluetoothA2dp implements BluetoothProfile { @SystemApi public static final int OPTIONAL_CODECS_PREF_ENABLED = 1; + /** @hide */ + @IntDef(prefix = "DYNAMIC_BUFFER_SUPPORT_", value = { + DYNAMIC_BUFFER_SUPPORT_NONE, + DYNAMIC_BUFFER_SUPPORT_A2DP_OFFLOAD, + DYNAMIC_BUFFER_SUPPORT_A2DP_SOFTWARE_ENCODING + }) + @Retention(RetentionPolicy.SOURCE) + public @interface Type {} + + /** + * Indicates the supported type of Dynamic Audio Buffer is not supported. + * + * @hide + */ + @SystemApi + public static final int DYNAMIC_BUFFER_SUPPORT_NONE = 0; + + /** + * Indicates the supported type of Dynamic Audio Buffer is A2DP offload. + * + * @hide + */ + @SystemApi + public static final int DYNAMIC_BUFFER_SUPPORT_A2DP_OFFLOAD = 1; + + /** + * Indicates the supported type of Dynamic Audio Buffer is A2DP software encoding. + * + * @hide + */ + @SystemApi + public static final int DYNAMIC_BUFFER_SUPPORT_A2DP_SOFTWARE_ENCODING = 2; + private BluetoothAdapter mAdapter; private final BluetoothProfileConnector<IBluetoothA2dp> mProfileConnector = new BluetoothProfileConnector(this, BluetoothProfile.A2DP, "BluetoothA2dp", @@ -845,6 +878,87 @@ public final class BluetoothA2dp implements BluetoothProfile { } /** + * Get the supported type of the Dynamic Audio Buffer. + * <p>Possible return values are + * {@link #DYNAMIC_BUFFER_SUPPORT_NONE}, + * {@link #DYNAMIC_BUFFER_SUPPORT_A2DP_OFFLOAD}, + * {@link #DYNAMIC_BUFFER_SUPPORT_A2DP_SOFTWARE_ENCODING}. + * + * @return supported type of Dynamic Audio Buffer feature + * + * @hide + */ + @SystemApi + @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) + public @Type int getDynamicBufferSupport() { + if (VDBG) log("getDynamicBufferSupport()"); + try { + final IBluetoothA2dp service = getService(); + if (service != null && isEnabled()) { + return service.getDynamicBufferSupport(); + } + if (service == null) Log.w(TAG, "Proxy not attached to service"); + return DYNAMIC_BUFFER_SUPPORT_NONE; + } catch (RemoteException e) { + Log.e(TAG, "failed to get getDynamicBufferSupport, error: ", e); + return DYNAMIC_BUFFER_SUPPORT_NONE; + } + } + + /** + * Return the record of {@link BufferConstraints} object that + * has the default/maximum/minimum audio buffer. This can be used to inform what the controller + * has support for the audio buffer. + * + * @return a record with {@link BufferConstraints} or null if report is unavailable + * or unsupported + * + * @hide + */ + @SystemApi + @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) + public @Nullable BufferConstraints getBufferConstraints() { + if (VDBG) log("getBufferConstraints()"); + try { + final IBluetoothA2dp service = getService(); + if (service != null && isEnabled()) { + return service.getBufferConstraints(); + } + if (service == null) Log.w(TAG, "Proxy not attached to service"); + return null; + } catch (RemoteException e) { + Log.e(TAG, "", e); + return null; + } + } + + /** + * Set Dynamic Audio Buffer Size. + * + * @param codec audio codec + * @param value buffer millis + * @return true to indicate success, or false on immediate error + * + * @hide + */ + @SystemApi + @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) + public boolean setBufferMillis(@BluetoothCodecConfig.SourceCodecType int codec, int value) { + if (VDBG) log("setBufferMillis(" + codec + ", " + value + ")"); + try { + final IBluetoothA2dp service = getService(); + if (service != null && isEnabled()) { + return service.setBufferMillis(codec, value); + } + if (service == null) Log.w(TAG, "Proxy not attached to service"); + return false; + } catch (RemoteException e) { + Log.e(TAG, "", e); + return false; + } + } + + /** * Helper for converting a state to a string. * * For debug use only - strings are not internationalized. diff --git a/core/java/android/bluetooth/BufferConstraint.java b/core/java/android/bluetooth/BufferConstraint.java new file mode 100644 index 000000000000..cbffc788c35d --- /dev/null +++ b/core/java/android/bluetooth/BufferConstraint.java @@ -0,0 +1,105 @@ +/* + * 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.bluetooth; + +import android.annotation.NonNull; +import android.annotation.SystemApi; +import android.os.Parcel; +import android.os.Parcelable; + +/** + * Stores a codec's constraints on buffering length in milliseconds. + * + * {@hide} + */ +@SystemApi +public final class BufferConstraint implements Parcelable { + + private static final String TAG = "BufferConstraint"; + private int mDefaultMillis; + private int mMaxMillis; + private int mMinMillis; + + public BufferConstraint(int defaultMillis, int maxMillis, + int minMillis) { + mDefaultMillis = defaultMillis; + mMaxMillis = maxMillis; + mMinMillis = minMillis; + } + + BufferConstraint(Parcel in) { + mDefaultMillis = in.readInt(); + mMaxMillis = in.readInt(); + mMinMillis = in.readInt(); + } + + public static final @NonNull Parcelable.Creator<BufferConstraint> CREATOR = + new Parcelable.Creator<BufferConstraint>() { + public BufferConstraint createFromParcel(Parcel in) { + return new BufferConstraint(in); + } + + public BufferConstraint[] newArray(int size) { + return new BufferConstraint[size]; + } + }; + + @Override + public void writeToParcel(@NonNull Parcel out, int flags) { + out.writeInt(mDefaultMillis); + out.writeInt(mMaxMillis); + out.writeInt(mMinMillis); + } + + @Override + public int describeContents() { + return 0; + } + + /** + * Get the default buffer millis + * + * @return default buffer millis + * @hide + */ + @SystemApi + public int getDefaultMillis() { + return mDefaultMillis; + } + + /** + * Get the maximum buffer millis + * + * @return maximum buffer millis + * @hide + */ + @SystemApi + public int getMaxMillis() { + return mMaxMillis; + } + + /** + * Get the minimum buffer millis + * + * @return minimum buffer millis + * @hide + */ + @SystemApi + public int getMinMillis() { + return mMinMillis; + } +} diff --git a/core/java/android/bluetooth/BufferConstraints.java b/core/java/android/bluetooth/BufferConstraints.java new file mode 100644 index 000000000000..7e5ec1e78435 --- /dev/null +++ b/core/java/android/bluetooth/BufferConstraints.java @@ -0,0 +1,96 @@ +/* + * 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.bluetooth; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + + +/** + * A parcelable collection of buffer constraints by codec type. + * + * {@hide} + */ +@SystemApi +public final class BufferConstraints implements Parcelable { + public static final int BUFFER_CODEC_MAX_NUM = 32; + + private static final String TAG = "BufferConstraints"; + + private Map<Integer, BufferConstraint> mBufferConstraints; + private List<BufferConstraint> mBufferConstraintList; + + public BufferConstraints(@NonNull List<BufferConstraint> + bufferConstraintList) { + + mBufferConstraintList = new ArrayList<BufferConstraint>(bufferConstraintList); + mBufferConstraints = new HashMap<Integer, BufferConstraint>(); + for (int i = 0; i < BUFFER_CODEC_MAX_NUM; i++) { + mBufferConstraints.put(i, bufferConstraintList.get(i)); + } + } + + BufferConstraints(Parcel in) { + mBufferConstraintList = new ArrayList<BufferConstraint>(); + mBufferConstraints = new HashMap<Integer, BufferConstraint>(); + in.readList(mBufferConstraintList, BufferConstraint.class.getClassLoader()); + for (int i = 0; i < mBufferConstraintList.size(); i++) { + mBufferConstraints.put(i, mBufferConstraintList.get(i)); + } + } + + public static final @NonNull Parcelable.Creator<BufferConstraints> CREATOR = + new Parcelable.Creator<BufferConstraints>() { + public BufferConstraints createFromParcel(Parcel in) { + return new BufferConstraints(in); + } + + public BufferConstraints[] newArray(int size) { + return new BufferConstraints[size]; + } + }; + + @Override + public void writeToParcel(@NonNull Parcel out, int flags) { + out.writeList(mBufferConstraintList); + } + + @Override + public int describeContents() { + return 0; + } + + /** + * Get the buffer constraints by codec type. + * + * @param codec Audio codec + * @return buffer constraints by codec type. + * @hide + */ + @SystemApi + public @Nullable BufferConstraint getCodec(@BluetoothCodecConfig.SourceCodecType int codec) { + return mBufferConstraints.get(codec); + } +} diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 92ede1ca45fb..eecdb843774a 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -2602,6 +2602,36 @@ public abstract class Context { public abstract void sendStickyBroadcast(@RequiresPermission Intent intent); /** + * <p>Perform a {@link #sendBroadcast(Intent)} that is "sticky," meaning the + * Intent you are sending stays around after the broadcast is complete, + * so that others can quickly retrieve that data through the return + * value of {@link #registerReceiver(BroadcastReceiver, IntentFilter)}. In + * all other ways, this behaves the same as + * {@link #sendBroadcast(Intent)}. + * + * @deprecated Sticky broadcasts should not be used. They provide no security (anyone + * can access them), no protection (anyone can modify them), and many other problems. + * The recommended pattern is to use a non-sticky broadcast to report that <em>something</em> + * has changed, with another mechanism for apps to retrieve the current value whenever + * desired. + * + * @param intent The Intent to broadcast; all receivers matching this + * Intent will receive the broadcast, and the Intent will be held to + * be re-broadcast to future receivers. + * @param options (optional) Additional sending options, generated from a + * {@link android.app.BroadcastOptions}. + * + * @see #sendBroadcast(Intent) + * @see #sendStickyOrderedBroadcast(Intent, BroadcastReceiver, Handler, int, String, Bundle) + */ + @Deprecated + @RequiresPermission(android.Manifest.permission.BROADCAST_STICKY) + public void sendStickyBroadcast(@RequiresPermission @NonNull Intent intent, + @Nullable Bundle options) { + throw new RuntimeException("Not implemented. Must override in a subclass."); + } + + /** * <p>Version of {@link #sendStickyBroadcast} that allows you to * receive data back from the broadcast. This is accomplished by * supplying your own BroadcastReceiver when calling, which will be @@ -4999,9 +5029,7 @@ public abstract class Context { * Service to capture a bugreport. * @see #getSystemService(String) * @see android.os.BugreportManager - * @hide */ - @SystemApi public static final String BUGREPORT_SERVICE = "bugreport"; /** diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java index 5bdd521e92dd..e351c244b04c 100644 --- a/core/java/android/content/ContextWrapper.java +++ b/core/java/android/content/ContextWrapper.java @@ -617,6 +617,35 @@ public class ContextWrapper extends Context { mBase.sendStickyBroadcast(intent); } + /** + * <p>Perform a {@link #sendBroadcast(Intent)} that is "sticky," meaning the + * Intent you are sending stays around after the broadcast is complete, + * so that others can quickly retrieve that data through the return + * value of {@link #registerReceiver(BroadcastReceiver, IntentFilter)}. In + * all other ways, this behaves the same as + * {@link #sendBroadcast(Intent)}. + * + * @deprecated Sticky broadcasts should not be used. They provide no security (anyone + * can access them), no protection (anyone can modify them), and many other problems. + * The recommended pattern is to use a non-sticky broadcast to report that <em>something</em> + * has changed, with another mechanism for apps to retrieve the current value whenever + * desired. + * + * @param intent The Intent to broadcast; all receivers matching this + * Intent will receive the broadcast, and the Intent will be held to + * be re-broadcast to future receivers. + * @param options (optional) Additional sending options, generated from a + * {@link android.app.BroadcastOptions}. + * + * @see #sendBroadcast(Intent) + * @see #sendStickyOrderedBroadcast(Intent, BroadcastReceiver, Handler, int, String, Bundle) + */ + @Override + @Deprecated + public void sendStickyBroadcast(@NonNull Intent intent, @Nullable Bundle options) { + mBase.sendStickyBroadcast(intent, options); + } + @Override @Deprecated public void sendStickyOrderedBroadcast( diff --git a/core/java/android/content/om/IOverlayManager.aidl b/core/java/android/content/om/IOverlayManager.aidl index 44b5c4482599..0b950b461285 100644 --- a/core/java/android/content/om/IOverlayManager.aidl +++ b/core/java/android/content/om/IOverlayManager.aidl @@ -17,6 +17,7 @@ package android.content.om; import android.content.om.OverlayInfo; +import android.content.om.OverlayManagerTransaction; /** * Api for getting information about overlay packages. @@ -163,4 +164,18 @@ interface IOverlayManager { * @param packageName The name of the overlay package whose idmap should be deleted. */ void invalidateCachesForOverlay(in String packageName, in int userIs); + + /** + * Perform a series of requests related to overlay packages. This is an + * atomic operation: either all requests were performed successfully and + * the changes were propagated to the rest of the system, or at least one + * request could not be performed successfully and nothing is changed and + * nothing is propagated to the rest of the system. + * + * @see OverlayManagerTransaction + * + * @param transaction the series of overlay related requests to perform + * @throws SecurityException if the transaction failed + */ + void commit(in OverlayManagerTransaction transaction); } diff --git a/core/java/android/content/om/OverlayManager.java b/core/java/android/content/om/OverlayManager.java index 217f637cf9e3..7c14c2891d01 100644 --- a/core/java/android/content/om/OverlayManager.java +++ b/core/java/android/content/om/OverlayManager.java @@ -254,6 +254,29 @@ public class OverlayManager { } /** + * Perform a series of requests related to overlay packages. This is an + * atomic operation: either all requests were performed successfully and + * the changes were propagated to the rest of the system, or at least one + * request could not be performed successfully and nothing is changed and + * nothing is propagated to the rest of the system. + * + * @see OverlayManagerTransaction + * + * @param transaction the series of overlay related requests to perform + * @throws Exception if not all the requests could be successfully and + * atomically executed + * + * @hide + */ + public void commit(@NonNull final OverlayManagerTransaction transaction) { + try { + mService.commit(transaction); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** * Starting on R, actor enforcement and app visibility changes introduce additional failure * cases, but the SecurityException thrown with these checks is unexpected for existing * consumers of the API. diff --git a/core/java/android/content/om/OverlayManagerTransaction.aidl b/core/java/android/content/om/OverlayManagerTransaction.aidl new file mode 100644 index 000000000000..6715c82d4e6f --- /dev/null +++ b/core/java/android/content/om/OverlayManagerTransaction.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.content.om; + +parcelable OverlayManagerTransaction; diff --git a/core/java/android/content/om/OverlayManagerTransaction.java b/core/java/android/content/om/OverlayManagerTransaction.java new file mode 100644 index 000000000000..1fa8973c35b5 --- /dev/null +++ b/core/java/android/content/om/OverlayManagerTransaction.java @@ -0,0 +1,216 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.content.om; + +import static com.android.internal.util.Preconditions.checkNotNull; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.os.Parcel; +import android.os.Parcelable; +import android.os.UserHandle; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +/** + * Container for a batch of requests to the OverlayManagerService. + * + * Transactions are created using a builder interface. Example usage: + * + * final OverlayManager om = ctx.getSystemService(OverlayManager.class); + * final OverlayManagerTransaction t = new OverlayManagerTransaction.Builder() + * .setEnabled(...) + * .setEnabled(...) + * .build(); + * om.commit(t); + * + * @hide + */ +public class OverlayManagerTransaction + implements Iterable<OverlayManagerTransaction.Request>, Parcelable { + // TODO: remove @hide from this class when OverlayManager is added to the + // SDK, but keep OverlayManagerTransaction.Request @hidden + private final List<Request> mRequests; + + OverlayManagerTransaction(@NonNull final List<Request> requests) { + checkNotNull(requests); + if (requests.contains(null)) { + throw new IllegalArgumentException("null request"); + } + mRequests = requests; + } + + private OverlayManagerTransaction(@NonNull final Parcel source) { + final int size = source.readInt(); + mRequests = new ArrayList<Request>(size); + for (int i = 0; i < size; i++) { + final int request = source.readInt(); + final String packageName = source.readString(); + final int userId = source.readInt(); + mRequests.add(new Request(request, packageName, userId)); + } + } + + @Override + public Iterator<Request> iterator() { + return mRequests.iterator(); + } + + @Override + public String toString() { + return String.format("OverlayManagerTransaction { mRequests = %s }", mRequests); + } + + /** + * A single unit of the transaction, such as a request to enable an + * overlay, or to disable an overlay. + * + * @hide + */ + public static class Request { + @IntDef(prefix = "TYPE_", value = { + TYPE_SET_ENABLED, + TYPE_SET_DISABLED, + }) + @Retention(RetentionPolicy.SOURCE) + @interface RequestType {} + + public static final int TYPE_SET_ENABLED = 0; + public static final int TYPE_SET_DISABLED = 1; + + @RequestType public final int type; + public final String packageName; + public final int userId; + + public Request(@RequestType final int type, @NonNull final String packageName, + final int userId) { + this.type = type; + this.packageName = packageName; + this.userId = userId; + } + + @Override + public String toString() { + return String.format("Request{type=0x%02x (%s), packageName=%s, userId=%d}", + type, typeToString(), packageName, userId); + } + + /** + * Translate the request type into a human readable string. Only + * intended for debugging. + * + * @hide + */ + public String typeToString() { + switch (type) { + case TYPE_SET_ENABLED: return "TYPE_SET_ENABLED"; + case TYPE_SET_DISABLED: return "TYPE_SET_DISABLED"; + default: return String.format("TYPE_UNKNOWN (0x%02x)", type); + } + } + } + + /** + * Builder class for OverlayManagerTransaction objects. + * + * @hide + */ + public static class Builder { + private final List<Request> mRequests = new ArrayList<>(); + + /** + * Request that an overlay package be enabled and change its loading + * order to the last package to be loaded, or disabled + * + * If the caller has the correct permissions, it is always possible to + * disable an overlay. Due to technical and security reasons it may not + * always be possible to enable an overlay, for instance if the overlay + * does not successfully overlay any target resources due to + * overlayable policy restrictions. + * + * An enabled overlay is a part of target package's resources, i.e. it will + * be part of any lookups performed via {@link android.content.res.Resources} + * and {@link android.content.res.AssetManager}. A disabled overlay will no + * longer affect the resources of the target package. If the target is + * currently running, its outdated resources will be replaced by new ones. + * + * @param packageName The name of the overlay package. + * @param enable true to enable the overlay, false to disable it. + * @return this Builder object, so you can chain additional requests + */ + public Builder setEnabled(@NonNull String packageName, boolean enable) { + return setEnabled(packageName, enable, UserHandle.myUserId()); + } + + /** + * @hide + */ + public Builder setEnabled(@NonNull String packageName, boolean enable, int userId) { + checkNotNull(packageName); + @Request.RequestType final int type = + enable ? Request.TYPE_SET_ENABLED : Request.TYPE_SET_DISABLED; + mRequests.add(new Request(type, packageName, userId)); + return this; + } + + /** + * Create a new transaction out of the requests added so far. Execute + * the transaction by calling OverlayManager#commit. + * + * @see OverlayManager#commit + * @return a new transaction + */ + public OverlayManagerTransaction build() { + return new OverlayManagerTransaction(mRequests); + } + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + final int size = mRequests.size(); + dest.writeInt(size); + for (int i = 0; i < size; i++) { + final Request req = mRequests.get(i); + dest.writeInt(req.type); + dest.writeString(req.packageName); + dest.writeInt(req.userId); + } + } + + public static final Parcelable.Creator<OverlayManagerTransaction> CREATOR = + new Parcelable.Creator<OverlayManagerTransaction>() { + + @Override + public OverlayManagerTransaction createFromParcel(Parcel source) { + return new OverlayManagerTransaction(source); + } + + @Override + public OverlayManagerTransaction[] newArray(int size) { + return new OverlayManagerTransaction[size]; + } + }; +} diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index 5e925b6a2bd8..47c7a1af029b 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -206,11 +206,11 @@ interface IConnectivityManager void startNattKeepalive(in Network network, int intervalSeconds, in ISocketKeepaliveCallback cb, String srcAddr, int srcPort, String dstAddr); - void startNattKeepaliveWithFd(in Network network, in FileDescriptor fd, int resourceId, + void startNattKeepaliveWithFd(in Network network, in ParcelFileDescriptor pfd, int resourceId, int intervalSeconds, in ISocketKeepaliveCallback cb, String srcAddr, String dstAddr); - void startTcpKeepalive(in Network network, in FileDescriptor fd, int intervalSeconds, + void startTcpKeepalive(in Network network, in ParcelFileDescriptor pfd, int intervalSeconds, in ISocketKeepaliveCallback cb); void stopKeepalive(in Network network, int slot); diff --git a/core/java/android/net/NattSocketKeepalive.java b/core/java/android/net/NattSocketKeepalive.java index b0ce0c71fbeb..a15d165e65e7 100644 --- a/core/java/android/net/NattSocketKeepalive.java +++ b/core/java/android/net/NattSocketKeepalive.java @@ -51,7 +51,7 @@ public final class NattSocketKeepalive extends SocketKeepalive { void startImpl(int intervalSec) { mExecutor.execute(() -> { try { - mService.startNattKeepaliveWithFd(mNetwork, mPfd.getFileDescriptor(), mResourceId, + mService.startNattKeepaliveWithFd(mNetwork, mPfd, mResourceId, intervalSec, mCallback, mSource.getHostAddress(), mDestination.getHostAddress()); } catch (RemoteException e) { diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java index 4f46736c087d..83a7d16fa2d9 100644 --- a/core/java/android/net/NetworkAgent.java +++ b/core/java/android/net/NetworkAgent.java @@ -227,12 +227,6 @@ public abstract class NetworkAgent { */ public static final String REDIRECT_URL_KEY = "redirect URL"; - /** - * Bundle key for the underlying networks in {@code EVENT_UNDERLYING_NETWORKS_CHANGED}. - * @hide - */ - public static final String UNDERLYING_NETWORKS_KEY = "underlyingNetworks"; - /** * Sent by the NetworkAgent to ConnectivityService to indicate this network was * explicitly selected. This should be sent before the NetworkInfo is marked diff --git a/core/java/android/net/TcpSocketKeepalive.java b/core/java/android/net/TcpSocketKeepalive.java index 436397ea7754..d89814d49bd0 100644 --- a/core/java/android/net/TcpSocketKeepalive.java +++ b/core/java/android/net/TcpSocketKeepalive.java @@ -21,7 +21,6 @@ import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.util.Log; -import java.io.FileDescriptor; import java.util.concurrent.Executor; /** @hide */ @@ -54,8 +53,7 @@ final class TcpSocketKeepalive extends SocketKeepalive { void startImpl(int intervalSec) { mExecutor.execute(() -> { try { - final FileDescriptor fd = mPfd.getFileDescriptor(); - mService.startTcpKeepalive(mNetwork, fd, intervalSec, mCallback); + mService.startTcpKeepalive(mNetwork, mPfd, intervalSec, mCallback); } catch (RemoteException e) { Log.e(TAG, "Error starting packet keepalive: ", e); throw e.rethrowFromSystemServer(); diff --git a/core/java/android/net/TestNetworkInterface.java b/core/java/android/net/TestNetworkInterface.java index 84550834be07..4449ff80180b 100644 --- a/core/java/android/net/TestNetworkInterface.java +++ b/core/java/android/net/TestNetworkInterface.java @@ -15,7 +15,8 @@ */ package android.net; -import android.annotation.TestApi; +import android.annotation.NonNull; +import android.annotation.SystemApi; import android.os.Parcel; import android.os.ParcelFileDescriptor; import android.os.Parcelable; @@ -25,9 +26,11 @@ import android.os.Parcelable; * * @hide */ -@TestApi +@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) public final class TestNetworkInterface implements Parcelable { + @NonNull private final ParcelFileDescriptor mFileDescriptor; + @NonNull private final String mInterfaceName; @Override @@ -36,29 +39,32 @@ public final class TestNetworkInterface implements Parcelable { } @Override - public void writeToParcel(Parcel out, int flags) { + public void writeToParcel(@NonNull Parcel out, int flags) { out.writeParcelable(mFileDescriptor, PARCELABLE_WRITE_RETURN_VALUE); out.writeString(mInterfaceName); } - public TestNetworkInterface(ParcelFileDescriptor pfd, String intf) { + public TestNetworkInterface(@NonNull ParcelFileDescriptor pfd, @NonNull String intf) { mFileDescriptor = pfd; mInterfaceName = intf; } - private TestNetworkInterface(Parcel in) { + private TestNetworkInterface(@NonNull Parcel in) { mFileDescriptor = in.readParcelable(ParcelFileDescriptor.class.getClassLoader()); mInterfaceName = in.readString(); } + @NonNull public ParcelFileDescriptor getFileDescriptor() { return mFileDescriptor; } + @NonNull public String getInterfaceName() { return mInterfaceName; } + @NonNull public static final Parcelable.Creator<TestNetworkInterface> CREATOR = new Parcelable.Creator<TestNetworkInterface>() { public TestNetworkInterface createFromParcel(Parcel in) { diff --git a/core/java/android/net/TestNetworkManager.java b/core/java/android/net/TestNetworkManager.java index a0a563b37025..4e894143bf91 100644 --- a/core/java/android/net/TestNetworkManager.java +++ b/core/java/android/net/TestNetworkManager.java @@ -17,18 +17,21 @@ package android.net; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.TestApi; +import android.annotation.SystemApi; import android.os.IBinder; import android.os.RemoteException; import com.android.internal.util.Preconditions; +import java.util.Arrays; +import java.util.Collection; + /** * Class that allows creation and management of per-app, test-only networks * * @hide */ -@TestApi +@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) public class TestNetworkManager { /** * Prefix for tun interfaces created by this class. @@ -57,7 +60,7 @@ public class TestNetworkManager { * @param network The test network that should be torn down * @hide */ - @TestApi + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) public void teardownTestNetwork(@NonNull Network network) { try { mService.teardownTestNetwork(network.netId); @@ -102,7 +105,7 @@ public class TestNetworkManager { * @param binder A binder object guarding the lifecycle of this test network. * @hide */ - @TestApi + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) public void setupTestNetwork(@NonNull String iface, @NonNull IBinder binder) { setupTestNetwork(iface, null, true, new int[0], binder); } @@ -127,12 +130,29 @@ public class TestNetworkManager { * @param linkAddrs an array of LinkAddresses to assign to the TUN interface * @return A ParcelFileDescriptor of the underlying TUN interface. Close this to tear down the * TUN interface. + * @deprecated Use {@link #createTunInterface(Collection)} instead. * @hide */ - @TestApi + @Deprecated + @NonNull public TestNetworkInterface createTunInterface(@NonNull LinkAddress[] linkAddrs) { + return createTunInterface(Arrays.asList(linkAddrs)); + } + + /** + * Create a tun interface for testing purposes + * + * @param linkAddrs an array of LinkAddresses to assign to the TUN interface + * @return A ParcelFileDescriptor of the underlying TUN interface. Close this to tear down the + * TUN interface. + * @hide + */ + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + @NonNull + public TestNetworkInterface createTunInterface(@NonNull Collection<LinkAddress> linkAddrs) { try { - return mService.createTunInterface(linkAddrs); + final LinkAddress[] arr = new LinkAddress[linkAddrs.size()]; + return mService.createTunInterface(linkAddrs.toArray(arr)); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -145,7 +165,8 @@ public class TestNetworkManager { * TAP interface. * @hide */ - @TestApi + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + @NonNull public TestNetworkInterface createTapInterface() { try { return mService.createTapInterface(); diff --git a/core/java/android/net/metrics/ApfProgramEvent.java b/core/java/android/net/metrics/ApfProgramEvent.java index ab12cdd22685..3d79f284fcd3 100644 --- a/core/java/android/net/metrics/ApfProgramEvent.java +++ b/core/java/android/net/metrics/ApfProgramEvent.java @@ -39,7 +39,11 @@ import java.util.List; * An event logged when there is a change or event that requires updating the * the APF program in place with a new APF program. * {@hide} + * @deprecated The event may not be sent in Android S and above. The events + * are logged by a single caller in the system using signature permissions + * and that caller is migrating to statsd. */ +@Deprecated @SystemApi public final class ApfProgramEvent implements IpConnectivityLog.Event { diff --git a/core/java/android/net/metrics/ApfStats.java b/core/java/android/net/metrics/ApfStats.java index fcafb7ebd676..a32d3a65b73a 100644 --- a/core/java/android/net/metrics/ApfStats.java +++ b/core/java/android/net/metrics/ApfStats.java @@ -27,7 +27,11 @@ import android.os.Parcelable; /** * An event logged for an interface with APF capabilities when its IpClient state machine exits. * {@hide} + * @deprecated The event may not be sent in Android S and above. The events + * are logged by a single caller in the system using signature permissions + * and that caller is migrating to statsd. */ +@Deprecated @SystemApi public final class ApfStats implements IpConnectivityLog.Event { diff --git a/core/java/android/net/metrics/DhcpClientEvent.java b/core/java/android/net/metrics/DhcpClientEvent.java index 8de427de1dab..e175d587c137 100644 --- a/core/java/android/net/metrics/DhcpClientEvent.java +++ b/core/java/android/net/metrics/DhcpClientEvent.java @@ -28,7 +28,11 @@ import android.text.TextUtils; /** * An event recorded when a DhcpClient state machine transitions to a new state. * {@hide} + * @deprecated The event may not be sent in Android S and above. The events + * are logged by a single caller in the system using signature permissions + * and that caller is migrating to statsd. */ +@Deprecated @SystemApi public final class DhcpClientEvent implements IpConnectivityLog.Event { diff --git a/core/java/android/net/metrics/DhcpErrorEvent.java b/core/java/android/net/metrics/DhcpErrorEvent.java index de3129d5e94d..7dd0696d81a3 100644 --- a/core/java/android/net/metrics/DhcpErrorEvent.java +++ b/core/java/android/net/metrics/DhcpErrorEvent.java @@ -27,7 +27,11 @@ import com.android.internal.util.MessageUtils; /** * Event class used to record error events when parsing DHCP response packets. * {@hide} + * @deprecated The event may not be sent in Android S and above. The events + * are logged by a single caller in the system using signature permissions + * and that caller is migrating to statsd. */ +@Deprecated @SystemApi public final class DhcpErrorEvent implements IpConnectivityLog.Event { public static final int L2_ERROR = 1; diff --git a/core/java/android/net/metrics/IpConnectivityLog.java b/core/java/android/net/metrics/IpConnectivityLog.java index 58ea91573775..5cadb45590bb 100644 --- a/core/java/android/net/metrics/IpConnectivityLog.java +++ b/core/java/android/net/metrics/IpConnectivityLog.java @@ -35,7 +35,11 @@ import com.android.internal.util.BitUtils; /** * Class for logging IpConnectvity events with IpConnectivityMetrics * {@hide} + * @deprecated The event may not be sent in Android S and above. The events + * are logged by a single caller in the system using signature permissions + * and that caller is migrating to statsd. */ +@Deprecated @SystemApi public class IpConnectivityLog { private static final String TAG = IpConnectivityLog.class.getSimpleName(); @@ -137,7 +141,7 @@ public class IpConnectivityLog { * @return true if the event was successfully logged. */ public boolean log(@NonNull Network network, @NonNull int[] transports, @NonNull Event data) { - return log(network.netId, transports, data); + return log(network.getNetId(), transports, data); } /** diff --git a/core/java/android/net/metrics/IpManagerEvent.java b/core/java/android/net/metrics/IpManagerEvent.java index 4f7f3263117b..3abcc0589dc1 100644 --- a/core/java/android/net/metrics/IpManagerEvent.java +++ b/core/java/android/net/metrics/IpManagerEvent.java @@ -33,7 +33,11 @@ import java.lang.annotation.RetentionPolicy; * An event recorded by IpClient when IP provisioning completes for a network or * when a network disconnects. * {@hide} + * @deprecated The event may not be sent in Android S and above. The events + * are logged by a single caller in the system using signature permissions + * and that caller is migrating to statsd. */ +@Deprecated @SystemApi public final class IpManagerEvent implements IpConnectivityLog.Event { diff --git a/core/java/android/net/metrics/IpReachabilityEvent.java b/core/java/android/net/metrics/IpReachabilityEvent.java index d5003badd614..0b65bbdbcbf6 100644 --- a/core/java/android/net/metrics/IpReachabilityEvent.java +++ b/core/java/android/net/metrics/IpReachabilityEvent.java @@ -29,7 +29,11 @@ import com.android.internal.util.MessageUtils; * An event recorded when IpReachabilityMonitor sends a neighbor probe or receives * a neighbor probe result. * {@hide} + * @deprecated The event may not be sent in Android S and above. The events + * are logged by a single caller in the system using signature permissions + * and that caller is migrating to statsd. */ +@Deprecated @SystemApi public final class IpReachabilityEvent implements IpConnectivityLog.Event { diff --git a/core/java/android/net/metrics/NetworkEvent.java b/core/java/android/net/metrics/NetworkEvent.java index 8c28f7a7d643..47eeeff90088 100644 --- a/core/java/android/net/metrics/NetworkEvent.java +++ b/core/java/android/net/metrics/NetworkEvent.java @@ -31,7 +31,11 @@ import java.lang.annotation.RetentionPolicy; /** * {@hide} + * @deprecated The event may not be sent in Android S and above. The events + * are logged by a single caller in the system using signature permissions + * and that caller is migrating to statsd. */ +@Deprecated @SystemApi public final class NetworkEvent implements IpConnectivityLog.Event { diff --git a/core/java/android/net/metrics/RaEvent.java b/core/java/android/net/metrics/RaEvent.java index b54874f5a573..05a47e55fce4 100644 --- a/core/java/android/net/metrics/RaEvent.java +++ b/core/java/android/net/metrics/RaEvent.java @@ -25,7 +25,11 @@ import android.os.Parcelable; /** * An event logged when the APF packet socket receives an RA packet. * {@hide} + * @deprecated The event may not be sent in Android S and above. The events + * are logged by a single caller in the system using signature permissions + * and that caller is migrating to statsd. */ +@Deprecated @SystemApi public final class RaEvent implements IpConnectivityLog.Event { diff --git a/core/java/android/net/metrics/ValidationProbeEvent.java b/core/java/android/net/metrics/ValidationProbeEvent.java index 7f4e4a73677e..8118fe005d5d 100644 --- a/core/java/android/net/metrics/ValidationProbeEvent.java +++ b/core/java/android/net/metrics/ValidationProbeEvent.java @@ -32,7 +32,11 @@ import java.lang.annotation.RetentionPolicy; /** * An event recorded by NetworkMonitor when sending a probe for finding captive portals. * {@hide} + * @deprecated The event may not be sent in Android S and above. The events + * are logged by a single caller in the system using signature permissions + * and that caller is migrating to statsd. */ +@Deprecated @SystemApi public final class ValidationProbeEvent implements IpConnectivityLog.Event { diff --git a/core/java/android/net/util/MultinetworkPolicyTracker.java b/core/java/android/net/util/MultinetworkPolicyTracker.java index 8dfd4e182ec4..85e3fa3048ed 100644 --- a/core/java/android/net/util/MultinetworkPolicyTracker.java +++ b/core/java/android/net/util/MultinetworkPolicyTracker.java @@ -29,7 +29,6 @@ import android.content.res.Resources; import android.database.ContentObserver; import android.net.Uri; import android.os.Handler; -import android.os.UserHandle; import android.provider.Settings; import android.telephony.PhoneStateListener; import android.telephony.SubscriptionManager; @@ -114,8 +113,8 @@ public class MultinetworkPolicyTracker { final IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED); - mContext.registerReceiverAsUser( - mBroadcastReceiver, UserHandle.ALL, intentFilter, null, mHandler); + mContext.registerReceiverForAllUsers(mBroadcastReceiver, intentFilter, + null /* broadcastPermission */, mHandler); reevaluate(); } diff --git a/core/java/android/net/vcn/IVcnManagementService.aidl b/core/java/android/net/vcn/IVcnManagementService.aidl index 04b585cdf420..80ac64b87d4d 100644 --- a/core/java/android/net/vcn/IVcnManagementService.aidl +++ b/core/java/android/net/vcn/IVcnManagementService.aidl @@ -16,6 +16,7 @@ package android.net.vcn; +import android.net.vcn.IVcnUnderlyingNetworkPolicyListener; import android.net.vcn.VcnConfig; import android.os.ParcelUuid; @@ -25,4 +26,7 @@ import android.os.ParcelUuid; interface IVcnManagementService { void setVcnConfig(in ParcelUuid subscriptionGroup, in VcnConfig config, in String opPkgName); void clearVcnConfig(in ParcelUuid subscriptionGroup); + + void addVcnUnderlyingNetworkPolicyListener(in IVcnUnderlyingNetworkPolicyListener listener); + void removeVcnUnderlyingNetworkPolicyListener(in IVcnUnderlyingNetworkPolicyListener listener); } diff --git a/core/java/android/net/vcn/IVcnUnderlyingNetworkPolicyListener.aidl b/core/java/android/net/vcn/IVcnUnderlyingNetworkPolicyListener.aidl new file mode 100644 index 000000000000..f8ae492016f0 --- /dev/null +++ b/core/java/android/net/vcn/IVcnUnderlyingNetworkPolicyListener.aidl @@ -0,0 +1,22 @@ +/* + * 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.vcn; + +/** @hide */ +interface IVcnUnderlyingNetworkPolicyListener { + void onPolicyChanged(); +}
\ No newline at end of file diff --git a/core/java/android/net/vcn/VcnGatewayConnectionConfig.java b/core/java/android/net/vcn/VcnGatewayConnectionConfig.java index 039360a69a3a..d531cdb2a6e9 100644 --- a/core/java/android/net/vcn/VcnGatewayConnectionConfig.java +++ b/core/java/android/net/vcn/VcnGatewayConnectionConfig.java @@ -15,8 +15,6 @@ */ package android.net.vcn; -import static android.net.NetworkCapabilities.NetCapability; - import static com.android.internal.annotations.VisibleForTesting.Visibility; import android.annotation.IntRange; @@ -233,7 +231,7 @@ public final class VcnGatewayConnectionConfig { * * @param capability the capability to check for */ - public boolean hasExposedCapability(@NetCapability int capability) { + public boolean hasExposedCapability(int capability) { checkValidCapability(capability); return mExposedCapabilities.contains(capability); @@ -254,7 +252,7 @@ public final class VcnGatewayConnectionConfig { * * @param capability the capability to check for */ - public boolean requiresUnderlyingCapability(@NetCapability int capability) { + public boolean requiresUnderlyingCapability(int capability) { checkValidCapability(capability); return mUnderlyingCapabilities.contains(capability); @@ -341,7 +339,7 @@ public final class VcnGatewayConnectionConfig { * @see VcnGatewayConnectionConfig for a list of capabilities may be exposed by a Gateway * Connection */ - public Builder addExposedCapability(@NetCapability int exposedCapability) { + public Builder addExposedCapability(int exposedCapability) { checkValidCapability(exposedCapability); mExposedCapabilities.add(exposedCapability); @@ -357,7 +355,7 @@ public final class VcnGatewayConnectionConfig { * @see VcnGatewayConnectionConfig for a list of capabilities may be exposed by a Gateway * Connection */ - public Builder removeExposedCapability(@NetCapability int exposedCapability) { + public Builder removeExposedCapability(int exposedCapability) { checkValidCapability(exposedCapability); mExposedCapabilities.remove(exposedCapability); @@ -373,7 +371,7 @@ public final class VcnGatewayConnectionConfig { * @see VcnGatewayConnectionConfig for a list of capabilities may be required of underlying * networks */ - public Builder addRequiredUnderlyingCapability(@NetCapability int underlyingCapability) { + public Builder addRequiredUnderlyingCapability(int underlyingCapability) { checkValidCapability(underlyingCapability); mUnderlyingCapabilities.add(underlyingCapability); @@ -393,7 +391,7 @@ public final class VcnGatewayConnectionConfig { * @see VcnGatewayConnectionConfig for a list of capabilities may be required of underlying * networks */ - public Builder removeRequiredUnderlyingCapability(@NetCapability int underlyingCapability) { + public Builder removeRequiredUnderlyingCapability(int underlyingCapability) { checkValidCapability(underlyingCapability); mUnderlyingCapabilities.remove(underlyingCapability); diff --git a/core/java/android/net/vcn/VcnManager.java b/core/java/android/net/vcn/VcnManager.java index b881a339535b..2ccdc2633af0 100644 --- a/core/java/android/net/vcn/VcnManager.java +++ b/core/java/android/net/vcn/VcnManager.java @@ -25,7 +25,12 @@ import android.os.ParcelUuid; import android.os.RemoteException; import android.os.ServiceSpecificException; +import com.android.internal.annotations.VisibleForTesting; + import java.io.IOException; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Executor; /** * VcnManager publishes APIs for applications to configure and manage Virtual Carrier Networks. @@ -60,6 +65,11 @@ import java.io.IOException; public final class VcnManager { @NonNull private static final String TAG = VcnManager.class.getSimpleName(); + @VisibleForTesting + public static final Map< + VcnUnderlyingNetworkPolicyListener, VcnUnderlyingNetworkPolicyListenerBinder> + REGISTERED_POLICY_LISTENERS = new ConcurrentHashMap<>(); + @NonNull private final Context mContext; @NonNull private final IVcnManagementService mService; @@ -136,4 +146,101 @@ public final class VcnManager { throw e.rethrowFromSystemServer(); } } + + // TODO: make VcnUnderlyingNetworkPolicyListener @SystemApi + /** + * VcnUnderlyingNetworkPolicyListener is the interface through which internal system components + * can register to receive updates for VCN-underlying Network policies from the System Server. + * + * @hide + */ + public interface VcnUnderlyingNetworkPolicyListener { + /** + * Notifies the implementation that the VCN's underlying Network policy has changed. + * + * <p>After receiving this callback, implementations MUST poll VcnManager for the updated + * VcnUnderlyingNetworkPolicy via VcnManager#getUnderlyingNetworkPolicy. + */ + void onPolicyChanged(); + } + + /** + * Add a listener for VCN-underlying network policy updates. + * + * @param executor the Executor that will be used for invoking all calls to the specified + * Listener + * @param listener the VcnUnderlyingNetworkPolicyListener to be added + * @throws SecurityException if the caller does not have permission NETWORK_FACTORY + * @throws IllegalArgumentException if the specified VcnUnderlyingNetworkPolicyListener is + * already registered + * @hide + */ + @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) + public void addVcnUnderlyingNetworkPolicyListener( + @NonNull Executor executor, @NonNull VcnUnderlyingNetworkPolicyListener listener) { + requireNonNull(executor, "executor must not be null"); + requireNonNull(listener, "listener must not be null"); + + VcnUnderlyingNetworkPolicyListenerBinder binder = + new VcnUnderlyingNetworkPolicyListenerBinder(executor, listener); + if (REGISTERED_POLICY_LISTENERS.putIfAbsent(listener, binder) != null) { + throw new IllegalArgumentException( + "Attempting to add a listener that is already in use"); + } + + try { + mService.addVcnUnderlyingNetworkPolicyListener(binder); + } catch (RemoteException e) { + REGISTERED_POLICY_LISTENERS.remove(listener); + throw e.rethrowFromSystemServer(); + } + } + + /** + * Remove the specified VcnUnderlyingNetworkPolicyListener from VcnManager. + * + * <p>If the specified listener is not currently registered, this is a no-op. + * + * @param listener the VcnUnderlyingNetworkPolicyListener that will be removed + * @hide + */ + public void removeVcnUnderlyingNetworkPolicyListener( + @NonNull VcnUnderlyingNetworkPolicyListener listener) { + requireNonNull(listener, "listener must not be null"); + + VcnUnderlyingNetworkPolicyListenerBinder binder = + REGISTERED_POLICY_LISTENERS.remove(listener); + if (binder == null) { + return; + } + + try { + mService.removeVcnUnderlyingNetworkPolicyListener(binder); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Binder wrapper for added VcnUnderlyingNetworkPolicyListeners to receive signals from System + * Server. + * + * @hide + */ + private static class VcnUnderlyingNetworkPolicyListenerBinder + extends IVcnUnderlyingNetworkPolicyListener.Stub { + @NonNull private final Executor mExecutor; + @NonNull private final VcnUnderlyingNetworkPolicyListener mListener; + + private VcnUnderlyingNetworkPolicyListenerBinder( + Executor executor, VcnUnderlyingNetworkPolicyListener listener) { + mExecutor = executor; + mListener = listener; + } + + @Override + public void onPolicyChanged() { + mExecutor.execute(() -> mListener.onPolicyChanged()); + } + } } diff --git a/core/java/android/net/vcn/VcnUnderlyingNetworkPolicy.aidl b/core/java/android/net/vcn/VcnUnderlyingNetworkPolicy.aidl new file mode 100644 index 000000000000..6cb6ee685a64 --- /dev/null +++ b/core/java/android/net/vcn/VcnUnderlyingNetworkPolicy.aidl @@ -0,0 +1,20 @@ +/* + * 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.vcn; + +/** @hide */ +parcelable VcnUnderlyingNetworkPolicy; diff --git a/core/java/android/net/vcn/VcnUnderlyingNetworkPolicy.java b/core/java/android/net/vcn/VcnUnderlyingNetworkPolicy.java new file mode 100644 index 000000000000..dd7c86d87ff2 --- /dev/null +++ b/core/java/android/net/vcn/VcnUnderlyingNetworkPolicy.java @@ -0,0 +1,110 @@ +/* + * 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.vcn; + +import android.annotation.NonNull; +import android.net.NetworkCapabilities; +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.Objects; + +/** + * VcnUnderlyingNetworkPolicy represents the Network policy for a VCN-managed Network. + * + * <p>Transports that are bringing up networks capable of acting as a VCN's underlying network + * should query for policy state upon major capability changes (e.g. changing of TRUSTED bit), and + * when prompted by VcnManagementService via VcnUnderlyingNetworkPolicyListener. + * + * @hide + */ +public final class VcnUnderlyingNetworkPolicy implements Parcelable { + private final boolean mIsTearDownRequested; + private final NetworkCapabilities mMergedNetworkCapabilities; + + /** + * Constructs a VcnUnderlyingNetworkPolicy with the specified parameters. + * + * @hide + */ + public VcnUnderlyingNetworkPolicy( + boolean isTearDownRequested, @NonNull NetworkCapabilities mergedNetworkCapabilities) { + Objects.requireNonNull( + mergedNetworkCapabilities, "mergedNetworkCapabilities must be nonnull"); + + mIsTearDownRequested = isTearDownRequested; + mMergedNetworkCapabilities = mergedNetworkCapabilities; + } + + /** + * Returns whether this Carrier VCN policy policy indicates that the underlying Network should + * be torn down. + */ + public boolean isTeardownRequested() { + return mIsTearDownRequested; + } + + /** + * Returns the NetworkCapabilities with Carrier VCN policy bits merged into the provided + * capabilities. + */ + @NonNull + public NetworkCapabilities getMergedNetworkCapabilities() { + return mMergedNetworkCapabilities; + } + + @Override + public int hashCode() { + return Objects.hash(mIsTearDownRequested, mMergedNetworkCapabilities); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof VcnUnderlyingNetworkPolicy)) return false; + final VcnUnderlyingNetworkPolicy that = (VcnUnderlyingNetworkPolicy) o; + + return mIsTearDownRequested == that.mIsTearDownRequested + && mMergedNetworkCapabilities.equals(that.mMergedNetworkCapabilities); + } + + /** {@inheritDoc} */ + @Override + public int describeContents() { + return 0; + } + + /** {@inheritDoc} */ + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeBoolean(mIsTearDownRequested); + dest.writeParcelable(mMergedNetworkCapabilities, flags); + } + + /** Implement the Parcelable interface */ + public static final @NonNull Creator<VcnUnderlyingNetworkPolicy> CREATOR = + new Creator<VcnUnderlyingNetworkPolicy>() { + public VcnUnderlyingNetworkPolicy createFromParcel(Parcel in) { + return new VcnUnderlyingNetworkPolicy( + in.readBoolean(), in.readParcelable(null)); + } + + public VcnUnderlyingNetworkPolicy[] newArray(int size) { + return new VcnUnderlyingNetworkPolicy[size]; + } + }; +} diff --git a/core/java/android/nfc/INfcAdapter.aidl b/core/java/android/nfc/INfcAdapter.aidl index 0b2cfdd9ece3..bc3d5c4ab1ac 100644 --- a/core/java/android/nfc/INfcAdapter.aidl +++ b/core/java/android/nfc/INfcAdapter.aidl @@ -72,4 +72,7 @@ interface INfcAdapter boolean deviceSupportsNfcSecure(); boolean setNfcSecure(boolean enable); + boolean setAlwaysOn(boolean value); + boolean isAlwaysOnEnabled(); + boolean isAlwaysOnSupported(); } diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java index a17a5370e787..e85eb935a8e7 100644 --- a/core/java/android/nfc/NfcAdapter.java +++ b/core/java/android/nfc/NfcAdapter.java @@ -350,6 +350,22 @@ public final class NfcAdapter { "android.nfc.extra.HANDOVER_TRANSFER_STATUS"; /** @hide */ + public static final String ACTION_ALWAYS_ON_STATE_CHANGED = + "android.nfc.action.ALWAYS_ON_STATE_CHANGED"; + + /** + * Used as an int extra field in {@link #ACTION_ALWAYS_ON_STATE_CHANGED} + * intents to request the current power state. Possible values are: + * {@link #STATE_OFF}, + * {@link #STATE_TURNING_ON}, + * {@link #STATE_ON}, + * {@link #STATE_TURNING_OFF}, + * @hide + */ + public static final String EXTRA_ALWAYS_ON_STATE = + "android.nfc.extra.ALWAYS_ON_STATE"; + + /** @hide */ public static final int HANDOVER_TRANSFER_STATUS_SUCCESS = 0; /** @hide */ public static final int HANDOVER_TRANSFER_STATUS_FAILURE = 1; @@ -358,6 +374,14 @@ public final class NfcAdapter { public static final String EXTRA_HANDOVER_TRANSFER_URI = "android.nfc.extra.HANDOVER_TRANSFER_URI"; + /** + * Broadcast Action: Notify possible NFC transaction blocked because device is locked. + * <p>An external NFC field detected when device locked and SecureNfc enabled. + * @hide + */ + public static final String ACTION_REQUIRE_UNLOCK_FOR_NFC = + "android.nfc.action.REQUIRE_UNLOCK_FOR_NFC"; + // Guarded by NfcAdapter.class static boolean sIsInitialized = false; static boolean sHasNfcFeature; @@ -2211,4 +2235,106 @@ public final class NfcAdapter { return mContext.getApplicationInfo().targetSdkVersion; } } + + /** + * Sets NFC controller always on feature. + * <p>This API is for the NFCC internal state management. It allows to discriminate + * the controller function from the NFC function by keeping the NFC Controller on without + * any NFC RF enabled if necessary. + * <p>This call is asynchronous. Listen for {@link #ACTION_ALWAYS_ON_STATE_CHANGED} + * broadcasts to find out when the operation is complete. + * <p>If this returns true, then either NFCC is already on, or + * a {@link #ACTION_ALWAYS_ON_STATE_CHANGED} broadcast will be sent to indicate + * a state transition. + * If this returns false, then there is some problem that prevents an attempt to turn NFCC on. + * @param value if true the NFCC will be kept on (with no RF enabled if NFC adapter is + * disabled), if false the NFCC will follow completely the Nfc adapter state. + * @throws UnsupportedOperationException if FEATURE_NFC is unavailable. + * @return void + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) + public boolean setAlwaysOn(boolean value) { + if (!sHasNfcFeature) { + throw new UnsupportedOperationException(); + } + try { + return sService.setAlwaysOn(value); + } catch (RemoteException e) { + attemptDeadServiceRecovery(e); + // Try one more time + if (sService == null) { + Log.e(TAG, "Failed to recover NFC Service."); + return false; + } + try { + return sService.setAlwaysOn(value); + } catch (RemoteException ee) { + Log.e(TAG, "Failed to recover NFC Service."); + } + return false; + } + } + + /** + * Checks NFC controller always on feature is enabled. + * + * @return True if NFC controller always on is enabled, false otherwise + * @throws UnsupportedOperationException if FEATURE_NFC is unavailable. + * @hide + */ + + @SystemApi + @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) + public boolean isAlwaysOnEnabled() { + try { + return sService.isAlwaysOnEnabled(); + } catch (RemoteException e) { + attemptDeadServiceRecovery(e); + // Try one more time + if (sService == null) { + Log.e(TAG, "Failed to recover NFC Service."); + return false; + } + try { + return sService.isAlwaysOnEnabled(); + } catch (RemoteException ee) { + Log.e(TAG, "Failed to recover NFC Service."); + } + return false; + } + } + + /** + * Checks if the device supports NFC controller always on functionality. + * + * @return True if device supports NFC controller always on, false otherwise + * @throws UnsupportedOperationException if FEATURE_NFC is unavailable. + * @hide + */ + + @SystemApi + @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) + public boolean isAlwaysOnSupported() { + if (!sHasNfcFeature) { + throw new UnsupportedOperationException(); + } + try { + return sService.isAlwaysOnSupported(); + } catch (RemoteException e) { + attemptDeadServiceRecovery(e); + // Try one more time + if (sService == null) { + Log.e(TAG, "Failed to recover NFC Service."); + return false; + } + try { + return sService.isAlwaysOnSupported(); + } catch (RemoteException ee) { + Log.e(TAG, "Failed to recover NFC Service."); + } + return false; + } + } } diff --git a/core/java/android/nfc/tech/Ndef.java b/core/java/android/nfc/tech/Ndef.java index fdccaae9cb1b..225636565480 100644 --- a/core/java/android/nfc/tech/Ndef.java +++ b/core/java/android/nfc/tech/Ndef.java @@ -112,7 +112,7 @@ public final class Ndef extends BasicTagTechnology { public static final String NFC_FORUM_TYPE_1 = "org.nfcforum.ndef.type1"; /** NFC Forum Tag Type 2 */ public static final String NFC_FORUM_TYPE_2 = "org.nfcforum.ndef.type2"; - /** NFC Forum Tag Type 4 */ + /** NFC Forum Tag Type 3 */ public static final String NFC_FORUM_TYPE_3 = "org.nfcforum.ndef.type3"; /** NFC Forum Tag Type 4 */ public static final String NFC_FORUM_TYPE_4 = "org.nfcforum.ndef.type4"; diff --git a/core/java/android/os/BugreportManager.java b/core/java/android/os/BugreportManager.java index 46ad7b880a37..305c686f8657 100644 --- a/core/java/android/os/BugreportManager.java +++ b/core/java/android/os/BugreportManager.java @@ -22,11 +22,11 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; +import android.annotation.SuppressAutoDoc; import android.annotation.SystemApi; import android.annotation.SystemService; import android.app.ActivityManager; import android.content.Context; -import android.os.Handler; import android.util.Log; import android.widget.Toast; @@ -41,12 +41,7 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.concurrent.Executor; -/** - * Class that provides a privileged API to capture and consume bugreports. - * - * @hide - */ -@SystemApi +/** Class that provides a privileged API to capture and consume bugreports. */ @SystemService(Context.BUGREPORT_SERVICE) public final class BugreportManager { @@ -61,28 +56,30 @@ public final class BugreportManager { mBinder = binder; } - /** - * An interface describing the callback for bugreport progress and status. - */ + /** An interface describing the callback for bugreport progress and status. */ public abstract static class BugreportCallback { - /** @hide */ + /** + * Possible error codes taking a bugreport can encounter. + * + * @hide + */ @Retention(RetentionPolicy.SOURCE) - @IntDef(prefix = { "BUGREPORT_ERROR_" }, value = { - BUGREPORT_ERROR_INVALID_INPUT, - BUGREPORT_ERROR_RUNTIME, - BUGREPORT_ERROR_USER_DENIED_CONSENT, - BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT, - BUGREPORT_ERROR_ANOTHER_REPORT_IN_PROGRESS - }) - - /** Possible error codes taking a bugreport can encounter */ + @IntDef( + prefix = {"BUGREPORT_ERROR_"}, + value = { + BUGREPORT_ERROR_INVALID_INPUT, + BUGREPORT_ERROR_RUNTIME, + BUGREPORT_ERROR_USER_DENIED_CONSENT, + BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT, + BUGREPORT_ERROR_ANOTHER_REPORT_IN_PROGRESS + }) public @interface BugreportErrorCode {} /** The input options were invalid */ public static final int BUGREPORT_ERROR_INVALID_INPUT = IDumpstateListener.BUGREPORT_ERROR_INVALID_INPUT; - /** A runtime error occured */ + /** A runtime error occurred */ public static final int BUGREPORT_ERROR_RUNTIME = IDumpstateListener.BUGREPORT_ERROR_RUNTIME_ERROR; @@ -100,6 +97,7 @@ public final class BugreportManager { /** * Called when there is a progress update. + * * @param progress the progress in [0.0, 100.0] */ public void onProgress(@FloatRange(from = 0f, to = 100f) float progress) {} @@ -114,14 +112,12 @@ public final class BugreportManager { * out, but the bugreport could be available in the internal directory of dumpstate for * manual retrieval. * - * <p> If {@code BUGREPORT_ERROR_ANOTHER_REPORT_IN_PROGRESS} is passed, then the - * caller should try later, as only one bugreport can be in progress at a time. + * <p>If {@code BUGREPORT_ERROR_ANOTHER_REPORT_IN_PROGRESS} is passed, then the caller + * should try later, as only one bugreport can be in progress at a time. */ public void onError(@BugreportErrorCode int errorCode) {} - /** - * Called when taking bugreport finishes successfully. - */ + /** Called when taking bugreport finishes successfully. */ public void onFinished() {} /** @@ -138,20 +134,23 @@ public final class BugreportManager { * seconds to return in the worst case. {@code callback} will receive progress and status * updates. * - * <p>The bugreport artifacts will be copied over to the given file descriptors only if the - * user consents to sharing with the calling app. + * <p>The bugreport artifacts will be copied over to the given file descriptors only if the user + * consents to sharing with the calling app. * * <p>{@link BugreportManager} takes ownership of {@code bugreportFd} and {@code screenshotFd}. * - * @param bugreportFd file to write the bugreport. This should be opened in write-only, - * append mode. - * @param screenshotFd file to write the screenshot, if necessary. This should be opened - * in write-only, append mode. + * @param bugreportFd file to write the bugreport. This should be opened in write-only, append + * mode. + * @param screenshotFd file to write the screenshot, if necessary. This should be opened in + * write-only, append mode. * @param params options that specify what kind of a bugreport should be taken * @param callback callback for progress and status updates + * @hide */ + @SystemApi @RequiresPermission(android.Manifest.permission.DUMP) - public void startBugreport(@NonNull ParcelFileDescriptor bugreportFd, + public void startBugreport( + @NonNull ParcelFileDescriptor bugreportFd, @Nullable ParcelFileDescriptor screenshotFd, @NonNull BugreportParams params, @NonNull @CallbackExecutor Executor executor, @@ -165,17 +164,21 @@ public final class BugreportManager { boolean isScreenshotRequested = screenshotFd != null; if (screenshotFd == null) { // Binder needs a valid File Descriptor to be passed - screenshotFd = ParcelFileDescriptor.open(new File("/dev/null"), - ParcelFileDescriptor.MODE_READ_ONLY); + screenshotFd = + ParcelFileDescriptor.open( + new File("/dev/null"), ParcelFileDescriptor.MODE_READ_ONLY); } - DumpstateListener dsListener = new DumpstateListener(executor, callback, - isScreenshotRequested); + DumpstateListener dsListener = + new DumpstateListener(executor, callback, isScreenshotRequested); // Note: mBinder can get callingUid from the binder transaction. - mBinder.startBugreport(-1 /* callingUid */, + mBinder.startBugreport( + -1 /* callingUid */, mContext.getOpPackageName(), bugreportFd.getFileDescriptor(), screenshotFd.getFileDescriptor(), - params.getMode(), dsListener, isScreenshotRequested); + params.getMode(), + dsListener, + isScreenshotRequested); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } catch (FileNotFoundException e) { @@ -189,13 +192,64 @@ public final class BugreportManager { } } - /* - * Cancels a currently running bugreport. + /** + * Starts a connectivity bugreport. + * + * <p>The connectivity bugreport is a specialized version of bugreport that only includes + * information specifically for debugging connectivity-related issues (e.g. telephony, wi-fi, + * and IP networking issues). It is intended primarily for use by OEMs and network providers + * such as mobile network operators. In addition to generally excluding information that isn't + * targeted to connectivity debugging, this type of bugreport excludes PII and sensitive + * information that isn't strictly necessary for connectivity debugging. + * + * <p>The calling app MUST have a context-specific reason for requesting a connectivity + * bugreport, such as detecting a connectivity-related issue. This API SHALL NOT be used to + * perform random sampling from a fleet of public end-user devices. + * + * <p>Calling this API will cause the system to ask the user for consent every single time. The + * bugreport artifacts will be copied over to the given file descriptors only if the user + * consents to sharing with the calling app. + * + * <p>This starts a bugreport in the background. However the call itself can take several + * seconds to return in the worst case. {@code callback} will receive progress and status + * updates. + * + * <p>Requires that the calling app has carrier privileges (see {@link + * android.telephony.TelephonyManager#hasCarrierPrivileges}) on any active subscription. + * + * @param bugreportFd file to write the bugreport. This should be opened in write-only, append + * mode. + * @param callback callback for progress and status updates. */ - @RequiresPermission(android.Manifest.permission.DUMP) + @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges + public void startConnectivityBugreport( + @NonNull ParcelFileDescriptor bugreportFd, + @NonNull @CallbackExecutor Executor executor, + @NonNull BugreportCallback callback) { + startBugreport( + bugreportFd, + null /* screenshotFd */, + new BugreportParams(BugreportParams.BUGREPORT_MODE_TELEPHONY), + executor, + callback); + } + + /** + * Cancels the currently running bugreport. + * + * <p>Apps are only able to cancel their own bugreports. App A cannot cancel a bugreport started + * by app B. + * + * <p>Requires permission: {@link android.Manifest.permission#DUMP} or that the calling app has + * carrier privileges (see {@link android.telephony.TelephonyManager#hasCarrierPrivileges}) on + * any active subscription. + * + * @throws SecurityException if trying to cancel another app's bugreport in progress + */ + @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges public void cancelBugreport() { try { - mBinder.cancelBugreport(); + mBinder.cancelBugreport(-1 /* callingUid */, mContext.getOpPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -205,23 +259,26 @@ public final class BugreportManager { * Requests a bugreport. * * <p>This requests the platform/system to take a bugreport and makes the final bugreport - * available to the user. The user may choose to share it with another app, but the bugreport - * is never given back directly to the app that requested it. + * available to the user. The user may choose to share it with another app, but the bugreport is + * never given back directly to the app that requested it. * - * @param params {@link BugreportParams} that specify what kind of a bugreport should - * be taken, please note that not all kinds of bugreport allow for a - * progress notification - * @param shareTitle title on the final share notification + * @param params {@link BugreportParams} that specify what kind of a bugreport should be taken, + * please note that not all kinds of bugreport allow for a progress notification + * @param shareTitle title on the final share notification * @param shareDescription description on the final share notification + * @hide */ + @SystemApi @RequiresPermission(android.Manifest.permission.DUMP) - public void requestBugreport(@NonNull BugreportParams params, @Nullable CharSequence shareTitle, + public void requestBugreport( + @NonNull BugreportParams params, + @Nullable CharSequence shareTitle, @Nullable CharSequence shareDescription) { try { String title = shareTitle == null ? null : shareTitle.toString(); String description = shareDescription == null ? null : shareDescription.toString(); - ActivityManager.getService().requestBugReportWithDescription(title, description, - params.getMode()); + ActivityManager.getService() + .requestBugReportWithDescription(title, description, params.getMode()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -232,8 +289,8 @@ public final class BugreportManager { private final BugreportCallback mCallback; private final boolean mIsScreenshotRequested; - DumpstateListener(Executor executor, BugreportCallback callback, - boolean isScreenshotRequested) { + DumpstateListener( + Executor executor, BugreportCallback callback, boolean isScreenshotRequested) { mExecutor = executor; mCallback = callback; mIsScreenshotRequested = isScreenshotRequested; @@ -243,9 +300,7 @@ public final class BugreportManager { public void onProgress(int progress) throws RemoteException { final long identity = Binder.clearCallingIdentity(); try { - mExecutor.execute(() -> { - mCallback.onProgress(progress); - }); + mExecutor.execute(() -> mCallback.onProgress(progress)); } finally { Binder.restoreCallingIdentity(identity); } @@ -255,9 +310,7 @@ public final class BugreportManager { public void onError(int errorCode) throws RemoteException { final long identity = Binder.clearCallingIdentity(); try { - mExecutor.execute(() -> { - mCallback.onError(errorCode); - }); + mExecutor.execute(() -> mCallback.onError(errorCode)); } finally { Binder.restoreCallingIdentity(identity); } @@ -267,9 +320,7 @@ public final class BugreportManager { public void onFinished() throws RemoteException { final long identity = Binder.clearCallingIdentity(); try { - mExecutor.execute(() -> { - mCallback.onFinished(); - }); + mExecutor.execute(() -> mCallback.onFinished()); } finally { Binder.restoreCallingIdentity(identity); } @@ -284,20 +335,19 @@ public final class BugreportManager { Handler mainThreadHandler = new Handler(Looper.getMainLooper()); mainThreadHandler.post( () -> { - int message = success ? R.string.bugreport_screenshot_success_toast - : R.string.bugreport_screenshot_failure_toast; + int message = + success + ? R.string.bugreport_screenshot_success_toast + : R.string.bugreport_screenshot_failure_toast; Toast.makeText(mContext, message, Toast.LENGTH_LONG).show(); }); } @Override - public void onUiIntensiveBugreportDumpsFinished() - throws RemoteException { + public void onUiIntensiveBugreportDumpsFinished() throws RemoteException { final long identity = Binder.clearCallingIdentity(); try { - mExecutor.execute(() -> { - mCallback.onEarlyReportFinished(); - }); + mExecutor.execute(() -> mCallback.onEarlyReportFinished()); } finally { Binder.restoreCallingIdentity(identity); } diff --git a/core/java/android/os/storage/DiskInfo.java b/core/java/android/os/storage/DiskInfo.java index df3c4d55d979..51856d8bb723 100644 --- a/core/java/android/os/storage/DiskInfo.java +++ b/core/java/android/os/storage/DiskInfo.java @@ -50,6 +50,8 @@ public class DiskInfo implements Parcelable { public static final int FLAG_DEFAULT_PRIMARY = 1 << 1; public static final int FLAG_SD = 1 << 2; public static final int FLAG_USB = 1 << 3; + /** The FLAG_STUB_VISIBLE is set from vold, which gets the flag from outside (e.g., ChromeOS) */ + public static final int FLAG_STUB_VISIBLE = 1 << 6; public final String id; @UnsupportedAppUsage @@ -152,6 +154,10 @@ public class DiskInfo implements Parcelable { return (flags & FLAG_USB) != 0; } + public boolean isStubVisible() { + return (flags & FLAG_STUB_VISIBLE) != 0; + } + @Override public String toString() { final CharArrayWriter writer = new CharArrayWriter(); diff --git a/core/java/android/os/storage/IStorageManager.aidl b/core/java/android/os/storage/IStorageManager.aidl index 99bdfd1fc103..4669b208b163 100644 --- a/core/java/android/os/storage/IStorageManager.aidl +++ b/core/java/android/os/storage/IStorageManager.aidl @@ -195,4 +195,5 @@ interface IStorageManager { void abortChanges(in String message, boolean retry) = 87; void clearUserKeyAuth(int userId, int serialNumber, in byte[] token, in byte[] secret) = 88; void fixupAppDir(in String path) = 89; + void disableAppDataIsolation(in String pkgName, int pid, int userId) = 90; } diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 4086161603a4..0f7365dcfd90 100755 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -999,6 +999,20 @@ public final class Settings { "android.settings.MANAGE_ALL_APPLICATIONS_SETTINGS"; /** + * Activity Action: Show settings to manage all SIM profiles. + * <p> + * In some cases, a matching Activity may not exist, so ensure you + * safeguard against this. + * <p> + * Input: Nothing. + * <p> + * Output: Nothing. + */ + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) + public static final String ACTION_MANAGE_ALL_SUBSCRIPTIONS_SETTINGS = + "android.settings.MANAGE_ALL_SUBSCRIPTIONS_SETTINGS"; + + /** * Activity Action: Show screen for controlling which apps can draw on top of other apps. * <p> * In some cases, a matching Activity may not exist, so ensure you safeguard against this. diff --git a/core/java/android/se/OWNERS b/core/java/android/se/OWNERS index f1539dc55d59..5682fd3281f4 100644 --- a/core/java/android/se/OWNERS +++ b/core/java/android/se/OWNERS @@ -1,4 +1,5 @@ # Bug component: 456592 -cbrubaker@google.com -vishwath@google.com +zachoverflow@google.com +alisher@google.com +jackcwyu@google.com diff --git a/core/java/android/se/omapi/OWNERS b/core/java/android/se/omapi/OWNERS index f1539dc55d59..5682fd3281f4 100644 --- a/core/java/android/se/omapi/OWNERS +++ b/core/java/android/se/omapi/OWNERS @@ -1,4 +1,5 @@ # Bug component: 456592 -cbrubaker@google.com -vishwath@google.com +zachoverflow@google.com +alisher@google.com +jackcwyu@google.com diff --git a/core/java/android/service/textservice/OWNERS b/core/java/android/service/textservice/OWNERS index 10b8b7637431..0471e29a25cd 100644 --- a/core/java/android/service/textservice/OWNERS +++ b/core/java/android/service/textservice/OWNERS @@ -1,3 +1,3 @@ -# Bug component: 34867 +# Bug component: 816455 -include ../../inputmethodservice/OWNERS
\ No newline at end of file +include /services/core/java/com/android/server/textservices/OWNERS diff --git a/core/java/android/text/format/Formatter.java b/core/java/android/text/format/Formatter.java index 17d3ae4a7ff0..471f2c2aecae 100644 --- a/core/java/android/text/format/Formatter.java +++ b/core/java/android/text/format/Formatter.java @@ -24,11 +24,12 @@ import android.content.res.Resources; import android.icu.text.MeasureFormat; import android.icu.util.Measure; import android.icu.util.MeasureUnit; -import android.net.NetworkUtils; import android.text.BidiFormatter; import android.text.TextUtils; import android.view.View; +import com.android.net.module.util.Inet4AddressUtils; + import java.util.Locale; /** @@ -207,7 +208,7 @@ public final class Formatter { */ @Deprecated public static String formatIpAddress(int ipv4Address) { - return NetworkUtils.intToInetAddress(ipv4Address).getHostAddress(); + return Inet4AddressUtils.intToInet4AddressHTL(ipv4Address).getHostAddress(); } private static final int SECONDS_PER_MINUTE = 60; diff --git a/core/java/android/view/accessibility/OWNERS b/core/java/android/view/accessibility/OWNERS index 93b5a2e8bc28..b1d3967a8b04 100644 --- a/core/java/android/view/accessibility/OWNERS +++ b/core/java/android/view/accessibility/OWNERS @@ -9,3 +9,4 @@ sumir@google.com ogunwale@google.com jjaggi@google.com pweaver@google.com +ryanlwlin@google.com diff --git a/core/java/android/view/textservice/OWNERS b/core/java/android/view/textservice/OWNERS index 582be8dc4594..0471e29a25cd 100644 --- a/core/java/android/view/textservice/OWNERS +++ b/core/java/android/view/textservice/OWNERS @@ -1,3 +1,3 @@ -# Bug component: 34867 +# Bug component: 816455 -include ../inputmethod/OWNERS +include /services/core/java/com/android/server/textservices/OWNERS diff --git a/core/java/android/widget/AbsSeekBar.java b/core/java/android/widget/AbsSeekBar.java index b9ff26b7d9ff..6281ee9d05d1 100644 --- a/core/java/android/widget/AbsSeekBar.java +++ b/core/java/android/widget/AbsSeekBar.java @@ -39,6 +39,7 @@ import android.view.accessibility.AccessibilityNodeInfo; import android.view.inspector.InspectableProperty; import com.android.internal.R; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.Preconditions; import java.util.ArrayList; @@ -776,17 +777,23 @@ public abstract class AbsSeekBar extends ProgressBar { /** * Grows {@code r} from its center such that each dimension is at least {@code minimumSize}. + * + * The result will still have the same {@link Rect#centerX()} and {@link Rect#centerY()} as the + * input. + * + * @hide */ - private void growRectTo(Rect r, int minimumSize) { - int dy = (minimumSize - r.height()) / 2; + @VisibleForTesting + public void growRectTo(Rect r, int minimumSize) { + int dy = minimumSize - r.height(); if (dy > 0) { - r.top -= dy; - r.bottom += dy; + r.top -= (dy + 1) / 2; + r.bottom += dy / 2; } - int dx = (minimumSize - r.width()) / 2; + int dx = minimumSize - r.width(); if (dx > 0) { - r.left -= dx; - r.right += dx; + r.left -= (dx + 1) / 2; + r.right += dx / 2; } } diff --git a/core/java/com/android/internal/compat/IPlatformCompat.aidl b/core/java/com/android/internal/compat/IPlatformCompat.aidl index cc266d60465e..a5eb5f607c12 100644 --- a/core/java/com/android/internal/compat/IPlatformCompat.aidl +++ b/core/java/com/android/internal/compat/IPlatformCompat.aidl @@ -22,17 +22,16 @@ import java.util.Map; parcelable CompatibilityChangeConfig; parcelable CompatibilityChangeInfo; - /** * Platform private API for talking with the PlatformCompat service. * - * <p> Should be used for gating and logging from non-app processes. - * For app processes please use android.compat.Compatibility API. + * <p>Should be used for gating and logging from non-app processes. + * + * <p>Note: for app processes please use {@code android.compat.Compatibility} API. * * {@hide} */ -interface IPlatformCompat -{ +interface IPlatformCompat { /** * Reports that a compatibility change is affecting an app process now. @@ -40,8 +39,9 @@ interface IPlatformCompat * <p>Note: for changes that are gated using {@link #isChangeEnabled(long, ApplicationInfo)}, * you do not need to call this API directly. The change will be reported for you. * - * @param changeId The ID of the compatibility change taking effect. - * @param appInfo Representing the affected app. + * @param changeId the ID of the compatibility change taking effect + * @param appInfo representing the affected app + * @throws SecurityException if logging is not allowed */ void reportChange(long changeId, in ApplicationInfo appInfo); @@ -51,11 +51,12 @@ interface IPlatformCompat * <p>Note: for changes that are gated using {@link #isChangeEnabled(long, String)}, * you do not need to call this API directly. The change will be reported for you. * - * @param changeId The ID of the compatibility change taking effect. - * @param userId The ID of the user that the operation is done for. - * @param packageName The package name of the app in question. + * @param changeId the ID of the compatibility change taking effect + * @param userId the ID of the user that the operation is done for + * @param packageName the package name of the app in question + * @throws SecurityException if logging is not allowed */ - void reportChangeByPackageName(long changeId, in String packageName, int userId); + void reportChangeByPackageName(long changeId, in String packageName, int userId); /** * Reports that a compatibility change is affecting an app process now. @@ -63,13 +64,14 @@ interface IPlatformCompat * <p>Note: for changes that are gated using {@link #isChangeEnabled(long, int)}, * you do not need to call this API directly. The change will be reported for you. * - * @param changeId The ID of the compatibility change taking effect. - * @param uid The UID of the app in question. + * @param changeId the ID of the compatibility change taking effect + * @param uid the UID of the app in question + * @throws SecurityException if logging is not allowed */ void reportChangeByUid(long changeId, int uid); /** - * Query if a given compatibility change is enabled for an app process. This method should + * Queries if a given compatibility change is enabled for an app process. This method should * be called when implementing functionality on behalf of the affected app. * * <p>If this method returns {@code true}, the calling code should implement the compatibility @@ -79,14 +81,15 @@ interface IPlatformCompat * <p>It will also report the change as {@link #reportChange(long, ApplicationInfo)} would, so * there is no need to call that method directly. * - * @param changeId The ID of the compatibility change in question. - * @param appInfo Representing the app in question. - * @return {@code true} if the change is enabled for the current app. + * @param changeId the ID of the compatibility change in question + * @param appInfo representing the app in question + * @return {@code true} if the change is enabled for the current app + * @throws SecurityException if logging or reading compat confis is not allowed */ boolean isChangeEnabled(long changeId, in ApplicationInfo appInfo); /** - * Query if a given compatibility change is enabled for an app process. This method should + * Queries if a given compatibility change is enabled for an app process. This method should * be called when implementing functionality on behalf of the affected app. * * <p>Same as {@link #isChangeEnabled(long, ApplicationInfo)}, except it receives a package name @@ -102,15 +105,16 @@ interface IPlatformCompat * <p>It will also report the change as {@link #reportChange(long, String)} would, so there is * no need to call that method directly. * - * @param changeId The ID of the compatibility change in question. - * @param packageName The package name of the app in question. - * @param userId The ID of the user that the operation is done for. - * @return {@code true} if the change is enabled for the current app. + * @param changeId the ID of the compatibility change in question + * @param packageName the package name of the app in question + * @param userId the ID of the user that the operation is done for + * @return {@code true} if the change is enabled for the current app + * @throws SecurityException if logging or reading compat confis is not allowed */ boolean isChangeEnabledByPackageName(long changeId, in String packageName, int userId); /** - * Query if a given compatibility change is enabled for an app process. This method should + * Queries if a given compatibility change is enabled for an app process. This method should * be called when implementing functionality on behalf of the affected app. * * <p>Same as {@link #isChangeEnabled(long, ApplicationInfo)}, except it receives a uid @@ -127,110 +131,132 @@ interface IPlatformCompat * <p>It will also report the change as {@link #reportChange(long, int)} would, so there is * no need to call that method directly. * - * @param changeId The ID of the compatibility change in question. - * @param uid The UID of the app in question. - * @return {@code true} if the change is enabled for the current app. + * @param changeId the ID of the compatibility change in question + * @param uid the UID of the app in question + * @return {@code true} if the change is enabled for the current app + * @throws SecurityException if logging or reading compat confis is not allowed */ boolean isChangeEnabledByUid(long changeId, int uid); /** - * Add overrides to compatibility changes. Kills the app to allow the changes to take effect. + * Adds overrides to compatibility changes. * - * @param overrides Parcelable containing the compat change overrides to be applied. - * @param packageName The package name of the app whose changes will be overridden. + * <p>Kills the app to allow the changes to take effect. * + * @param overrides parcelable containing the compat change overrides to be applied + * @param packageName the package name of the app whose changes will be overridden + * @throws SecurityException if overriding changes is not permitted */ void setOverrides(in CompatibilityChangeConfig overrides, in String packageName); /** - * Add overrides to compatibility changes. Doesn't kill the app, to be only used in tests. + * Adds overrides to compatibility changes. * - * @param overrides Parcelable containing the compat change overrides to be applied. - * @param packageName The package name of the app whose changes will be overridden. + * <p>Does not kill the app, to be only used in tests. * + * @param overrides parcelable containing the compat change overrides to be applied + * @param packageName the package name of the app whose changes will be overridden + * @throws SecurityException if overriding changes is not permitted. */ void setOverridesForTest(in CompatibilityChangeConfig overrides, in String packageName); /** - * Removes an override previously added via {@link #setOverrides(CompatibilityChangeConfig, - * String)}. This restores the default behaviour for the given change and app, once any app - * processes have been restarted. - * Kills the app to allow the changes to take effect. + * Restores the default behaviour for the given change and app. * - * @param changeId The ID of the change that was overridden. - * @param packageName The app package name that was overridden. - * @return {@code true} if an override existed; + * <p>Kills the app to allow the changes to take effect. + * + * @param changeId the ID of the change that was overridden + * @param packageName the app package name that was overridden + * @return {@code true} if an override existed + * @throws SecurityException if overriding changes is not permitted */ boolean clearOverride(long changeId, String packageName); /** - * Enable all compatibility changes which have enabledSinceTargetSdk == - * {@param targetSdkVersion} for an app, subject to the policy. Kills the app to allow the - * changes to take effect. + * Restores the default behaviour for the given change and app. * - * @param packageName The package name of the app whose compatibility changes will be enabled. - * @param targetSdkVersion The targetSdkVersion for filtering the changes to be enabled. + * <p>Does not kill the app; to be only used in tests. + * + * @param changeId the ID of the change that was overridden + * @param packageName the app package name that was overridden + * @throws SecurityException if overriding changes is not permitted + */ + void clearOverrideForTest(long changeId, String packageName); + + /** + * Enables all compatibility changes that have enabledSinceTargetSdk == + * {@param targetSdkVersion} for an app, subject to the policy. + * + * <p>Kills the app to allow the changes to take effect. * + * @param packageName The package name of the app whose compatibility changes will be + * enabled. + * @param targetSdkVersion The targetSdkVersion for filtering the changes to be enabled. * @return The number of changes that were enabled. + * @throws SecurityException if overriding changes is not permitted. */ int enableTargetSdkChanges(in String packageName, int targetSdkVersion); /** - * Disable all compatibility changes which have enabledAfterTargetSdk == - * {@param targetSdkVersion} for an app, subject to the policy. Kills the app to allow the - * changes to take effect. + * Disables all compatibility changes that have enabledAfterTargetSdk == + * {@param targetSdkVersion} for an app, subject to the policy. * - * @param packageName The package name of the app whose compatibility changes will be disabled. - * @param targetSdkVersion The targetSdkVersion for filtering the changes to be disabled. + * <p>Kills the app to allow the changes to take effect. * - * @return The number of changes that were disabled. + * @param packageName the package name of the app whose compatibility changes will be + * disabled + * @param targetSdkVersion the targetSdkVersion for filtering the changes to be disabled + * @return the number of changes that were disabled + * @throws SecurityException if overriding changes is not permitted. */ int disableTargetSdkChanges(in String packageName, int targetSdkVersion); /** - * Revert overrides to compatibility changes. Kills the app to allow the changes to take effect. + * Restores the default behaviour for the given app. * - * @param packageName The package name of the app whose overrides will be cleared. + * <p>Kills the app to allow the changes to take effect. * + * @param packageName the package name of the app whose overrides will be cleared + * @throws SecurityException if overriding changes is not permitted */ void clearOverrides(in String packageName); /** - * Revert overrides to compatibility changes. Doesn't kill the app, to be only used in tests. + * Restores the default behaviour for the given app. * - * @param packageName The package name of the app whose overrides will be cleared. + * <p>Does not kill the app; to be only used in tests. * + * @param packageName the package name of the app whose overrides will be cleared + * @throws SecurityException if overriding changes is not permitted */ void clearOverridesForTest(in String packageName); - /** * Get configs for an application. * - * @param appInfo The application whose config will be returned. - * - * @return A {@link CompatibilityChangeConfig}, representing whether a change is enabled for - * the given app or not. + * @param appInfo the application whose config will be returned + * @return a {@link CompatibilityChangeConfig}, representing whether a change is enabled for + * the given app or not */ CompatibilityChangeConfig getAppConfig(in ApplicationInfo appInfo); /** * List all compatibility changes. * - * @return An array of {@link CompatChangeInfo} known to the service. + * @return an array of {@link CompatibilityChangeInfo} known to the service */ CompatibilityChangeInfo[] listAllChanges(); /** - * List the compatibility changes that should be present in the UI. - * Filters out certain changes like e.g. logging only. - * - * @return An array of {@link CompatChangeInfo}. - */ + * List the compatibility changes that should be present in the UI. + * Filters out certain changes like e.g. logging only. + * + * @return an array of {@link CompatibilityChangeInfo} + */ CompatibilityChangeInfo[] listUIChanges(); /** - * Get an instance that can determine whether a changeid can be overridden for a package name. + * Gets an instance that can determine whether a changeid can be overridden for a package name. */ IOverrideValidator getOverrideValidator(); } diff --git a/core/java/com/android/internal/os/WrapperInit.java b/core/java/com/android/internal/os/WrapperInit.java index 790d7f7ab694..6860759eea8a 100644 --- a/core/java/com/android/internal/os/WrapperInit.java +++ b/core/java/com/android/internal/os/WrapperInit.java @@ -69,15 +69,16 @@ public class WrapperInit { // Tell the Zygote what our actual PID is (since it only knows about the // wrapper that it directly forked). if (fdNum != 0) { + FileDescriptor fd = new FileDescriptor(); try { - FileDescriptor fd = new FileDescriptor(); fd.setInt$(fdNum); DataOutputStream os = new DataOutputStream(new FileOutputStream(fd)); os.writeInt(Process.myPid()); os.close(); - IoUtils.closeQuietly(fd); } catch (IOException ex) { Slog.d(TAG, "Could not write pid of wrapped process to Zygote pipe.", ex); + } finally { + IoUtils.closeQuietly(fd); } } diff --git a/core/java/com/android/internal/textservice/OWNERS b/core/java/com/android/internal/textservice/OWNERS new file mode 100644 index 000000000000..0471e29a25cd --- /dev/null +++ b/core/java/com/android/internal/textservice/OWNERS @@ -0,0 +1,3 @@ +# Bug component: 816455 + +include /services/core/java/com/android/server/textservices/OWNERS diff --git a/core/jni/android_os_HwBlob.cpp b/core/jni/android_os_HwBlob.cpp index 0fb29111d043..a9db91be1d5b 100644 --- a/core/jni/android_os_HwBlob.cpp +++ b/core/jni/android_os_HwBlob.cpp @@ -257,7 +257,17 @@ jobject JHwBlob::NewObject(JNIEnv *env, size_t size) { // XXX Again cannot refer to gFields.constructID because InitClass may // not have been called yet. - return env->NewObject(clazz.get(), constructID, size); + // Cases: + // - this originates from another process (something so large should not fit + // in the binder buffer, and it should be rejected by the binder driver) + // - if this is used in process, this code makes too many heap copies (in + // order to retrofit HIDL's scatter-gather format to java types) to + // justify passing such a large amount of data over this path. So the + // alternative (updating the constructor and other code to accept other + // types, should also probably not be taken in this case). + CHECK_LE(size, std::numeric_limits<jint>::max()); + + return env->NewObject(clazz.get(), constructID, static_cast<jint>(size)); } } // namespace android diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp index dc98aafb129e..b2e562c9650e 100644 --- a/core/jni/com_android_internal_os_Zygote.cpp +++ b/core/jni/com_android_internal_os_Zygote.cpp @@ -1559,7 +1559,6 @@ static void isolateAppData(JNIEnv* env, jobjectArray pkg_data_info_list, jobjectArray whitelisted_data_info_list, uid_t uid, const char* process_name, jstring managed_nice_name, fail_fn_t fail_fn) { - ensureInAppMountNamespace(fail_fn); std::vector<std::string> merged_data_info_list; insertPackagesToMergedList(env, merged_data_info_list, pkg_data_info_list, process_name, managed_nice_name, fail_fn); @@ -1706,10 +1705,11 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids, MountEmulatedStorage(uid, mount_external, need_pre_initialize_native_bridge, fail_fn); - // System services, isolated process, webview/app zygote, old target sdk app, should - // give a null in same_uid_pkgs and private_volumes so they don't need app data isolation. - // Isolated process / webview / app zygote should be gated by SELinux and file permission - // so they can't even traverse CE / DE directories. + // Make sure app is running in its own mount namespace before isolating its data directories. + ensureInAppMountNamespace(fail_fn); + + // Sandbox data and jit profile directories by overlaying a tmpfs on those dirs and bind + // mount all related packages separately. if (mount_data_dirs) { isolateAppData(env, pkg_data_info_list, whitelisted_data_info_list, uid, process_name, managed_nice_name, fail_fn); diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 60b3839a57ef..c6a1bdd54080 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -313,8 +313,10 @@ <protected-broadcast android:name="android.se.omapi.action.SECURE_ELEMENT_STATE_CHANGED" /> <protected-broadcast android:name="android.nfc.action.ADAPTER_STATE_CHANGED" /> + <protected-broadcast android:name="android.nfc.action.ALWAYS_ON_STATE_CHANGED" /> <protected-broadcast android:name="android.nfc.action.PREFERRED_PAYMENT_CHANGED" /> <protected-broadcast android:name="android.nfc.action.TRANSACTION_DETECTED" /> + <protected-broadcast android:name="android.nfc.action.REQUIRE_UNLOCK_FOR_NFC" /> <protected-broadcast android:name="com.android.nfc.action.LLCP_UP" /> <protected-broadcast android:name="com.android.nfc.action.LLCP_DOWN" /> <protected-broadcast android:name="com.android.nfc.cardemulation.action.CLOSE_TAP_DIALOG" /> @@ -1625,7 +1627,7 @@ <permission android:name="android.permission.MANAGE_IPSEC_TUNNELS" android:protectionLevel="signature|appop" /> - <!-- @hide Allows apps to create and manage Test Networks. + <!-- @SystemApi @hide Allows apps to create and manage Test Networks. <p>Granted only to shell. CTS tests will use UiAutomation.AdoptShellPermissionIdentity() to gain access. --> diff --git a/core/tests/bugreports/src/com/android/os/bugreports/tests/BugreportManagerTest.java b/core/tests/bugreports/src/com/android/os/bugreports/tests/BugreportManagerTest.java index f9e3bc60561c..222471a830b1 100644 --- a/core/tests/bugreports/src/com/android/os/bugreports/tests/BugreportManagerTest.java +++ b/core/tests/bugreports/src/com/android/os/bugreports/tests/BugreportManagerTest.java @@ -23,7 +23,10 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import android.Manifest; +import android.content.BroadcastReceiver; import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; import android.os.BugreportManager; import android.os.BugreportManager.BugreportCallback; import android.os.BugreportParams; @@ -31,7 +34,9 @@ import android.os.FileUtils; import android.os.Handler; import android.os.HandlerThread; import android.os.ParcelFileDescriptor; +import android.os.Process; import android.os.StrictMode; +import android.text.TextUtils; import android.util.Log; import androidx.annotation.NonNull; @@ -53,10 +58,11 @@ import org.junit.runner.RunWith; import org.junit.runners.JUnit4; import java.io.File; +import java.io.IOException; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; - /** * Tests for BugreportManager API. */ @@ -67,8 +73,16 @@ public class BugreportManagerTest { private static final String TAG = "BugreportManagerTest"; private static final long BUGREPORT_TIMEOUT_MS = TimeUnit.MINUTES.toMillis(10); + private static final long DUMPSTATE_STARTUP_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(10); private static final long UIAUTOMATOR_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(10); + // Sent by Shell when its bugreport finishes (contains final bugreport/screenshot file name + // associated with the bugreport). + private static final String INTENT_BUGREPORT_FINISHED = + "com.android.internal.intent.action.BUGREPORT_FINISHED"; + private static final String EXTRA_BUGREPORT = "android.intent.extra.BUGREPORT"; + private static final String EXTRA_SCREENSHOT = "android.intent.extra.SCREENSHOT"; + private Handler mHandler; private Executor mExecutor; private BugreportManager mBrm; @@ -212,6 +226,48 @@ public class BugreportManagerTest { } @Test + public void cancelBugreport_noReportStarted() throws Exception { + // Without the native DumpstateService running, we don't get a SecurityException. + mBrm.cancelBugreport(); + } + + @LargeTest + @Test + public void cancelBugreport_fromDifferentUid() throws Exception { + assertThat(Process.myUid()).isNotEqualTo(Process.SHELL_UID); + + // Start a bugreport through ActivityManager's shell command - this starts a BR from the + // shell UID rather than our own. + BugreportBroadcastReceiver br = new BugreportBroadcastReceiver(); + InstrumentationRegistry.getContext() + .registerReceiver(br, new IntentFilter(INTENT_BUGREPORT_FINISHED)); + UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) + .executeShellCommand("am bug-report"); + + // The command triggers the report through a broadcast, so wait until dumpstate actually + // starts up, which may take a bit. + waitTillDumpstateRunningOrTimeout(); + + try { + mBrm.cancelBugreport(); + fail("Expected cancelBugreport to throw SecurityException when report started by " + + "different UID"); + } catch (SecurityException expected) { + } finally { + // Do this in the finally block so that even if this test case fails, we don't break + // other test cases unexpectedly due to the still-running shell report. + try { + // The shell's BR is still running and should complete successfully. + br.waitForBugreportFinished(); + } finally { + // The latch may fail for a number of reasons but we still need to unregister the + // BroadcastReceiver. + InstrumentationRegistry.getContext().unregisterReceiver(br); + } + } + } + + @Test public void insufficientPermissions_throwsException() throws Exception { dropPermissions(); @@ -346,6 +402,28 @@ public class BugreportManagerTest { .adoptShellPermissionIdentity(Manifest.permission.DUMP); } + private static boolean isDumpstateRunning() { + String[] output; + try { + output = + UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) + .executeShellCommand("ps -A -o NAME | grep dumpstate") + .trim() + .split("\n"); + } catch (IOException e) { + Log.w(TAG, "Failed to check if dumpstate is running", e); + return false; + } + for (String line : output) { + // Check for an exact match since there may be other things that contain "dumpstate" as + // a substring (e.g. the dumpstate HAL). + if (TextUtils.equals("dumpstate", line)) { + return true; + } + } + return false; + } + private static void assertFdIsClosed(ParcelFileDescriptor pfd) { try { int fd = pfd.getFd(); @@ -364,18 +442,25 @@ public class BugreportManagerTest { return System.currentTimeMillis(); } - private static boolean shouldTimeout(long startTimeMs) { - return now() - startTimeMs >= BUGREPORT_TIMEOUT_MS; + private static void waitTillDumpstateRunningOrTimeout() throws Exception { + long startTimeMs = now(); + while (!isDumpstateRunning()) { + Thread.sleep(500 /* .5s */); + if (now() - startTimeMs >= DUMPSTATE_STARTUP_TIMEOUT_MS) { + break; + } + Log.d(TAG, "Waited " + (now() - startTimeMs) + "ms for dumpstate to start"); + } } private static void waitTillDoneOrTimeout(BugreportCallbackImpl callback) throws Exception { long startTimeMs = now(); while (!callback.isDone()) { Thread.sleep(1000 /* 1s */); - if (shouldTimeout(startTimeMs)) { + if (now() - startTimeMs >= BUGREPORT_TIMEOUT_MS) { break; } - Log.d(TAG, "Waited " + (now() - startTimeMs) + "ms"); + Log.d(TAG, "Waited " + (now() - startTimeMs) + "ms for bugreport to finish"); } } @@ -450,6 +535,36 @@ public class BugreportManagerTest { assertTrue(device.wait(Until.gone(consentTitleObj), UIAUTOMATOR_TIMEOUT_MS)); } + private class BugreportBroadcastReceiver extends BroadcastReceiver { + Intent mBugreportFinishedIntent = null; + final CountDownLatch mLatch; + + BugreportBroadcastReceiver() { + mLatch = new CountDownLatch(1); + } + + @Override + public void onReceive(Context context, Intent intent) { + setBugreportFinishedIntent(intent); + mLatch.countDown(); + } + + private void setBugreportFinishedIntent(Intent intent) { + mBugreportFinishedIntent = intent; + } + + public Intent getBugreportFinishedIntent() { + return mBugreportFinishedIntent; + } + + public void waitForBugreportFinished() throws Exception { + if (!mLatch.await(BUGREPORT_TIMEOUT_MS, TimeUnit.MILLISECONDS)) { + throw new Exception("Failed to receive BUGREPORT_FINISHED in " + + BUGREPORT_TIMEOUT_MS + " ms."); + } + } + } + /** * A rule to change strict mode vm policy temporarily till test method finished. * diff --git a/core/tests/coretests/src/android/content/OWNERS b/core/tests/coretests/src/android/content/OWNERS index 696aa11618ff..912db1e835dc 100644 --- a/core/tests/coretests/src/android/content/OWNERS +++ b/core/tests/coretests/src/android/content/OWNERS @@ -1,4 +1,3 @@ per-file ContextTest.java = file:/services/core/java/com/android/server/wm/OWNERS per-file *Shortcut* = file:/core/java/android/content/pm/SHORTCUT_OWNERS -per-file AppSearchPersonTest.java = file:/core/java/android/content/pm/SHORTCUT_OWNERS per-file *Launcher* = file:/core/java/android/content/pm/LAUNCHER_OWNERS diff --git a/core/tests/coretests/src/android/content/pm/OWNERS b/core/tests/coretests/src/android/content/pm/OWNERS new file mode 100644 index 000000000000..711f5f012b8b --- /dev/null +++ b/core/tests/coretests/src/android/content/pm/OWNERS @@ -0,0 +1,2 @@ +per-file AppSearchPersonTest.java = file:/core/java/android/content/pm/SHORTCUT_OWNERS + diff --git a/core/tests/coretests/src/android/view/textservice/OWNERS b/core/tests/coretests/src/android/view/textservice/OWNERS new file mode 100644 index 000000000000..0471e29a25cd --- /dev/null +++ b/core/tests/coretests/src/android/view/textservice/OWNERS @@ -0,0 +1,3 @@ +# Bug component: 816455 + +include /services/core/java/com/android/server/textservices/OWNERS diff --git a/core/tests/coretests/src/android/widget/AbsSeekBarTest.java b/core/tests/coretests/src/android/widget/AbsSeekBarTest.java index 5371a0f8d9d7..ccd873dc390e 100644 --- a/core/tests/coretests/src/android/widget/AbsSeekBarTest.java +++ b/core/tests/coretests/src/android/widget/AbsSeekBarTest.java @@ -30,7 +30,6 @@ import android.graphics.Rect; import android.graphics.drawable.ShapeDrawable; import android.graphics.drawable.shapes.RectShape; import android.platform.test.annotations.Presubmit; -import android.view.View; import androidx.test.filters.SmallTest; import androidx.test.platform.app.InstrumentationRegistry; @@ -48,6 +47,7 @@ import java.util.List; @Presubmit public class AbsSeekBarTest { + public static final int PADDING = 10; private Context mContext; private AbsSeekBar mBar; @@ -59,34 +59,42 @@ public class AbsSeekBarTest { @Test public void testExclusionForThumb_limitedTo48dp() { - mBar.setPadding(10, 10, 10, 10); + mBar.setPadding(PADDING, PADDING, PADDING, PADDING); mBar.setThumb(newThumb(dpToPxSize(20))); mBar.setMin(0); mBar.setMax(100); mBar.setProgress(50); + + final int thumbOffset = mBar.getThumbOffset(); + measureAndLayout(dpToPxSize(200), dpToPxSize(100)); List<Rect> exclusions = mBar.getSystemGestureExclusionRects(); assertEquals("exclusions should be size 1, but was " + exclusions, 1, exclusions.size()); assertEquals("exclusion should be centered on thumb", - center(mBar), center(exclusions.get(0))); + center(offset(mBar.getThumb().getBounds(), PADDING - thumbOffset, PADDING)), + center(exclusions.get(0))); assertEquals("exclusion should be 48dp high", dpToPxSize(48), exclusions.get(0).height()); assertEquals("exclusion should be 48dp wide", dpToPxSize(48), exclusions.get(0).width()); } @Test public void testExclusionForThumb_limitedToHeight() { - mBar.setPadding(10, 10, 10, 10); + mBar.setPadding(PADDING, PADDING, PADDING, PADDING); mBar.setThumb(newThumb(dpToPxSize(20))); mBar.setMin(0); mBar.setMax(100); mBar.setProgress(50); + + final int thumbOffset = mBar.getThumbOffset(); + measureAndLayout(dpToPxSize(200), dpToPxSize(32)); List<Rect> exclusions = mBar.getSystemGestureExclusionRects(); assertEquals("exclusions should be size 1, but was " + exclusions, 1, exclusions.size()); assertEquals("exclusion should be centered on thumb", - center(mBar), center(exclusions.get(0))); + center(offset(mBar.getThumb().getBounds(), PADDING - thumbOffset, PADDING)), + center(exclusions.get(0))); assertEquals("exclusion should be 32dp high", dpToPxSize(32), exclusions.get(0).height()); assertEquals("exclusion should be 32dp wide", dpToPxSize(32), exclusions.get(0).width()); } @@ -95,7 +103,7 @@ public class AbsSeekBarTest { public void testExclusionForThumb_passesThroughUserExclusions() { mBar.setSystemGestureExclusionRects(Arrays.asList(new Rect(1, 2, 3, 4))); - mBar.setPadding(10, 10, 10, 10); + mBar.setPadding(PADDING, PADDING, PADDING, PADDING); mBar.setThumb(newThumb(dpToPxSize(20))); mBar.setMin(0); mBar.setMax(100); @@ -110,12 +118,37 @@ public class AbsSeekBarTest { assertThat(mBar.getSystemGestureExclusionRects(), hasSize(2)); } + @Test + public void testGrowRectTo_evenInitialDifference() { + doGrowRectTest(new Rect(0, 0, 0, 0), 10, new Rect(-5, -5, 5, 5)); + } + + @Test + public void testGrowRectTo_unevenInitialDifference() { + doGrowRectTest(new Rect(0, 0, 1, 1), 10, new Rect(-5, -5, 5, 5)); + } + + @Test + public void testGrowRectTo_unevenInitialDifference_unevenSize() { + doGrowRectTest(new Rect(0, 0, 0, 0), 9, new Rect(-5, -5, 4, 4)); + } + + public void doGrowRectTest(Rect in, int minimumSize, Rect expected) { + Rect result = new Rect(in); + mBar.growRectTo(result, minimumSize); + + assertEquals("grown rect", expected, result); + assertEquals("grown rect center point", center(expected), center(result)); + } + private Point center(Rect rect) { return new Point(rect.centerX(), rect.centerY()); } - private Point center(View view) { - return center(new Rect(view.getLeft(), view.getTop(), view.getRight(), view.getBottom())); + private Rect offset(Rect rect, int dx, int dy) { + Rect result = new Rect(rect); + result.offset(dx, dy); + return result; } private ShapeDrawable newThumb(int size) { diff --git a/core/tests/overlaytests/device/Android.bp b/core/tests/overlaytests/device/Android.bp index 12a2b0815050..f86ac9ce37e1 100644 --- a/core/tests/overlaytests/device/Android.bp +++ b/core/tests/overlaytests/device/Android.bp @@ -16,7 +16,11 @@ android_test { name: "OverlayDeviceTests", srcs: ["src/**/*.java"], platform_apis: true, - static_libs: ["androidx.test.rules"], + certificate: "platform", + static_libs: [ + "androidx.test.rules", + "testng", + ], test_suites: ["device-tests"], data: [ ":OverlayDeviceTests_AppOverlayOne", diff --git a/core/tests/overlaytests/device/AndroidManifest.xml b/core/tests/overlaytests/device/AndroidManifest.xml index 4881636c7095..a69911f8d827 100644 --- a/core/tests/overlaytests/device/AndroidManifest.xml +++ b/core/tests/overlaytests/device/AndroidManifest.xml @@ -19,6 +19,8 @@ <uses-sdk android:minSdkVersion="21" /> + <uses-permission android:name="android.permission.CHANGE_OVERLAY_PACKAGES" /> + <application> <uses-library android:name="android.test.runner"/> </application> diff --git a/core/tests/overlaytests/device/AndroidTest.xml b/core/tests/overlaytests/device/AndroidTest.xml index 6507839a4288..ebbdda559ed2 100644 --- a/core/tests/overlaytests/device/AndroidTest.xml +++ b/core/tests/overlaytests/device/AndroidTest.xml @@ -19,9 +19,20 @@ <option name="test-suite-tag" value="apct" /> <option name="test-suite-tag" value="apct-instrumentation" /> + <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher"> + <option name="cleanup" value="true" /> + <option name="remount-system" value="true" /> + <option name="push" value="OverlayDeviceTests.apk->/system/app/OverlayDeviceTests.apk" /> + </target_preparer> + + <!-- Reboot to have the test APK scanned by PM and reboot after to remove the test APK. --> + <target_preparer class="com.android.tradefed.targetprep.RebootTargetPreparer"> + <option name="pre-reboot" value="true" /> + <option name="post-reboot" value="true" /> + </target_preparer> + <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup"> <option name="cleanup-apks" value="true" /> - <option name="test-file-name" value="OverlayDeviceTests.apk" /> <option name="test-file-name" value="OverlayDeviceTests_AppOverlayOne.apk" /> <option name="test-file-name" value="OverlayDeviceTests_AppOverlayTwo.apk" /> <option name="test-file-name" value="OverlayDeviceTests_FrameworkOverlay.apk" /> diff --git a/core/tests/overlaytests/device/src/com/android/overlaytest/LocalOverlayManager.java b/core/tests/overlaytests/device/src/com/android/overlaytest/LocalOverlayManager.java index 390bb766ab81..76c01a7e1125 100644 --- a/core/tests/overlaytests/device/src/com/android/overlaytest/LocalOverlayManager.java +++ b/core/tests/overlaytests/device/src/com/android/overlaytest/LocalOverlayManager.java @@ -18,60 +18,76 @@ package com.android.overlaytest; import static java.util.concurrent.TimeUnit.SECONDS; -import android.app.UiAutomation; -import android.content.res.Resources; -import android.os.ParcelFileDescriptor; +import android.annotation.NonNull; +import android.content.Context; +import android.content.om.OverlayManager; +import android.content.om.OverlayManagerTransaction; +import android.os.UserHandle; import androidx.test.InstrumentationRegistry; -import java.io.BufferedReader; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.nio.charset.StandardCharsets; -import java.util.Arrays; import java.util.concurrent.Executor; import java.util.concurrent.FutureTask; class LocalOverlayManager { private static final long TIMEOUT = 30; - public static void setEnabledAndWait(Executor executor, final String packageName, - boolean enable) throws Exception { - final String pattern = (enable ? "[x]" : "[ ]") + " " + packageName; - if (executeShellCommand("cmd overlay list").contains(pattern)) { - // nothing to do, overlay already in the requested state - return; + public static void toggleOverlaysAndWait(@NonNull final String[] overlaysToEnable, + @NonNull final String[] overlaysToDisable) throws Exception { + final int userId = UserHandle.myUserId(); + OverlayManagerTransaction.Builder builder = new OverlayManagerTransaction.Builder(); + for (String pkg : overlaysToEnable) { + builder.setEnabled(pkg, true, userId); } + for (String pkg : overlaysToDisable) { + builder.setEnabled(pkg, false, userId); + } + OverlayManagerTransaction transaction = builder.build(); - final Resources res = InstrumentationRegistry.getContext().getResources(); - final String[] oldApkPaths = res.getAssets().getApkPaths(); + final Context ctx = InstrumentationRegistry.getTargetContext(); FutureTask<Boolean> task = new FutureTask<>(() -> { while (true) { - if (!Arrays.equals(oldApkPaths, res.getAssets().getApkPaths())) { + final String[] paths = ctx.getResources().getAssets().getApkPaths(); + if (arrayTailContains(paths, overlaysToEnable) + && arrayDoesNotContain(paths, overlaysToDisable)) { return true; } Thread.sleep(10); } }); + + OverlayManager om = ctx.getSystemService(OverlayManager.class); + om.commit(transaction); + + Executor executor = (cmd) -> new Thread(cmd).start(); executor.execute(task); - executeShellCommand("cmd overlay " + (enable ? "enable " : "disable ") + packageName); task.get(TIMEOUT, SECONDS); } - private static String executeShellCommand(final String command) - throws Exception { - final UiAutomation uiAutomation = - InstrumentationRegistry.getInstrumentation().getUiAutomation(); - final ParcelFileDescriptor pfd = uiAutomation.executeShellCommand(command); - try (InputStream in = new ParcelFileDescriptor.AutoCloseInputStream(pfd)) { - final BufferedReader reader = new BufferedReader( - new InputStreamReader(in, StandardCharsets.UTF_8)); - StringBuilder str = new StringBuilder(); - String line; - while ((line = reader.readLine()) != null) { - str.append(line); + private static boolean arrayTailContains(@NonNull final String[] array, + @NonNull final String[] substrings) { + if (array.length < substrings.length) { + return false; + } + for (int i = 0; i < substrings.length; i++) { + String a = array[array.length - substrings.length + i]; + String s = substrings[i]; + if (!a.contains(s)) { + return false; + } + } + return true; + } + + private static boolean arrayDoesNotContain(@NonNull final String[] array, + @NonNull final String[] substrings) { + for (String s : substrings) { + for (String a : array) { + if (a.contains(s)) { + return false; + } } - return str.toString(); } + return true; } } diff --git a/core/tests/overlaytests/device/src/com/android/overlaytest/TransactionTest.java b/core/tests/overlaytests/device/src/com/android/overlaytest/TransactionTest.java new file mode 100644 index 000000000000..0b4f5e227169 --- /dev/null +++ b/core/tests/overlaytests/device/src/com/android/overlaytest/TransactionTest.java @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.overlaytest; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.testng.Assert.assertThrows; + +import android.content.Context; +import android.content.om.OverlayInfo; +import android.content.om.OverlayManager; +import android.content.om.OverlayManagerTransaction; +import android.content.res.Resources; +import android.os.UserHandle; + +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.MediumTest; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +import java.util.List; + +@RunWith(JUnit4.class) +@MediumTest +public class TransactionTest { + static final String APP_OVERLAY_ONE_PKG = "com.android.overlaytest.app_overlay_one"; + static final String APP_OVERLAY_TWO_PKG = "com.android.overlaytest.app_overlay_two"; + + private Context mContext; + private Resources mResources; + private OverlayManager mOverlayManager; + private int mUserId; + private UserHandle mUserHandle; + + @Before + public void setUp() throws Exception { + mContext = InstrumentationRegistry.getContext(); + mResources = mContext.getResources(); + mOverlayManager = mContext.getSystemService(OverlayManager.class); + mUserId = UserHandle.myUserId(); + mUserHandle = UserHandle.of(mUserId); + + LocalOverlayManager.toggleOverlaysAndWait( + new String[]{}, + new String[]{APP_OVERLAY_ONE_PKG, APP_OVERLAY_TWO_PKG}); + } + + @Test + public void testValidTransaction() throws Exception { + assertOverlayIsEnabled(APP_OVERLAY_ONE_PKG, false, mUserId); + assertOverlayIsEnabled(APP_OVERLAY_TWO_PKG, false, mUserId); + + OverlayManagerTransaction t = new OverlayManagerTransaction.Builder() + .setEnabled(APP_OVERLAY_ONE_PKG, true) + .setEnabled(APP_OVERLAY_TWO_PKG, true) + .build(); + mOverlayManager.commit(t); + + assertOverlayIsEnabled(APP_OVERLAY_ONE_PKG, true, mUserId); + assertOverlayIsEnabled(APP_OVERLAY_TWO_PKG, true, mUserId); + List<OverlayInfo> ois = + mOverlayManager.getOverlayInfosForTarget("com.android.overlaytest", mUserHandle); + assertEquals(ois.size(), 2); + assertEquals(ois.get(0).packageName, APP_OVERLAY_ONE_PKG); + assertEquals(ois.get(1).packageName, APP_OVERLAY_TWO_PKG); + + OverlayManagerTransaction t2 = new OverlayManagerTransaction.Builder() + .setEnabled(APP_OVERLAY_TWO_PKG, true) + .setEnabled(APP_OVERLAY_ONE_PKG, true) + .build(); + mOverlayManager.commit(t2); + + assertOverlayIsEnabled(APP_OVERLAY_ONE_PKG, true, mUserId); + assertOverlayIsEnabled(APP_OVERLAY_TWO_PKG, true, mUserId); + List<OverlayInfo> ois2 = + mOverlayManager.getOverlayInfosForTarget("com.android.overlaytest", mUserHandle); + assertEquals(ois2.size(), 2); + assertEquals(ois2.get(0).packageName, APP_OVERLAY_TWO_PKG); + assertEquals(ois2.get(1).packageName, APP_OVERLAY_ONE_PKG); + + OverlayManagerTransaction t3 = new OverlayManagerTransaction.Builder() + .setEnabled(APP_OVERLAY_TWO_PKG, false) + .build(); + mOverlayManager.commit(t3); + + assertOverlayIsEnabled(APP_OVERLAY_ONE_PKG, true, mUserId); + assertOverlayIsEnabled(APP_OVERLAY_TWO_PKG, false, mUserId); + List<OverlayInfo> ois3 = + mOverlayManager.getOverlayInfosForTarget("com.android.overlaytest", mUserHandle); + assertEquals(ois3.size(), 2); + assertEquals(ois3.get(0).packageName, APP_OVERLAY_TWO_PKG); + assertEquals(ois3.get(1).packageName, APP_OVERLAY_ONE_PKG); + } + + @Test + public void testInvalidRequestHasNoEffect() { + assertOverlayIsEnabled(APP_OVERLAY_ONE_PKG, false, mUserId); + assertOverlayIsEnabled(APP_OVERLAY_TWO_PKG, false, mUserId); + + OverlayManagerTransaction t = new OverlayManagerTransaction.Builder() + .setEnabled(APP_OVERLAY_ONE_PKG, true) + .setEnabled("does-not-exist", true) + .setEnabled(APP_OVERLAY_TWO_PKG, true) + .build(); + assertThrows(SecurityException.class, () -> mOverlayManager.commit(t)); + + assertOverlayIsEnabled(APP_OVERLAY_ONE_PKG, false, mUserId); + assertOverlayIsEnabled(APP_OVERLAY_TWO_PKG, false, mUserId); + } + + private void assertOverlayIsEnabled(final String packageName, boolean enabled, int userId) { + final OverlayInfo oi = mOverlayManager.getOverlayInfo(packageName, UserHandle.of(userId)); + assertNotNull(oi); + assertEquals(oi.isEnabled(), enabled); + } +} diff --git a/core/tests/overlaytests/device/src/com/android/overlaytest/WithMultipleOverlaysTest.java b/core/tests/overlaytests/device/src/com/android/overlaytest/WithMultipleOverlaysTest.java index d28c47d9c922..420f755c5251 100644 --- a/core/tests/overlaytests/device/src/com/android/overlaytest/WithMultipleOverlaysTest.java +++ b/core/tests/overlaytests/device/src/com/android/overlaytest/WithMultipleOverlaysTest.java @@ -22,8 +22,6 @@ import org.junit.BeforeClass; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; -import java.util.concurrent.Executor; - @RunWith(JUnit4.class) @MediumTest public class WithMultipleOverlaysTest extends OverlayBaseTest { @@ -33,9 +31,8 @@ public class WithMultipleOverlaysTest extends OverlayBaseTest { @BeforeClass public static void enableOverlay() throws Exception { - Executor executor = (cmd) -> new Thread(cmd).start(); - LocalOverlayManager.setEnabledAndWait(executor, APP_OVERLAY_ONE_PKG, true); - LocalOverlayManager.setEnabledAndWait(executor, APP_OVERLAY_TWO_PKG, true); - LocalOverlayManager.setEnabledAndWait(executor, FRAMEWORK_OVERLAY_PKG, true); + LocalOverlayManager.toggleOverlaysAndWait( + new String[]{FRAMEWORK_OVERLAY_PKG, APP_OVERLAY_ONE_PKG, APP_OVERLAY_TWO_PKG}, + new String[]{}); } } diff --git a/core/tests/overlaytests/device/src/com/android/overlaytest/WithOverlayTest.java b/core/tests/overlaytests/device/src/com/android/overlaytest/WithOverlayTest.java index 6566ad304c1c..a86255e96388 100644 --- a/core/tests/overlaytests/device/src/com/android/overlaytest/WithOverlayTest.java +++ b/core/tests/overlaytests/device/src/com/android/overlaytest/WithOverlayTest.java @@ -22,8 +22,6 @@ import org.junit.BeforeClass; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; -import java.util.concurrent.Executor; - @RunWith(JUnit4.class) @MediumTest public class WithOverlayTest extends OverlayBaseTest { @@ -32,10 +30,9 @@ public class WithOverlayTest extends OverlayBaseTest { } @BeforeClass - public static void enableOverlay() throws Exception { - Executor executor = (cmd) -> new Thread(cmd).start(); - LocalOverlayManager.setEnabledAndWait(executor, APP_OVERLAY_ONE_PKG, true); - LocalOverlayManager.setEnabledAndWait(executor, APP_OVERLAY_TWO_PKG, false); - LocalOverlayManager.setEnabledAndWait(executor, FRAMEWORK_OVERLAY_PKG, true); + public static void enableOverlays() throws Exception { + LocalOverlayManager.toggleOverlaysAndWait( + new String[]{FRAMEWORK_OVERLAY_PKG, APP_OVERLAY_ONE_PKG}, + new String[]{APP_OVERLAY_TWO_PKG}); } } diff --git a/core/tests/overlaytests/device/src/com/android/overlaytest/WithoutOverlayTest.java b/core/tests/overlaytests/device/src/com/android/overlaytest/WithoutOverlayTest.java index 48cfeab2fbff..51c411819b87 100644 --- a/core/tests/overlaytests/device/src/com/android/overlaytest/WithoutOverlayTest.java +++ b/core/tests/overlaytests/device/src/com/android/overlaytest/WithoutOverlayTest.java @@ -22,8 +22,6 @@ import org.junit.BeforeClass; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; -import java.util.concurrent.Executor; - @RunWith(JUnit4.class) @MediumTest public class WithoutOverlayTest extends OverlayBaseTest { @@ -33,9 +31,8 @@ public class WithoutOverlayTest extends OverlayBaseTest { @BeforeClass public static void disableOverlays() throws Exception { - Executor executor = (cmd) -> new Thread(cmd).start(); - LocalOverlayManager.setEnabledAndWait(executor, APP_OVERLAY_ONE_PKG, false); - LocalOverlayManager.setEnabledAndWait(executor, APP_OVERLAY_TWO_PKG, false); - LocalOverlayManager.setEnabledAndWait(executor, FRAMEWORK_OVERLAY_PKG, false); + LocalOverlayManager.toggleOverlaysAndWait( + new String[]{}, + new String[]{FRAMEWORK_OVERLAY_PKG, APP_OVERLAY_ONE_PKG, APP_OVERLAY_TWO_PKG}); } } diff --git a/core/tests/overlaytests/device/test-apps/AppOverlayOne/Android.bp b/core/tests/overlaytests/device/test-apps/AppOverlayOne/Android.bp index da3aa007135a..847b4915530b 100644 --- a/core/tests/overlaytests/device/test-apps/AppOverlayOne/Android.bp +++ b/core/tests/overlaytests/device/test-apps/AppOverlayOne/Android.bp @@ -15,6 +15,6 @@ android_test { name: "OverlayDeviceTests_AppOverlayOne", sdk_version: "current", - + certificate: "platform", aaptflags: ["--no-resource-removal"], } diff --git a/core/tests/overlaytests/device/test-apps/AppOverlayTwo/Android.bp b/core/tests/overlaytests/device/test-apps/AppOverlayTwo/Android.bp index 215b66da36dc..7d5f82a71b44 100644 --- a/core/tests/overlaytests/device/test-apps/AppOverlayTwo/Android.bp +++ b/core/tests/overlaytests/device/test-apps/AppOverlayTwo/Android.bp @@ -15,6 +15,6 @@ android_test { name: "OverlayDeviceTests_AppOverlayTwo", sdk_version: "current", - + certificate: "platform", aaptflags: ["--no-resource-removal"], } diff --git a/keystore/java/android/security/AuthTokenUtils.java b/keystore/java/android/security/AuthTokenUtils.java index 14d6626e5e97..e6376000673b 100644 --- a/keystore/java/android/security/AuthTokenUtils.java +++ b/keystore/java/android/security/AuthTokenUtils.java @@ -18,7 +18,7 @@ package android.security; import android.annotation.NonNull; import android.hardware.security.keymint.HardwareAuthToken; -import android.hardware.security.keymint.Timestamp; +import android.hardware.security.secureclock.Timestamp; import java.nio.ByteBuffer; import java.nio.ByteOrder; diff --git a/keystore/java/android/security/Authorization.java b/keystore/java/android/security/Authorization.java index 2b76f25793ce..fcc518c374e3 100644 --- a/keystore/java/android/security/Authorization.java +++ b/keystore/java/android/security/Authorization.java @@ -17,11 +17,13 @@ package android.security; import android.annotation.NonNull; +import android.annotation.Nullable; import android.hardware.security.keymint.HardwareAuthToken; import android.os.RemoteException; import android.os.ServiceManager; import android.os.ServiceSpecificException; import android.security.authorization.IKeystoreAuthorization; +import android.security.authorization.LockScreenEvent; import android.system.keystore2.ResponseCode; import android.util.Log; @@ -42,7 +44,7 @@ public class Authorization { private static synchronized IKeystoreAuthorization getService() { if (sIKeystoreAuthorization == null) { sIKeystoreAuthorization = IKeystoreAuthorization.Stub.asInterface( - ServiceManager.getService("android.security.authorization")); + ServiceManager.checkService("android.security.authorization")); } return sIKeystoreAuthorization; } @@ -75,4 +77,31 @@ public class Authorization { return addAuthToken(AuthTokenUtils.toHardwareAuthToken(authToken)); } + /** + * Informs keystore2 about lock screen event. + * + * @param locked - whether it is a lock (true) or unlock (false) event + * @param syntheticPassword - if it is an unlock event with the password, pass the synthetic + * password provided by the LockSettingService + * + * @return 0 if successful or a {@code ResponseCode}. + */ + public int onLockScreenEvent(@NonNull boolean locked, @NonNull int userId, + @Nullable byte[] syntheticPassword) { + if (!android.security.keystore2.AndroidKeyStoreProvider.isInstalled()) return 0; + try { + if (locked) { + getService().onLockScreenEvent(LockScreenEvent.LOCK, userId, null); + } else { + getService().onLockScreenEvent(LockScreenEvent.UNLOCK, userId, syntheticPassword); + } + return 0; + } catch (RemoteException e) { + Log.w(TAG, "Can not connect to keystore", e); + return SYSTEM_ERROR; + } catch (ServiceSpecificException e) { + return e.errorCode; + } + } + } diff --git a/libs/hwui/pipeline/skia/SkiaDisplayList.cpp b/libs/hwui/pipeline/skia/SkiaDisplayList.cpp index 158c3493a90c..2edd48c5a41b 100644 --- a/libs/hwui/pipeline/skia/SkiaDisplayList.cpp +++ b/libs/hwui/pipeline/skia/SkiaDisplayList.cpp @@ -102,12 +102,12 @@ bool SkiaDisplayList::prepareListAndChildren( bool hasBackwardProjectedNodesSubtree = false; for (auto& child : mChildNodes) { - hasBackwardProjectedNodesHere |= child.getNodeProperties().getProjectBackwards(); RenderNode* childNode = child.getRenderNode(); Matrix4 mat4(child.getRecordedMatrix()); info.damageAccumulator->pushTransform(&mat4); info.hasBackwardProjectedNodes = false; childFn(childNode, observer, info, functorsNeedLayer); + hasBackwardProjectedNodesHere |= child.getNodeProperties().getProjectBackwards(); hasBackwardProjectedNodesSubtree |= info.hasBackwardProjectedNodes; info.damageAccumulator->popTransform(); } diff --git a/media/java/android/media/IMediaRouterService.aidl b/media/java/android/media/IMediaRouterService.aidl index 068f9689d06f..4b8a8adade1f 100644 --- a/media/java/android/media/IMediaRouterService.aidl +++ b/media/java/android/media/IMediaRouterService.aidl @@ -73,6 +73,8 @@ interface IMediaRouterService { void unregisterManager(IMediaRouter2Manager manager); void setRouteVolumeWithManager(IMediaRouter2Manager manager, int requestId, in MediaRoute2Info route, int volume); + void startScan(IMediaRouter2Manager manager); + void stopScan(IMediaRouter2Manager manager); void requestCreateSessionWithManager(IMediaRouter2Manager manager, int requestId, in RoutingSessionInfo oldSession, in @nullable MediaRoute2Info route); diff --git a/media/java/android/media/MediaRouter2Manager.java b/media/java/android/media/MediaRouter2Manager.java index 4b09a5f19fb0..68237de2ca98 100644 --- a/media/java/android/media/MediaRouter2Manager.java +++ b/media/java/android/media/MediaRouter2Manager.java @@ -147,6 +147,36 @@ public final class MediaRouter2Manager { } /** + * Starts scanning remote routes. + * @see #stopScan(String) + */ + public void startScan() { + Client client = getOrCreateClient(); + if (client != null) { + try { + mMediaRouterService.startScan(client); + } catch (RemoteException ex) { + Log.e(TAG, "Unable to get sessions. Service probably died.", ex); + } + } + } + + /** + * Stops scanning remote routes to reduce resource consumption. + * @see #startScan(String) + */ + public void stopScan() { + Client client = getOrCreateClient(); + if (client != null) { + try { + mMediaRouterService.stopScan(client); + } catch (RemoteException ex) { + Log.e(TAG, "Unable to get sessions. Service probably died.", ex); + } + } + } + + /** * Gets a {@link android.media.session.MediaController} associated with the * given routing session. * If there is no matching media session, {@code null} is returned. diff --git a/media/java/android/media/RouteDiscoveryPreference.java b/media/java/android/media/RouteDiscoveryPreference.java index 68f2964dbeb2..2f952474b7f0 100644 --- a/media/java/android/media/RouteDiscoveryPreference.java +++ b/media/java/android/media/RouteDiscoveryPreference.java @@ -153,6 +153,7 @@ public final class RouteDiscoveryPreference implements Parcelable { return false; } RouteDiscoveryPreference other = (RouteDiscoveryPreference) o; + //TODO: Make this order-free return Objects.equals(mPreferredFeatures, other.mPreferredFeatures) && mShouldPerformActiveScan == other.mShouldPerformActiveScan; } diff --git a/media/java/android/media/tv/TvInputHardwareInfo.java b/media/java/android/media/tv/TvInputHardwareInfo.java index 1249e0d3cb0f..0bedbd3c1f46 100644 --- a/media/java/android/media/tv/TvInputHardwareInfo.java +++ b/media/java/android/media/tv/TvInputHardwareInfo.java @@ -190,13 +190,16 @@ public final class TvInputHardwareInfo implements Parcelable { /** @hide */ public Builder toBuilder() { - return new Builder() + Builder newBuilder = new Builder() .deviceId(mDeviceId) .type(mType) .audioType(mAudioType) .audioAddress(mAudioAddress) - .hdmiPortId(mHdmiPortId) .cableConnectionStatus(mCableConnectionStatus); + if (mType == TV_INPUT_TYPE_HDMI) { + newBuilder.hdmiPortId(mHdmiPortId); + } + return newBuilder; } public static final class Builder { diff --git a/media/java/android/media/tv/tuner/dvr/DvrRecorder.java b/media/java/android/media/tv/tuner/dvr/DvrRecorder.java index 887116725961..c4b622d0fba9 100644 --- a/media/java/android/media/tv/tuner/dvr/DvrRecorder.java +++ b/media/java/android/media/tv/tuner/dvr/DvrRecorder.java @@ -47,6 +47,7 @@ public class DvrRecorder implements AutoCloseable { private static int sInstantId = 0; private int mSegmentId = 0; private int mOverflow; + private Boolean mIsStopped = null; private native int nativeAttachFilter(Filter filter); private native int nativeDetachFilter(Filter filter); @@ -135,7 +136,13 @@ public class DvrRecorder implements AutoCloseable { .write(FrameworkStatsLog.TV_TUNER_DVR_STATUS, mUserId, FrameworkStatsLog.TV_TUNER_DVR_STATUS__TYPE__RECORD, FrameworkStatsLog.TV_TUNER_DVR_STATUS__STATE__STARTED, mSegmentId, 0); - return nativeStartDvr(); + synchronized (mIsStopped) { + int result = nativeStartDvr(); + if (result == Tuner.RESULT_SUCCESS) { + mIsStopped = false; + } + return result; + } } /** @@ -152,7 +159,13 @@ public class DvrRecorder implements AutoCloseable { .write(FrameworkStatsLog.TV_TUNER_DVR_STATUS, mUserId, FrameworkStatsLog.TV_TUNER_DVR_STATUS__TYPE__RECORD, FrameworkStatsLog.TV_TUNER_DVR_STATUS__STATE__STOPPED, mSegmentId, mOverflow); - return nativeStopDvr(); + synchronized (mIsStopped) { + int result = nativeStopDvr(); + if (result == Tuner.RESULT_SUCCESS) { + mIsStopped = true; + } + return result; + } } /** @@ -164,7 +177,13 @@ public class DvrRecorder implements AutoCloseable { */ @Result public int flush() { - return nativeFlushDvr(); + synchronized (mIsStopped) { + if (mIsStopped) { + return nativeFlushDvr(); + } + Log.w(TAG, "Cannot flush non-stopped Record DVR."); + return Tuner.RESULT_INVALID_STATE; + } } /** diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java index 5a7c5c9b5ebc..f65f97a3a450 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusIconContainer.java @@ -271,7 +271,7 @@ public class StatusIconContainer extends AlphaOptimizedLinearLayout { float contentStart = getPaddingStart(); int childCount = getChildCount(); // Underflow === don't show content until that index - if (DEBUG) android.util.Log.d(TAG, "calculateIconTranslations: start=" + translationX + if (DEBUG) Log.d(TAG, "calculateIconTranslations: start=" + translationX + " width=" + width + " underflow=" + mNeedsUnderflow); // Collect all of the states which want to be visible diff --git a/services/Android.bp b/services/Android.bp index ef52c2aff002..785ca3537eb3 100644 --- a/services/Android.bp +++ b/services/Android.bp @@ -147,11 +147,20 @@ droidstubs { baseline_file: "api/lint-baseline.txt", }, }, - dist: { - targets: ["sdk", "win_sdk"], - dir: "apistubs/android/system-server/api", - dest: "android.txt", - }, + dists: [ + { + targets: ["sdk", "win_sdk"], + dir: "apistubs/android/system-server/api", + dest: "android.txt", + tag: ".api.txt" + }, + { + targets: ["sdk", "win_sdk"], + dir: "apistubs/android/system-server/api", + dest: "removed.txt", + tag: ".removed-api.txt", + }, + ] } java_library { diff --git a/services/accessibility/OWNERS b/services/accessibility/OWNERS index c6f42f719caa..a31cfae995b2 100644 --- a/services/accessibility/OWNERS +++ b/services/accessibility/OWNERS @@ -1,4 +1,4 @@ svetoslavganov@google.com pweaver@google.com rhedjao@google.com -qasid@google.com +ryanlwlin@google.com diff --git a/services/appwidget/java/com/android/server/appwidget/OWNERS b/services/appwidget/java/com/android/server/appwidget/OWNERS new file mode 100644 index 000000000000..d724cac4aa3e --- /dev/null +++ b/services/appwidget/java/com/android/server/appwidget/OWNERS @@ -0,0 +1 @@ +include /core/java/android/appwidget/OWNERS diff --git a/services/core/Android.bp b/services/core/Android.bp index 307d344bffa7..adebcc7ee54e 100644 --- a/services/core/Android.bp +++ b/services/core/Android.bp @@ -112,6 +112,9 @@ java_library_static { "time_zone_distro", "time_zone_distro_installer", "android.hardware.authsecret-V1.0-java", + "android.hardware.boot-V1.0-java", + "android.hardware.boot-V1.1-java", + "android.hardware.boot-V1.2-java", "android.hardware.broadcastradio-V2.0-java", "android.hardware.health-V1.0-java", "android.hardware.health-V2.0-java", diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 3ad4c5bd72ba..b07e98f60237 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -888,6 +888,13 @@ public class ConnectivityService extends IConnectivityManager.Stub } /** + * Get a reference to the system keystore. + */ + public KeyStore getKeyStore() { + return KeyStore.getInstance(); + } + + /** * @see ProxyTracker */ public ProxyTracker makeProxyTracker(@NonNull Context context, @@ -981,7 +988,7 @@ public class ConnectivityService extends IConnectivityManager.Stub mProxyTracker = mDeps.makeProxyTracker(mContext, mHandler); mNetd = netd; - mKeyStore = KeyStore.getInstance(); + mKeyStore = mDeps.getKeyStore(); mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE); mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE); mLocationPermissionChecker = new LocationPermissionChecker(mContext); @@ -1108,11 +1115,7 @@ public class ConnectivityService extends IConnectivityManager.Stub userAllContext.registerReceiver( mIntentReceiver, intentFilter, NETWORK_STACK, mHandler); - try { - mNMS.registerObserver(mDataActivityObserver); - } catch (RemoteException e) { - loge("Error registering observer :" + e); - } + mNetworkActivityTracker = new LegacyNetworkActivityTracker(mContext, mNMS); mSettingsObserver = new SettingsObserver(mContext, mHandler); registerSettingsCallbacks(); @@ -1644,7 +1647,6 @@ public class ConnectivityService extends IConnectivityManager.Stub private NetworkCapabilities getNetworkCapabilitiesInternal(NetworkAgentInfo nai) { if (nai == null) return null; synchronized (nai) { - if (nai.networkCapabilities == null) return null; return networkCapabilitiesRestrictedForCallerPermissions( nai.networkCapabilities, Binder.getCallingPid(), mDeps.getCallingUid()); } @@ -1796,30 +1798,6 @@ public class ConnectivityService extends IConnectivityManager.Stub } } - private INetworkManagementEventObserver mDataActivityObserver = new BaseNetworkObserver() { - @Override - public void interfaceClassDataActivityChanged(int transportType, boolean active, - long tsNanos, int uid) { - sendDataActivityBroadcast(transportTypeToLegacyType(transportType), active, tsNanos); - } - }; - - // This is deprecated and only to support legacy use cases. - private int transportTypeToLegacyType(int type) { - switch (type) { - case NetworkCapabilities.TRANSPORT_CELLULAR: - return ConnectivityManager.TYPE_MOBILE; - case NetworkCapabilities.TRANSPORT_WIFI: - return ConnectivityManager.TYPE_WIFI; - case NetworkCapabilities.TRANSPORT_BLUETOOTH: - return ConnectivityManager.TYPE_BLUETOOTH; - case NetworkCapabilities.TRANSPORT_ETHERNET: - return ConnectivityManager.TYPE_ETHERNET; - default: - loge("Unexpected transport in transportTypeToLegacyType: " + type); - } - return ConnectivityManager.TYPE_NONE; - } /** * Ensures that the system cannot call a particular method. */ @@ -2268,20 +2246,6 @@ public class ConnectivityService extends IConnectivityManager.Stub sendStickyBroadcast(makeGeneralIntent(info, bcastType)); } - private void sendDataActivityBroadcast(int deviceType, boolean active, long tsNanos) { - Intent intent = new Intent(ConnectivityManager.ACTION_DATA_ACTIVITY_CHANGE); - intent.putExtra(ConnectivityManager.EXTRA_DEVICE_TYPE, deviceType); - intent.putExtra(ConnectivityManager.EXTRA_IS_ACTIVE, active); - intent.putExtra(ConnectivityManager.EXTRA_REALTIME_NS, tsNanos); - final long ident = Binder.clearCallingIdentity(); - try { - mContext.sendOrderedBroadcastAsUser(intent, UserHandle.ALL, - RECEIVE_DATA_ACTIVITY_CHANGE, null, null, 0, null, null); - } finally { - Binder.restoreCallingIdentity(ident); - } - } - private void sendStickyBroadcast(Intent intent) { synchronized (this) { if (!mSystemReady @@ -2387,74 +2351,6 @@ public class ConnectivityService extends IConnectivityManager.Stub } /** - * Setup data activity tracking for the given network. - * - * Every {@code setupDataActivityTracking} should be paired with a - * {@link #removeDataActivityTracking} for cleanup. - */ - private void setupDataActivityTracking(NetworkAgentInfo networkAgent) { - final String iface = networkAgent.linkProperties.getInterfaceName(); - - final int timeout; - final int type; - - if (networkAgent.networkCapabilities.hasTransport( - NetworkCapabilities.TRANSPORT_CELLULAR)) { - timeout = Settings.Global.getInt(mContext.getContentResolver(), - Settings.Global.DATA_ACTIVITY_TIMEOUT_MOBILE, - 10); - type = NetworkCapabilities.TRANSPORT_CELLULAR; - } else if (networkAgent.networkCapabilities.hasTransport( - NetworkCapabilities.TRANSPORT_WIFI)) { - timeout = Settings.Global.getInt(mContext.getContentResolver(), - Settings.Global.DATA_ACTIVITY_TIMEOUT_WIFI, - 15); - type = NetworkCapabilities.TRANSPORT_WIFI; - } else { - return; // do not track any other networks - } - - if (timeout > 0 && iface != null) { - try { - mNMS.addIdleTimer(iface, timeout, type); - } catch (Exception e) { - // You shall not crash! - loge("Exception in setupDataActivityTracking " + e); - } - } - } - - /** - * Remove data activity tracking when network disconnects. - */ - private void removeDataActivityTracking(NetworkAgentInfo networkAgent) { - final String iface = networkAgent.linkProperties.getInterfaceName(); - final NetworkCapabilities caps = networkAgent.networkCapabilities; - - if (iface != null && (caps.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) || - caps.hasTransport(NetworkCapabilities.TRANSPORT_WIFI))) { - try { - // the call fails silently if no idle timer setup for this interface - mNMS.removeIdleTimer(iface); - } catch (Exception e) { - loge("Exception in removeDataActivityTracking " + e); - } - } - } - - /** - * Update data activity tracking when network state is updated. - */ - private void updateDataActivityTracking(NetworkAgentInfo newNetwork, - NetworkAgentInfo oldNetwork) { - if (newNetwork != null) { - setupDataActivityTracking(newNetwork); - } - if (oldNetwork != null) { - removeDataActivityTracking(oldNetwork); - } - } - /** * Reads the network specific MTU size from resources. * and set it on it's iface. */ @@ -2768,7 +2664,6 @@ public class ConnectivityService extends IConnectivityManager.Stub } private boolean isLiveNetworkAgent(NetworkAgentInfo nai, int what) { - if (nai.network == null) return false; final NetworkAgentInfo officialNai = getNetworkAgentInfoForNetwork(nai.network); if (officialNai != null && officialNai.equals(nai)) return true; if (officialNai != null || VDBG) { @@ -2869,13 +2764,7 @@ public class ConnectivityService extends IConnectivityManager.Stub Log.wtf(TAG, "Non-virtual networks cannot have underlying networks"); break; } - final ArrayList<Network> underlying; - try { - underlying = ((Bundle) arg.second).getParcelableArrayList( - NetworkAgent.UNDERLYING_NETWORKS_KEY); - } catch (NullPointerException | ClassCastException e) { - break; - } + final List<Network> underlying = (List<Network>) arg.second; final Network[] oldUnderlying = nai.declaredUnderlyingNetworks; nai.declaredUnderlyingNetworks = (underlying != null) ? underlying.toArray(new Network[0]) : null; @@ -3461,6 +3350,7 @@ public class ConnectivityService extends IConnectivityManager.Stub // available until we've told netd to delete it below. mNetworkForNetId.remove(nai.network.getNetId()); } + propagateUnderlyingNetworkCapabilities(nai.network); // Remove all previously satisfied requests. for (int i = 0; i < nai.numNetworkRequests(); i++) { NetworkRequest request = nai.requestAt(i); @@ -3473,10 +3363,12 @@ public class ConnectivityService extends IConnectivityManager.Stub } } nai.clearLingerState(); - propagateUnderlyingNetworkCapabilities(nai.network); + // TODO: this loop, and the mLegacyTypeTracker.remove just below it, seem redundant given + // there's a full rematch right after. Currently, deleting it breaks tests that check for + // the default network disconnecting. Find out why, fix the rematch code, and delete this. if (nai.isSatisfyingRequest(mDefaultRequest.requestId)) { mDefaultNetworkNai = null; - updateDataActivityTracking(null /* newNetwork */, nai); + mNetworkActivityTracker.updateDataActivityTracking(null /* newNetwork */, nai); notifyLockdownVpn(nai); ensureNetworkTransitionWakelock(nai.toShortString()); } @@ -4984,16 +4876,23 @@ public class ConnectivityService extends IConnectivityManager.Stub mVpnBlockedUidRanges = newVpnBlockedUidRanges; } + private boolean isLockdownVpnEnabled() { + return mKeyStore.contains(Credentials.LOCKDOWN_VPN); + } + @Override public boolean updateLockdownVpn() { - if (mDeps.getCallingUid() != Process.SYSTEM_UID) { - logw("Lockdown VPN only available to AID_SYSTEM"); + // Allow the system UID for the system server and for Settings. + // Also, for unit tests, allow the process that ConnectivityService is running in. + if (mDeps.getCallingUid() != Process.SYSTEM_UID + && Binder.getCallingPid() != Process.myPid()) { + logw("Lockdown VPN only available to system process or AID_SYSTEM"); return false; } synchronized (mVpns) { // Tear down existing lockdown if profile was removed - mLockdownEnabled = LockdownVpnTracker.isEnabled(); + mLockdownEnabled = isLockdownVpnEnabled(); if (mLockdownEnabled) { byte[] profileTag = mKeyStore.get(Credentials.LOCKDOWN_VPN); if (profileTag == null) { @@ -5014,7 +4913,8 @@ public class ConnectivityService extends IConnectivityManager.Stub logw("VPN for user " + user + " not ready yet. Skipping lockdown"); return false; } - setLockdownTracker(new LockdownVpnTracker(mContext, this, mHandler, vpn, profile)); + setLockdownTracker( + new LockdownVpnTracker(mContext, this, mHandler, mKeyStore, vpn, profile)); } else { setLockdownTracker(null); } @@ -5102,7 +5002,7 @@ public class ConnectivityService extends IConnectivityManager.Stub synchronized (mVpns) { // Can't set always-on VPN if legacy VPN is already in lockdown mode. - if (LockdownVpnTracker.isEnabled()) { + if (isLockdownVpnEnabled()) { return false; } @@ -5208,7 +5108,7 @@ public class ConnectivityService extends IConnectivityManager.Stub } userVpn = new Vpn(mHandler.getLooper(), mContext, mNMS, mNetd, userId, mKeyStore); mVpns.put(userId, userVpn); - if (mUserManager.getUserInfo(userId).isPrimary() && LockdownVpnTracker.isEnabled()) { + if (mUserManager.getUserInfo(userId).isPrimary() && isLockdownVpnEnabled()) { updateLockdownVpn(); } } @@ -5292,7 +5192,7 @@ public class ConnectivityService extends IConnectivityManager.Stub private void onUserUnlocked(int userId) { synchronized (mVpns) { // User present may be sent because of an unlock, which might mean an unlocked keystore. - if (mUserManager.getUserInfo(userId).isPrimary() && LockdownVpnTracker.isEnabled()) { + if (mUserManager.getUserInfo(userId).isPrimary() && isLockdownVpnEnabled()) { updateLockdownVpn(); } else { startAlwaysOnVpn(userId); @@ -6059,6 +5959,10 @@ public class ConnectivityService extends IConnectivityManager.Stub public Network registerNetworkAgent(INetworkAgent na, NetworkInfo networkInfo, LinkProperties linkProperties, NetworkCapabilities networkCapabilities, int currentScore, NetworkAgentConfig networkAgentConfig, int providerId) { + Objects.requireNonNull(networkInfo, "networkInfo must not be null"); + Objects.requireNonNull(linkProperties, "linkProperties must not be null"); + Objects.requireNonNull(networkCapabilities, "networkCapabilities must not be null"); + Objects.requireNonNull(networkAgentConfig, "networkAgentConfig must not be null"); if (networkCapabilities.hasTransport(TRANSPORT_TEST)) { enforceAnyPermissionOf(Manifest.permission.MANAGE_TEST_NETWORKS); } else { @@ -6597,7 +6501,7 @@ public class ConnectivityService extends IConnectivityManager.Stub } // Don't modify caller's NetworkCapabilities. - NetworkCapabilities newNc = new NetworkCapabilities(nc); + final NetworkCapabilities newNc = new NetworkCapabilities(nc); if (nai.lastValidated) { newNc.addCapability(NET_CAPABILITY_VALIDATED); } else { @@ -6685,26 +6589,21 @@ public class ConnectivityService extends IConnectivityManager.Stub notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_CAP_CHANGED); } - // TODO : static analysis indicates that prevNc can't be null here (getAndSetNetworkCaps - // never returns null), so mark the relevant members and functions in nai as @NonNull and - // remove this test - if (prevNc != null) { - final boolean oldMetered = prevNc.isMetered(); - final boolean newMetered = newNc.isMetered(); - final boolean meteredChanged = oldMetered != newMetered; + final boolean oldMetered = prevNc.isMetered(); + final boolean newMetered = newNc.isMetered(); + final boolean meteredChanged = oldMetered != newMetered; - if (meteredChanged) { - maybeNotifyNetworkBlocked(nai, oldMetered, newMetered, mRestrictBackground, - mRestrictBackground, mVpnBlockedUidRanges, mVpnBlockedUidRanges); - } + if (meteredChanged) { + maybeNotifyNetworkBlocked(nai, oldMetered, newMetered, mRestrictBackground, + mRestrictBackground, mVpnBlockedUidRanges, mVpnBlockedUidRanges); + } - final boolean roamingChanged = prevNc.hasCapability(NET_CAPABILITY_NOT_ROAMING) != - newNc.hasCapability(NET_CAPABILITY_NOT_ROAMING); + final boolean roamingChanged = prevNc.hasCapability(NET_CAPABILITY_NOT_ROAMING) + != newNc.hasCapability(NET_CAPABILITY_NOT_ROAMING); - // Report changes that are interesting for network statistics tracking. - if (meteredChanged || roamingChanged) { - notifyIfacesChangedForNetworkStats(); - } + // Report changes that are interesting for network statistics tracking. + if (meteredChanged || roamingChanged) { + notifyIfacesChangedForNetworkStats(); } // This network might have been underlying another network. Propagate its capabilities. @@ -7299,7 +7198,8 @@ public class ConnectivityService extends IConnectivityManager.Stub if (oldDefaultNetwork != null) { mLingerMonitor.noteLingerDefaultNetwork(oldDefaultNetwork, newDefaultNetwork); } - updateDataActivityTracking(newDefaultNetwork, oldDefaultNetwork); + mNetworkActivityTracker.updateDataActivityTracking( + newDefaultNetwork, oldDefaultNetwork); // Notify system services of the new default. makeDefault(newDefaultNetwork); @@ -7579,10 +7479,6 @@ public class ConnectivityService extends IConnectivityManager.Stub if (!networkAgent.everConnected && state == NetworkInfo.State.CONNECTED) { networkAgent.everConnected = true; - if (networkAgent.linkProperties == null) { - Log.wtf(TAG, networkAgent.toShortString() + " connected with null LinkProperties"); - } - // NetworkCapabilities need to be set before sending the private DNS config to // NetworkMonitor, otherwise NetworkMonitor cannot determine if validation is required. networkAgent.getAndSetNetworkCapabilities(networkAgent.networkCapabilities); @@ -7901,10 +7797,11 @@ public class ConnectivityService extends IConnectivityManager.Stub } @Override - public void startNattKeepaliveWithFd(Network network, FileDescriptor fd, int resourceId, + public void startNattKeepaliveWithFd(Network network, ParcelFileDescriptor pfd, int resourceId, int intervalSeconds, ISocketKeepaliveCallback cb, String srcAddr, String dstAddr) { try { + final FileDescriptor fd = pfd.getFileDescriptor(); mKeepaliveTracker.startNattKeepalive( getNetworkAgentInfoForNetwork(network), fd, resourceId, intervalSeconds, cb, @@ -7912,24 +7809,25 @@ public class ConnectivityService extends IConnectivityManager.Stub } finally { // FileDescriptors coming from AIDL calls must be manually closed to prevent leaks. // startNattKeepalive calls Os.dup(fd) before returning, so we can close immediately. - if (fd != null && Binder.getCallingPid() != Process.myPid()) { - IoUtils.closeQuietly(fd); + if (pfd != null && Binder.getCallingPid() != Process.myPid()) { + IoUtils.closeQuietly(pfd); } } } @Override - public void startTcpKeepalive(Network network, FileDescriptor fd, int intervalSeconds, + public void startTcpKeepalive(Network network, ParcelFileDescriptor pfd, int intervalSeconds, ISocketKeepaliveCallback cb) { try { enforceKeepalivePermission(); + final FileDescriptor fd = pfd.getFileDescriptor(); mKeepaliveTracker.startTcpKeepalive( getNetworkAgentInfoForNetwork(network), fd, intervalSeconds, cb); } finally { // FileDescriptors coming from AIDL calls must be manually closed to prevent leaks. // startTcpKeepalive calls Os.dup(fd) before returning, so we can close immediately. - if (fd != null && Binder.getCallingPid() != Process.myPid()) { - IoUtils.closeQuietly(fd); + if (pfd != null && Binder.getCallingPid() != Process.myPid()) { + IoUtils.closeQuietly(pfd); } } } @@ -8655,4 +8553,145 @@ public class ConnectivityService extends IConnectivityManager.Stub notifyDataStallSuspected(p, network.getNetId()); } + + private final LegacyNetworkActivityTracker mNetworkActivityTracker; + + /** + * Class used for updating network activity tracking with netd and notify network activity + * changes. + */ + private static final class LegacyNetworkActivityTracker { + private final Context mContext; + private final INetworkManagementService mNMS; + + LegacyNetworkActivityTracker(@NonNull Context context, + @NonNull INetworkManagementService nms) { + mContext = context; + mNMS = nms; + try { + mNMS.registerObserver(mDataActivityObserver); + } catch (RemoteException e) { + loge("Error registering observer :" + e); + } + } + + // TODO: Migrate away the dependency with INetworkManagementEventObserver. + private final INetworkManagementEventObserver mDataActivityObserver = + new BaseNetworkObserver() { + @Override + public void interfaceClassDataActivityChanged(int transportType, boolean active, + long tsNanos, int uid) { + sendDataActivityBroadcast(transportTypeToLegacyType(transportType), active, + tsNanos); + } + }; + + // This is deprecated and only to support legacy use cases. + private int transportTypeToLegacyType(int type) { + switch (type) { + case NetworkCapabilities.TRANSPORT_CELLULAR: + return ConnectivityManager.TYPE_MOBILE; + case NetworkCapabilities.TRANSPORT_WIFI: + return ConnectivityManager.TYPE_WIFI; + case NetworkCapabilities.TRANSPORT_BLUETOOTH: + return ConnectivityManager.TYPE_BLUETOOTH; + case NetworkCapabilities.TRANSPORT_ETHERNET: + return ConnectivityManager.TYPE_ETHERNET; + default: + loge("Unexpected transport in transportTypeToLegacyType: " + type); + } + return ConnectivityManager.TYPE_NONE; + } + + public void sendDataActivityBroadcast(int deviceType, boolean active, long tsNanos) { + final Intent intent = new Intent(ConnectivityManager.ACTION_DATA_ACTIVITY_CHANGE); + intent.putExtra(ConnectivityManager.EXTRA_DEVICE_TYPE, deviceType); + intent.putExtra(ConnectivityManager.EXTRA_IS_ACTIVE, active); + intent.putExtra(ConnectivityManager.EXTRA_REALTIME_NS, tsNanos); + final long ident = Binder.clearCallingIdentity(); + try { + mContext.sendOrderedBroadcastAsUser(intent, UserHandle.ALL, + RECEIVE_DATA_ACTIVITY_CHANGE, + null /* resultReceiver */, + null /* scheduler */, + 0 /* initialCode */, + null /* initialData */, + null /* initialExtra */); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + + /** + * Setup data activity tracking for the given network. + * + * Every {@code setupDataActivityTracking} should be paired with a + * {@link #removeDataActivityTracking} for cleanup. + */ + private void setupDataActivityTracking(NetworkAgentInfo networkAgent) { + final String iface = networkAgent.linkProperties.getInterfaceName(); + + final int timeout; + final int type; + + if (networkAgent.networkCapabilities.hasTransport( + NetworkCapabilities.TRANSPORT_CELLULAR)) { + timeout = Settings.Global.getInt(mContext.getContentResolver(), + Settings.Global.DATA_ACTIVITY_TIMEOUT_MOBILE, + 10); + type = NetworkCapabilities.TRANSPORT_CELLULAR; + } else if (networkAgent.networkCapabilities.hasTransport( + NetworkCapabilities.TRANSPORT_WIFI)) { + timeout = Settings.Global.getInt(mContext.getContentResolver(), + Settings.Global.DATA_ACTIVITY_TIMEOUT_WIFI, + 15); + type = NetworkCapabilities.TRANSPORT_WIFI; + } else { + return; // do not track any other networks + } + + if (timeout > 0 && iface != null) { + try { + // TODO: Access INetd directly instead of NMS + mNMS.addIdleTimer(iface, timeout, type); + } catch (Exception e) { + // You shall not crash! + loge("Exception in setupDataActivityTracking " + e); + } + } + } + + /** + * Remove data activity tracking when network disconnects. + */ + private void removeDataActivityTracking(NetworkAgentInfo networkAgent) { + final String iface = networkAgent.linkProperties.getInterfaceName(); + final NetworkCapabilities caps = networkAgent.networkCapabilities; + + if (iface != null && (caps.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) + || caps.hasTransport(NetworkCapabilities.TRANSPORT_WIFI))) { + try { + // the call fails silently if no idle timer setup for this interface + // TODO: Access INetd directly instead of NMS + mNMS.removeIdleTimer(iface); + } catch (Exception e) { + // You shall not crash! + loge("Exception in removeDataActivityTracking " + e); + } + } + } + + /** + * Update data activity tracking when network state is updated. + */ + public void updateDataActivityTracking(NetworkAgentInfo newNetwork, + NetworkAgentInfo oldNetwork) { + if (newNetwork != null) { + setupDataActivityTracking(newNetwork); + } + if (oldNetwork != null) { + removeDataActivityTracking(oldNetwork); + } + } + } } diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java index 1ea4a89a761f..d30a6405e95d 100644 --- a/services/core/java/com/android/server/NetworkManagementService.java +++ b/services/core/java/com/android/server/NetworkManagementService.java @@ -405,6 +405,9 @@ public class NetworkManagementService extends INetworkManagementService.Stub { if (mLastPowerStateFromRadio != powerState) { mLastPowerStateFromRadio = powerState; try { + // TODO: The interface changes that comes from netd are handled by BSS itself. + // There are still events caused by setting or removing idle timer, so keep + // reporting from here until setting idler timer moved to CS. getBatteryStats().noteMobileRadioPowerState(powerState, tsNanos, uid); } catch (RemoteException e) { } @@ -415,6 +418,9 @@ public class NetworkManagementService extends INetworkManagementService.Stub { if (mLastPowerStateFromWifi != powerState) { mLastPowerStateFromWifi = powerState; try { + // TODO: The interface changes that comes from netd are handled by BSS itself. + // There are still events caused by setting or removing idle timer, so keep + // reporting from here until setting idler timer moved to CS. getBatteryStats().noteWifiRadioPowerState(powerState, tsNanos, uid); } catch (RemoteException e) { } diff --git a/services/core/java/com/android/server/OWNERS b/services/core/java/com/android/server/OWNERS index f6b72d6bfe2c..222c96f2496b 100644 --- a/services/core/java/com/android/server/OWNERS +++ b/services/core/java/com/android/server/OWNERS @@ -6,10 +6,10 @@ per-file VibratorService.java, DisplayThread.java = michaelwr@google.com per-file VibratorService.java, DisplayThread.java = ogunwale@google.com # Zram writeback -per-file ZramWriteback.java = minchan@google.com, rajekumar@google.com, srnvs@google.com +per-file ZramWriteback.java = minchan@google.com, rajekumar@google.com # Userspace reboot -per-file UserspaceRebootLogger.java = ioffe@google.com, tomcherry@google.com +per-file UserspaceRebootLogger.java = ioffe@google.com, dvander@google.com # Sensor Privacy per-file SensorPrivacyService.java = file:platform/frameworks/native:/libs/sensorprivacy/OWNERS @@ -31,6 +31,7 @@ per-file IpSecService.java = file:/services/core/java/com/android/server/net/OWN per-file MmsServiceBroker.java = file:/telephony/OWNERS per-file NetIdManager.java = file:/services/core/java/com/android/server/net/OWNERS per-file PackageWatchdog.java = file:/services/core/java/com/android/server/rollback/OWNERS +per-file PinnerService.java = file:/apct-tests/perftests/OWNERS per-file TelephonyRegistry.java = file:/telephony/OWNERS per-file UiModeManagerService.java = file:/packages/SystemUI/OWNERS per-file VcnManagementService.java = file:/services/core/java/com/android/server/vcn/OWNERS diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java index c8d457d370ff..5c34584d0adf 100644 --- a/services/core/java/com/android/server/StorageManagerService.java +++ b/services/core/java/com/android/server/StorageManagerService.java @@ -1537,6 +1537,9 @@ class StorageManagerService extends IStorageManager.Stub mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget(); } else if (vol.type == VolumeInfo.TYPE_STUB) { + if (vol.disk.isStubVisible()) { + vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE; + } vol.mountUserId = mCurrentUserId; mHandler.obtainMessage(H_VOLUME_MOUNT, vol).sendToTarget(); } else { @@ -1606,7 +1609,6 @@ class StorageManagerService extends IStorageManager.Stub } } - private void onVolumeStateChangedAsync(VolumeInfo vol, int oldState, int newState) { synchronized (mLock) { // Remember that we saw this volume so we're ready to accept user @@ -3427,6 +3429,27 @@ class StorageManagerService extends IStorageManager.Stub } } + /* + * Disable storage's app data isolation for testing. + */ + @Override + public void disableAppDataIsolation(String pkgName, int pid, int userId) { + final int callingUid = Binder.getCallingUid(); + if (callingUid != Process.ROOT_UID && callingUid != Process.SHELL_UID) { + throw new SecurityException("no permission to enable app visibility"); + } + final String[] sharedPackages = + mPmInternal.getSharedUserPackagesForPackage(pkgName, userId); + final int uid = mPmInternal.getPackageUid(pkgName, 0, userId); + final String[] packages = + sharedPackages.length != 0 ? sharedPackages : new String[]{pkgName}; + try { + mVold.unmountAppStorageDirs(uid, pid, packages); + } catch (RemoteException e) { + throw e.rethrowAsRuntimeException(); + } + } + /** Not thread safe */ class AppFuseMountScope extends AppFuseBridge.MountScope { private boolean mMounted = false; diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java index 5560f8137e4c..81d2b831dc3c 100644 --- a/services/core/java/com/android/server/TelephonyRegistry.java +++ b/services/core/java/com/android/server/TelephonyRegistry.java @@ -52,7 +52,6 @@ import android.telephony.CallAttributes; import android.telephony.CallQuality; import android.telephony.CellIdentity; import android.telephony.CellInfo; -import android.telephony.CellLocation; import android.telephony.CellSignalStrength; import android.telephony.CellSignalStrengthCdma; import android.telephony.CellSignalStrengthGsm; @@ -584,8 +583,6 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) public TelephonyRegistry(Context context, ConfigurationProvider configurationProvider) { - CellLocation location = CellLocation.getEmpty(); - mContext = context; mConfigurationProvider = configurationProvider; mBatteryStats = BatteryStatsService.getService(); diff --git a/services/core/java/com/android/server/VcnManagementService.java b/services/core/java/com/android/server/VcnManagementService.java index c191a78aad0e..2fdc7965675d 100644 --- a/services/core/java/com/android/server/VcnManagementService.java +++ b/services/core/java/com/android/server/VcnManagementService.java @@ -26,6 +26,7 @@ import android.app.AppOpsManager; import android.content.Context; import android.net.ConnectivityManager; import android.net.vcn.IVcnManagementService; +import android.net.vcn.IVcnUnderlyingNetworkPolicyListener; import android.net.vcn.VcnConfig; import android.os.Binder; import android.os.Handler; @@ -495,4 +496,20 @@ public class VcnManagementService extends IVcnManagementService.Stub { return Collections.unmodifiableMap(mVcns); } } + + /** Adds the provided listener for receiving VcnUnderlyingNetworkPolicy updates. */ + @Override + public void addVcnUnderlyingNetworkPolicyListener( + IVcnUnderlyingNetworkPolicyListener listener) { + // TODO(b/175739863): implement policy listener registration + throw new UnsupportedOperationException("Not yet implemented"); + } + + /** Removes the provided listener from receiving VcnUnderlyingNetworkPolicy updates. */ + @Override + public void removeVcnUnderlyingNetworkPolicyListener( + IVcnUnderlyingNetworkPolicyListener listener) { + // TODO(b/175739863): implement policy listener unregistration + throw new UnsupportedOperationException("Not yet implemented"); + } } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 928ddab9dca7..686adbb7b793 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -190,6 +190,7 @@ import android.app.usage.UsageEvents.Event; import android.app.usage.UsageStatsManager; import android.app.usage.UsageStatsManagerInternal; import android.appwidget.AppWidgetManager; +import android.compat.Compatibility; import android.content.AutofillOptions; import android.content.BroadcastReceiver; import android.content.ComponentCallbacks2; @@ -318,6 +319,7 @@ import com.android.internal.app.IAppOpsService; import com.android.internal.app.ProcessMap; import com.android.internal.app.SystemUserHomeActivity; import com.android.internal.app.procstats.ProcessStats; +import com.android.internal.compat.CompatibilityChangeConfig; import com.android.internal.content.PackageHelper; import com.android.internal.messages.nano.SystemMessageProto.SystemMessage; import com.android.internal.notification.SystemNotificationChannels; @@ -16944,6 +16946,8 @@ public class ActivityManagerService extends IActivityManager.Stub if (disableHiddenApiChecks || disableTestApiChecks) { enforceCallingPermission(android.Manifest.permission.DISABLE_HIDDEN_API_CHECKS, "disable hidden API checks"); + + enableTestApiAccess(ii.packageName); } // TODO(b/158750470): remove @@ -17083,6 +17087,25 @@ public class ActivityManagerService extends IActivityManager.Stub forceStopPackageLocked(app.info.packageName, -1, false, false, true, true, false, app.userId, "finished inst"); + + disableTestApiAccess(app.info.packageName); + } + + private void enableTestApiAccess(String packageName) { + if (mPlatformCompat != null) { + Compatibility.ChangeConfig config = new Compatibility.ChangeConfig( + Collections.singleton(166236554L /* VMRuntime.ALLOW_TEST_API_ACCESS */), + Collections.emptySet()); + CompatibilityChangeConfig override = new CompatibilityChangeConfig(config); + mPlatformCompat.setOverridesForTest(override, packageName); + } + } + + private void disableTestApiAccess(String packageName) { + if (mPlatformCompat != null) { + mPlatformCompat.clearOverrideForTest(166236554L /* VMRuntime.ALLOW_TEST_API_ACCESS */, + packageName); + } } public void finishInstrumentation(IApplicationThread target, diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java index 1ade8e7e9311..3c538806be01 100644 --- a/services/core/java/com/android/server/am/BatteryStatsService.java +++ b/services/core/java/com/android/server/am/BatteryStatsService.java @@ -21,11 +21,14 @@ import android.content.ContentResolver; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; +import android.net.INetworkManagementEventObserver; +import android.net.NetworkCapabilities; import android.os.BatteryStats; import android.os.BatteryStatsInternal; import android.os.Binder; import android.os.Handler; import android.os.IBinder; +import android.os.INetworkManagementService; import android.os.Parcel; import android.os.ParcelFileDescriptor; import android.os.ParcelFormatException; @@ -33,6 +36,7 @@ import android.os.PowerManager.ServiceType; import android.os.PowerManagerInternal; import android.os.PowerSaveState; import android.os.Process; +import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemClock; import android.os.UserHandle; @@ -52,6 +56,7 @@ import android.telephony.SignalStrength; import android.telephony.TelephonyManager; import android.util.Slog; +import com.android.internal.annotations.GuardedBy; import com.android.internal.app.IBatteryStats; import com.android.internal.os.BatteryStatsHelper; import com.android.internal.os.BatteryStatsImpl; @@ -62,6 +67,7 @@ import com.android.internal.util.DumpUtils; import com.android.internal.util.FrameworkStatsLog; import com.android.internal.util.ParseUtils; import com.android.server.LocalServices; +import com.android.server.net.BaseNetworkObserver; import java.io.File; import java.io.FileDescriptor; @@ -108,6 +114,39 @@ public final class BatteryStatsService extends IBatteryStats.Stub private CharBuffer mUtf16BufferStat = CharBuffer.allocate(MAX_LOW_POWER_STATS_SIZE); private static final int MAX_LOW_POWER_STATS_SIZE = 4096; + @GuardedBy("mStats") + private int mLastPowerStateFromRadio = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW; + @GuardedBy("mStats") + private int mLastPowerStateFromWifi = DataConnectionRealTimeInfo.DC_POWER_STATE_LOW; + private final INetworkManagementEventObserver mActivityChangeObserver = + new BaseNetworkObserver() { + @Override + public void interfaceClassDataActivityChanged(int transportType, boolean active, + long tsNanos, int uid) { + final int powerState = active + ? DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH + : DataConnectionRealTimeInfo.DC_POWER_STATE_LOW; + final long timestampNanos; + if (tsNanos <= 0) { + timestampNanos = SystemClock.elapsedRealtimeNanos(); + } else { + timestampNanos = tsNanos; + } + + switch (transportType) { + case NetworkCapabilities.TRANSPORT_CELLULAR: + noteMobileRadioPowerState(powerState, timestampNanos, uid); + break; + case NetworkCapabilities.TRANSPORT_WIFI: + noteWifiRadioPowerState(powerState, timestampNanos, uid); + break; + default: + Slog.d(TAG, "Received unexpected transport in " + + "interfaceClassDataActivityChanged unexpected type: " + + transportType); + } + } + }; /** * Replaces the information in the given rpmStats with up-to-date information. */ @@ -203,6 +242,13 @@ public final class BatteryStatsService extends IBatteryStats.Stub } public void systemServicesReady() { + final INetworkManagementService nms = INetworkManagementService.Stub.asInterface( + ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE)); + try { + nms.registerObserver(mActivityChangeObserver); + } catch (RemoteException e) { + Slog.e(TAG, "Could not register INetworkManagement event observer " + e); + } mStats.systemServicesReady(mContext); } @@ -680,8 +726,13 @@ public final class BatteryStatsService extends IBatteryStats.Stub public void noteMobileRadioPowerState(int powerState, long timestampNs, int uid) { enforceCallingPermission(); + final boolean update; synchronized (mStats) { + // Ignore if no power state change. + if (mLastPowerStateFromRadio == powerState) return; + + mLastPowerStateFromRadio = powerState; update = mStats.noteMobileRadioPowerStateLocked(powerState, timestampNs, uid); } @@ -863,6 +914,10 @@ public final class BatteryStatsService extends IBatteryStats.Stub // There was a change in WiFi power state. // Collect data now for the past activity. synchronized (mStats) { + // Ignore if no power state change. + if (mLastPowerStateFromWifi == powerState) return; + + mLastPowerStateFromWifi = powerState; if (mStats.isOnBattery()) { final String type = (powerState == DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH || powerState == DataConnectionRealTimeInfo.DC_POWER_STATE_MEDIUM) ? "active" diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java index 88b0c3be5464..b6e632d42d8e 100644 --- a/services/core/java/com/android/server/am/ProcessList.java +++ b/services/core/java/com/android/server/am/ProcessList.java @@ -110,7 +110,6 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.ProcessMap; import com.android.internal.app.procstats.ProcessStats; -import com.android.internal.os.RuntimeInit; import com.android.internal.os.Zygote; import com.android.internal.util.ArrayUtils; import com.android.internal.util.FrameworkStatsLog; @@ -349,12 +348,23 @@ public final class ProcessList { private static final long NATIVE_HEAP_POINTER_TAGGING = 135754954; // This is a bug id. /** - * Enable memory tag checks in non-system apps. This flag will only have an effect on - * hardware supporting the ARM Memory Tagging Extension (MTE). + * Enable asynchronous (ASYNC) memory tag checking in this process. This + * flag will only have an effect on hardware supporting the ARM Memory + * Tagging Extension (MTE). */ @ChangeId @Disabled - private static final long NATIVE_MEMORY_TAGGING = 135772972; // This is a bug id. + private static final long NATIVE_MEMTAG_ASYNC = 135772972; // This is a bug id. + + /** + * Enable synchronous (SYNC) memory tag checking in this process. This flag + * will only have an effect on hardware supporting the ARM Memory Tagging + * Extension (MTE). If both NATIVE_MEMTAG_ASYNC and this option is selected, + * this option takes preference and MTE is enabled in SYNC mode. + */ + @ChangeId + @Disabled + private static final long NATIVE_MEMTAG_SYNC = 177438394; // This is a bug id. /** * Enable sampled memory bug detection in the app. @@ -1677,23 +1687,23 @@ public final class ProcessList { return gidArray; } - private boolean shouldEnableMemoryTagging(ProcessRecord app) { + // Returns the memory tagging level to be enabled. If memory tagging isn't + // requested, returns zero. + private int getMemtagLevel(ProcessRecord app) { // Ensure the hardware + kernel actually supports MTE. if (!Zygote.nativeSupportsMemoryTagging()) { - return false; + return 0; } - // Enable MTE for system apps if supported. - if ((app.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { - return true; + if (mPlatformCompat.isChangeEnabled(NATIVE_MEMTAG_SYNC, app.info)) { + return Zygote.MEMORY_TAG_LEVEL_SYNC; } - // Enable MTE if the compat feature is enabled. - if (mPlatformCompat.isChangeEnabled(NATIVE_MEMORY_TAGGING, app.info)) { - return true; + if (mPlatformCompat.isChangeEnabled(NATIVE_MEMTAG_ASYNC, app.info)) { + return Zygote.MEMORY_TAG_LEVEL_ASYNC; } - return false; + return 0; } private boolean shouldEnableTaggedPointers(ProcessRecord app) { @@ -1717,8 +1727,9 @@ public final class ProcessList { private int decideTaggingLevel(ProcessRecord app) { // Check MTE support first, as it should take precedence over TBI. - if (shouldEnableMemoryTagging(app)) { - return Zygote.MEMORY_TAG_LEVEL_ASYNC; + int memtagLevel = getMemtagLevel(app); + if (memtagLevel != 0) { + return memtagLevel; } if (shouldEnableTaggedPointers(app)) { diff --git a/services/core/java/com/android/server/compat/CompatConfig.java b/services/core/java/com/android/server/compat/CompatConfig.java index 9376e8dc16ea..69686a2e4678 100644 --- a/services/core/java/com/android/server/compat/CompatConfig.java +++ b/services/core/java/com/android/server/compat/CompatConfig.java @@ -21,7 +21,6 @@ import android.compat.Compatibility.ChangeConfig; import android.content.Context; import android.content.pm.ApplicationInfo; import android.os.Environment; -import android.os.RemoteException; import android.text.TextUtils; import android.util.LongArray; import android.util.LongSparseArray; @@ -53,7 +52,7 @@ import java.util.Set; import javax.xml.datatype.DatatypeConfigurationException; /** - * This class maintains state relating to platform compatibility changes. + * CompatConfig maintains state related to the platform compatibility changes. * * <p>It stores the default configuration for each change, and any per-package overrides that have * been configured. @@ -65,18 +64,38 @@ final class CompatConfig { @GuardedBy("mChanges") private final LongSparseArray<CompatChange> mChanges = new LongSparseArray<>(); - private OverrideValidatorImpl mOverrideValidator; + private final OverrideValidatorImpl mOverrideValidator; @VisibleForTesting CompatConfig(AndroidBuildClassifier androidBuildClassifier, Context context) { mOverrideValidator = new OverrideValidatorImpl(androidBuildClassifier, context, this); } + static CompatConfig create(AndroidBuildClassifier androidBuildClassifier, Context context) { + CompatConfig config = new CompatConfig(androidBuildClassifier, context); + config.initConfigFromLib(Environment.buildPath( + Environment.getRootDirectory(), "etc", "compatconfig")); + config.initConfigFromLib(Environment.buildPath( + Environment.getRootDirectory(), "system_ext", "etc", "compatconfig")); + + List<ApexManager.ActiveApexInfo> apexes = ApexManager.getInstance().getActiveApexInfos(); + for (ApexManager.ActiveApexInfo apex : apexes) { + config.initConfigFromLib(Environment.buildPath( + apex.apexDirectory, "etc", "compatconfig")); + } + config.invalidateCache(); + return config; + } + /** - * Add a change. This is intended to be used by code that reads change config from the - * filesystem. This should be done at system startup time. + * Adds a change. + * + * <p>This is intended to be used by code that reads change config from the filesystem. This + * should be done at system startup time. * - * @param change The change to add. Any change with the same ID will be overwritten. + * <p>Any change with the same ID will be overwritten. + * + * @param change the change to add */ void addChange(CompatChange change) { synchronized (mChanges) { @@ -86,13 +105,15 @@ final class CompatConfig { } /** - * Retrieves the set of disabled changes for a given app. Any change ID not in the returned - * array is by default enabled for the app. + * Retrieves the set of disabled changes for a given app. + * + * <p>Any change ID not in the returned array is by default enabled for the app. + * + * <p>We use a primitive array to minimize memory footprint: every app process will store this + * array statically so we aim to reduce overhead as much as possible. * - * @param app The app in question - * @return A sorted long array of change IDs. We use a primitive array to minimize memory - * footprint: Every app process will store this array statically so we aim to reduce - * overhead as much as possible. + * @param app the app in question + * @return a sorted long array of change IDs */ long[] getDisabledChanges(ApplicationInfo app) { LongArray disabled = new LongArray(); @@ -110,10 +131,10 @@ final class CompatConfig { } /** - * Look up a change ID by name. + * Looks up a change ID by name. * - * @param name Name of the change to look up - * @return The change ID, or {@code -1} if no change with that name exists. + * @param name name of the change to look up + * @return the change ID, or {@code -1} if no change with that name exists */ long lookupChangeId(String name) { synchronized (mChanges) { @@ -127,10 +148,10 @@ final class CompatConfig { } /** - * Find if a given change is enabled for a given application. + * Checks if a given change is enabled for a given application. * - * @param changeId The ID of the change in question - * @param app App to check for + * @param changeId the ID of the change in question + * @param app app to check for * @return {@code true} if the change is enabled for this app. Also returns {@code true} if the * change ID is not known, as unknown changes are enabled by default. */ @@ -146,10 +167,10 @@ final class CompatConfig { } /** - * Find if a given change will be enabled for a given package name, prior to installation. + * Checks if a given change will be enabled for a given package name after the installation. * - * @param changeId The ID of the change in question - * @param packageName Package name to check for + * @param changeId the ID of the change in question + * @param packageName package name to check for * @return {@code true} if the change would be enabled for this package name. Also returns * {@code true} if the change ID is not known, as unknown changes are enabled by default. */ @@ -165,22 +186,22 @@ final class CompatConfig { } /** - * Overrides the enabled state for a given change and app. This method is intended to be used - * *only* for debugging purposes, ultimately invoked either by an adb command, or from some - * developer settings UI. + * Overrides the enabled state for a given change and app. + * + * <p>This method is intended to be used *only* for debugging purposes, ultimately invoked + * either by an adb command, or from some developer settings UI. * - * <p>Note, package overrides are not persistent and will be lost on system or runtime restart. + * <p>Note: package overrides are not persistent and will be lost on system or runtime restart. * - * @param changeId The ID of the change to be overridden. Note, this call will succeed even - * if - * this change is not known; it will only have any effect if any code in the - * platform is gated on the ID given. - * @param packageName The app package name to override the change for. - * @param enabled If the change should be enabled or disabled. - * @return {@code true} if the change existed before adding the override. + * @param changeId the ID of the change to be overridden. Note, this call will succeed even + * if this change is not known; it will only have any effect if any code in + * the platform is gated on the ID given. + * @param packageName the app package name to override the change for + * @param enabled if the change should be enabled or disabled + * @return {@code true} if the change existed before adding the override + * @throws IllegalStateException if overriding is not allowed */ - boolean addOverride(long changeId, String packageName, boolean enabled) - throws SecurityException { + boolean addOverride(long changeId, String packageName, boolean enabled) { boolean alreadyKnown = true; OverrideAllowedState allowedState = mOverrideValidator.getOverrideAllowedState(changeId, packageName); @@ -201,18 +222,14 @@ final class CompatConfig { break; default: throw new IllegalStateException("Should only be able to override changes that " - + "are allowed or can be deferred."); + + "are allowed or can be deferred."); } invalidateCache(); } return alreadyKnown; } - /** - * Check whether the change is known to the compat config. - * - * @return {@code true} if the change is known. - */ + /** Checks whether the change is known to the compat config. */ boolean isKnownChangeId(long changeId) { synchronized (mChanges) { CompatChange c = mChanges.get(changeId); @@ -221,16 +238,13 @@ final class CompatConfig { } /** - * Returns the maximum sdk version for which this change can be opted in (or -1 if it is not - * target sdk gated). + * Returns the maximum SDK version for which this change can be opted in (or -1 if it is not + * target SDK gated). */ int maxTargetSdkForChangeIdOptIn(long changeId) { synchronized (mChanges) { CompatChange c = mChanges.get(changeId); - if (c == null) { - return -1; - } - if (c.getEnableSinceTargetSdk() != -1) { + if (c != null && c.getEnableSinceTargetSdk() != -1) { return c.getEnableSinceTargetSdk() - 1; } return -1; @@ -243,10 +257,7 @@ final class CompatConfig { boolean isLoggingOnly(long changeId) { synchronized (mChanges) { CompatChange c = mChanges.get(changeId); - if (c == null) { - return false; - } - return c.getLoggingOnly(); + return c != null && c.getLoggingOnly(); } } @@ -256,24 +267,21 @@ final class CompatConfig { boolean isDisabled(long changeId) { synchronized (mChanges) { CompatChange c = mChanges.get(changeId); - if (c == null) { - return false; - } - return c.getDisabled(); + return c != null && c.getDisabled(); } } /** - * Removes an override previously added via {@link #addOverride(long, String, boolean)}. This - * restores the default behaviour for the given change and app, once any app processes have been - * restarted. + * Removes an override previously added via {@link #addOverride(long, String, boolean)}. + * + * <p>This restores the default behaviour for the given change and app, once any app processes + * have been restarted. * - * @param changeId The ID of the change that was overridden. - * @param packageName The app package name that was overridden. + * @param changeId the ID of the change that was overridden + * @param packageName the app package name that was overridden * @return {@code true} if an override existed; */ - boolean removeOverride(long changeId, String packageName) - throws SecurityException { + boolean removeOverride(long changeId, String packageName) { boolean overrideExists = false; synchronized (mChanges) { CompatChange c = mChanges.get(changeId); @@ -299,13 +307,12 @@ final class CompatConfig { /** * Overrides the enabled state for a given change and app. * - * <p>Note, package overrides are not persistent and will be lost on system or runtime restart. + * <p>Note: package overrides are not persistent and will be lost on system or runtime restart. * - * @param overrides list of overrides to default changes config. - * @param packageName app for which the overrides will be applied. + * @param overrides list of overrides to default changes config + * @param packageName app for which the overrides will be applied */ - void addOverrides(CompatibilityChangeConfig overrides, String packageName) - throws RemoteException, SecurityException { + void addOverrides(CompatibilityChangeConfig overrides, String packageName) { synchronized (mChanges) { for (Long changeId : overrides.enabledChanges()) { addOverride(changeId, packageName, true); @@ -324,9 +331,9 @@ final class CompatConfig { * * <p>This restores the default behaviour for the given app. * - * @param packageName The package for which the overrides should be purged. + * @param packageName the package for which the overrides should be purged */ - void removePackageOverrides(String packageName) throws SecurityException { + void removePackageOverrides(String packageName) { synchronized (mChanges) { for (int i = 0; i < mChanges.size(); ++i) { CompatChange change = mChanges.valueAt(i); @@ -337,8 +344,7 @@ final class CompatConfig { } private long[] getAllowedChangesSinceTargetSdkForPackage(String packageName, - int targetSdkVersion) - throws RemoteException { + int targetSdkVersion) { LongArray allowed = new LongArray(); synchronized (mChanges) { for (int i = 0; i < mChanges.size(); ++i) { @@ -348,7 +354,7 @@ final class CompatConfig { } OverrideAllowedState allowedState = mOverrideValidator.getOverrideAllowedState(change.getId(), - packageName); + packageName); if (allowedState.state == OverrideAllowedState.ALLOWED) { allowed.add(change.getId()); } @@ -361,10 +367,9 @@ final class CompatConfig { * Enables all changes with enabledSinceTargetSdk == {@param targetSdkVersion} for * {@param packageName}. * - * @return The number of changes that were toggled. + * @return the number of changes that were toggled */ - int enableTargetSdkChangesForPackage(String packageName, int targetSdkVersion) - throws RemoteException { + int enableTargetSdkChangesForPackage(String packageName, int targetSdkVersion) { long[] changes = getAllowedChangesSinceTargetSdkForPackage(packageName, targetSdkVersion); for (long changeId : changes) { addOverride(changeId, packageName, true); @@ -372,15 +377,13 @@ final class CompatConfig { return changes.length; } - /** * Disables all changes with enabledSinceTargetSdk == {@param targetSdkVersion} for * {@param packageName}. * - * @return The number of changes that were toggled. + * @return the number of changes that were toggled */ - int disableTargetSdkChangesForPackage(String packageName, int targetSdkVersion) - throws RemoteException { + int disableTargetSdkChangesForPackage(String packageName, int targetSdkVersion) { long[] changes = getAllowedChangesSinceTargetSdkForPackage(packageName, targetSdkVersion); for (long changeId : changes) { addOverride(changeId, packageName, false); @@ -425,7 +428,7 @@ final class CompatConfig { /** * Dumps the current list of compatibility config information. * - * @param pw The {@link PrintWriter} instance to which the information will be dumped. + * @param pw {@link PrintWriter} instance to which the information will be dumped */ void dumpConfig(PrintWriter pw) { synchronized (mChanges) { @@ -441,13 +444,10 @@ final class CompatConfig { } /** - * Get the config for a given app. + * Returns config for a given app. * - * @param applicationInfo the {@link ApplicationInfo} for which the info should be dumped. - * @return A {@link CompatibilityChangeConfig} which contains the compat config info for the - * given app. + * @param applicationInfo the {@link ApplicationInfo} for which the info should be dumped */ - CompatibilityChangeConfig getAppConfig(ApplicationInfo applicationInfo) { Set<Long> enabled = new HashSet<>(); Set<Long> disabled = new HashSet<>(); @@ -467,7 +467,7 @@ final class CompatConfig { /** * Dumps all the compatibility change information. * - * @return An array of {@link CompatibilityChangeInfo} with the current changes. + * @return an array of {@link CompatibilityChangeInfo} with the current changes */ CompatibilityChangeInfo[] dumpChanges() { synchronized (mChanges) { @@ -480,22 +480,6 @@ final class CompatConfig { } } - static CompatConfig create(AndroidBuildClassifier androidBuildClassifier, Context context) { - CompatConfig config = new CompatConfig(androidBuildClassifier, context); - config.initConfigFromLib(Environment.buildPath( - Environment.getRootDirectory(), "etc", "compatconfig")); - config.initConfigFromLib(Environment.buildPath( - Environment.getRootDirectory(), "system_ext", "etc", "compatconfig")); - - List<ApexManager.ActiveApexInfo> apexes = ApexManager.getInstance().getActiveApexInfos(); - for (ApexManager.ActiveApexInfo apex : apexes) { - config.initConfigFromLib(Environment.buildPath( - apex.apexDirectory, "etc", "compatconfig")); - } - config.invalidateCache(); - return config; - } - void initConfigFromLib(File libraryDir) { if (!libraryDir.exists() || !libraryDir.isDirectory()) { Slog.d(TAG, "No directory " + libraryDir + ", skipping"); @@ -526,6 +510,7 @@ final class CompatConfig { private void invalidateCache() { ChangeIdStateCache.invalidate(); } + /** * Rechecks all the existing overrides for a package. */ diff --git a/services/core/java/com/android/server/compat/PlatformCompat.java b/services/core/java/com/android/server/compat/PlatformCompat.java index 1ea468c341d2..6b2a1c950e38 100644 --- a/services/core/java/com/android/server/compat/PlatformCompat.java +++ b/services/core/java/com/android/server/compat/PlatformCompat.java @@ -63,45 +63,43 @@ public class PlatformCompat extends IPlatformCompat.Stub { private final ChangeReporter mChangeReporter; private final CompatConfig mCompatConfig; - private static int sMinTargetSdk = Build.VERSION_CODES.Q; - public PlatformCompat(Context context) { mContext = context; - mChangeReporter = new ChangeReporter( - ChangeReporter.SOURCE_SYSTEM_SERVER); + mChangeReporter = new ChangeReporter(ChangeReporter.SOURCE_SYSTEM_SERVER); mCompatConfig = CompatConfig.create(new AndroidBuildClassifier(), mContext); } @VisibleForTesting PlatformCompat(Context context, CompatConfig compatConfig) { mContext = context; - mChangeReporter = new ChangeReporter( - ChangeReporter.SOURCE_SYSTEM_SERVER); + mChangeReporter = new ChangeReporter(ChangeReporter.SOURCE_SYSTEM_SERVER); mCompatConfig = compatConfig; + registerPackageReceiver(context); } @Override public void reportChange(long changeId, ApplicationInfo appInfo) { - checkCompatChangeLogPermission(); - reportChange(changeId, appInfo.uid, - ChangeReporter.STATE_LOGGED); + reportChangeByUid(changeId, appInfo.uid); } @Override - public void reportChangeByPackageName(long changeId, String packageName, int userId) { - checkCompatChangeLogPermission(); + public void reportChangeByPackageName(long changeId, String packageName, + @UserIdInt int userId) { ApplicationInfo appInfo = getApplicationInfo(packageName, userId); - if (appInfo == null) { - return; + if (appInfo != null) { + reportChangeByUid(changeId, appInfo.uid); } - reportChange(changeId, appInfo); } @Override public void reportChangeByUid(long changeId, int uid) { checkCompatChangeLogPermission(); - reportChange(changeId, uid, ChangeReporter.STATE_LOGGED); + reportChangeInternal(changeId, uid, ChangeReporter.STATE_LOGGED); + } + + private void reportChangeInternal(long changeId, int uid, int state) { + mChangeReporter.reportChange(uid, changeId, state); } @Override @@ -110,28 +108,6 @@ public class PlatformCompat extends IPlatformCompat.Stub { return isChangeEnabledInternal(changeId, appInfo); } - /** - * Internal version of the above method, without logging. Does not perform costly permission - * check. - * TODO(b/167551701): Remove this method and add 'loggability' as a changeid property. - */ - public boolean isChangeEnabledInternalNoLogging(long changeId, ApplicationInfo appInfo) { - return mCompatConfig.isChangeEnabled(changeId, appInfo); - } - - /** - * Internal version of {@link #isChangeEnabled(long, ApplicationInfo)}. Does not perform costly - * permission check. - */ - public boolean isChangeEnabledInternal(long changeId, ApplicationInfo appInfo) { - boolean enabled = isChangeEnabledInternalNoLogging(changeId, appInfo); - if (appInfo != null) { - reportChange(changeId, appInfo.uid, - enabled ? ChangeReporter.STATE_ENABLED : ChangeReporter.STATE_DISABLED); - } - return enabled; - } - @Override public boolean isChangeEnabledByPackageName(long changeId, String packageName, @UserIdInt int userId) { @@ -140,7 +116,7 @@ public class PlatformCompat extends IPlatformCompat.Stub { if (appInfo == null) { return mCompatConfig.willChangeBeEnabled(changeId, packageName); } - return isChangeEnabled(changeId, appInfo); + return isChangeEnabledInternal(changeId, appInfo); } @Override @@ -152,81 +128,82 @@ public class PlatformCompat extends IPlatformCompat.Stub { } boolean enabled = true; for (String packageName : packages) { - enabled = enabled && isChangeEnabledByPackageName(changeId, packageName, + enabled &= isChangeEnabledByPackageName(changeId, packageName, UserHandle.getUserId(uid)); } return enabled; } /** - * Register a listener for change state overrides. Only one listener per change is allowed. + * Internal version of the above method, without logging. * - * <p>{@code listener.onCompatChange(String)} method is guaranteed to be called with - * packageName before the app is killed upon an override change. The state of a change is not - * guaranteed to change when {@code listener.onCompatChange(String)} is called. + * <p>Does not perform costly permission check. + * TODO(b/167551701): Remove this method and add 'loggability' as a changeid property. + */ + public boolean isChangeEnabledInternalNoLogging(long changeId, ApplicationInfo appInfo) { + return mCompatConfig.isChangeEnabled(changeId, appInfo); + } + + /** + * Internal version of {@link #isChangeEnabled(long, ApplicationInfo)}. * - * @param changeId to get updates for - * @param listener the listener that will be called upon a potential change for package. - * @throws IllegalStateException if a listener was already registered for changeId - * @returns {@code true} if a change with changeId was already known, or (@code false} - * otherwise. + * <p>Does not perform costly permission check. */ - public boolean registerListener(long changeId, CompatChange.ChangeListener listener) { - return mCompatConfig.registerListener(changeId, listener); + public boolean isChangeEnabledInternal(long changeId, ApplicationInfo appInfo) { + boolean enabled = isChangeEnabledInternalNoLogging(changeId, appInfo); + if (appInfo != null) { + reportChangeInternal(changeId, appInfo.uid, + enabled ? ChangeReporter.STATE_ENABLED : ChangeReporter.STATE_DISABLED); + } + return enabled; } @Override - public void setOverrides(CompatibilityChangeConfig overrides, String packageName) - throws RemoteException, SecurityException { + public void setOverrides(CompatibilityChangeConfig overrides, String packageName) { checkCompatChangeOverridePermission(); mCompatConfig.addOverrides(overrides, packageName); killPackage(packageName); } @Override - public void setOverridesForTest(CompatibilityChangeConfig overrides, String packageName) - throws RemoteException, SecurityException { + public void setOverridesForTest(CompatibilityChangeConfig overrides, String packageName) { checkCompatChangeOverridePermission(); mCompatConfig.addOverrides(overrides, packageName); } @Override - public int enableTargetSdkChanges(String packageName, int targetSdkVersion) - throws RemoteException, SecurityException { + public int enableTargetSdkChanges(String packageName, int targetSdkVersion) { checkCompatChangeOverridePermission(); - int numChanges = mCompatConfig.enableTargetSdkChangesForPackage(packageName, - targetSdkVersion); + int numChanges = + mCompatConfig.enableTargetSdkChangesForPackage(packageName, targetSdkVersion); killPackage(packageName); return numChanges; } @Override - public int disableTargetSdkChanges(String packageName, int targetSdkVersion) - throws RemoteException, SecurityException { + public int disableTargetSdkChanges(String packageName, int targetSdkVersion) { checkCompatChangeOverridePermission(); - int numChanges = mCompatConfig.disableTargetSdkChangesForPackage(packageName, - targetSdkVersion); + int numChanges = + mCompatConfig.disableTargetSdkChangesForPackage(packageName, targetSdkVersion); killPackage(packageName); return numChanges; } @Override - public void clearOverrides(String packageName) throws RemoteException, SecurityException { + public void clearOverrides(String packageName) { checkCompatChangeOverridePermission(); mCompatConfig.removePackageOverrides(packageName); killPackage(packageName); } @Override - public void clearOverridesForTest(String packageName) - throws RemoteException, SecurityException { + public void clearOverridesForTest(String packageName) { checkCompatChangeOverridePermission(); mCompatConfig.removePackageOverrides(packageName); } @Override - public boolean clearOverride(long changeId, String packageName) - throws RemoteException, SecurityException { + public boolean clearOverride(long changeId, String packageName) { checkCompatChangeOverridePermission(); boolean existed = mCompatConfig.removeOverride(changeId, packageName); killPackage(packageName); @@ -234,6 +211,12 @@ public class PlatformCompat extends IPlatformCompat.Stub { } @Override + public void clearOverrideForTest(long changeId, String packageName) { + checkCompatChangeOverridePermission(); + mCompatConfig.removeOverride(changeId, packageName); + } + + @Override public CompatibilityChangeConfig getAppConfig(ApplicationInfo appInfo) { checkCompatChangeReadAndLogPermission(); return mCompatConfig.getAppConfig(appInfo); @@ -247,18 +230,13 @@ public class PlatformCompat extends IPlatformCompat.Stub { @Override public CompatibilityChangeInfo[] listUIChanges() { - return Arrays.stream(listAllChanges()).filter( - x -> isShownInUI(x)).toArray(CompatibilityChangeInfo[]::new); + return Arrays.stream(listAllChanges()).filter(this::isShownInUI).toArray( + CompatibilityChangeInfo[]::new); } - /** - * Check whether the change is known to the compat config. - * - * @return {@code true} if the change is known. - */ + /** Checks whether the change is known to the compat config. */ public boolean isKnownChangeId(long changeId) { return mCompatConfig.isKnownChangeId(changeId); - } /** @@ -286,7 +264,9 @@ public class PlatformCompat extends IPlatformCompat.Stub { @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, "platform_compat", pw)) return; + if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, "platform_compat", pw)) { + return; + } checkCompatChangeReadAndLogPermission(); mCompatConfig.dumpConfig(pw); } @@ -298,7 +278,8 @@ public class PlatformCompat extends IPlatformCompat.Stub { /** * Clears information stored about events reported on behalf of an app. - * To be called once upon app start or end. A second call would be a no-op. + * + * <p>To be called once upon app start or end. A second call would be a no-op. * * @param appInfo the app to reset */ @@ -311,13 +292,9 @@ public class PlatformCompat extends IPlatformCompat.Stub { packageName, 0, userId, userId); } - private void reportChange(long changeId, int uid, int state) { - mChangeReporter.reportChange(uid, changeId, state); - } - private void killPackage(String packageName) { int uid = LocalServices.getService(PackageManagerInternal.class).getPackageUid(packageName, - 0, UserHandle.myUserId()); + 0, UserHandle.myUserId()); if (uid < 0) { Slog.w(TAG, "Didn't find package " + packageName + " on device."); @@ -325,21 +302,18 @@ public class PlatformCompat extends IPlatformCompat.Stub { } Slog.d(TAG, "Killing package " + packageName + " (UID " + uid + ")."); - killUid(UserHandle.getAppId(uid), - UserHandle.USER_ALL, "PlatformCompat overrides"); + killUid(UserHandle.getAppId(uid)); } - private void killUid(int appId, int userId, String reason) { + private void killUid(int appId) { final long identity = Binder.clearCallingIdentity(); try { IActivityManager am = ActivityManager.getService(); if (am != null) { - try { - am.killUid(appId, userId, reason); - } catch (RemoteException e) { - /* ignore - same process */ - } + am.killUid(appId, UserHandle.USER_ALL, "PlatformCompat overrides"); } + } catch (RemoteException e) { + /* ignore - same process */ } finally { Binder.restoreCallingIdentity(identity); } @@ -350,13 +324,12 @@ public class PlatformCompat extends IPlatformCompat.Stub { if (Binder.getCallingUid() == SYSTEM_UID) { return; } - if (mContext.checkCallingOrSelfPermission(LOG_COMPAT_CHANGE) - != PERMISSION_GRANTED) { + if (mContext.checkCallingOrSelfPermission(LOG_COMPAT_CHANGE) != PERMISSION_GRANTED) { throw new SecurityException("Cannot log compat change usage"); } } - private void checkCompatChangeReadPermission() throws SecurityException { + private void checkCompatChangeReadPermission() { // Don't check for permissions within the system process if (Binder.getCallingUid() == SYSTEM_UID) { return; @@ -367,7 +340,7 @@ public class PlatformCompat extends IPlatformCompat.Stub { } } - private void checkCompatChangeOverridePermission() throws SecurityException { + private void checkCompatChangeOverridePermission() { // Don't check for permissions within the system process if (Binder.getCallingUid() == SYSTEM_UID) { return; @@ -378,7 +351,7 @@ public class PlatformCompat extends IPlatformCompat.Stub { } } - private void checkCompatChangeReadAndLogPermission() throws SecurityException { + private void checkCompatChangeReadAndLogPermission() { checkCompatChangeReadPermission(); checkCompatChangeLogPermission(); } @@ -391,16 +364,34 @@ public class PlatformCompat extends IPlatformCompat.Stub { return false; } if (change.getEnableSinceTargetSdk() > 0) { - if (change.getEnableSinceTargetSdk() < sMinTargetSdk) { - return false; - } + return change.getEnableSinceTargetSdk() >= Build.VERSION_CODES.Q; } return true; } /** + * Registers a listener for change state overrides. + * + * <p>Only one listener per change is allowed. + * + * <p>{@code listener.onCompatChange(String)} method is guaranteed to be called with + * packageName before the app is killed upon an override change. The state of a change is not + * guaranteed to change when {@code listener.onCompatChange(String)} is called. + * + * @param changeId to get updates for + * @param listener the listener that will be called upon a potential change for package + * @return {@code true} if a change with changeId was already known, or (@code false} + * otherwise + * @throws IllegalStateException if a listener was already registered for changeId + */ + public boolean registerListener(long changeId, CompatChange.ChangeListener listener) { + return mCompatConfig.registerListener(changeId, listener); + } + + /** * Registers a broadcast receiver that listens for package install, replace or remove. - * @param context the context where the receiver should be registered. + * + * @param context the context where the receiver should be registered */ public void registerPackageReceiver(Context context) { final BroadcastReceiver receiver = new BroadcastReceiver() { @@ -429,8 +420,8 @@ public class PlatformCompat extends IPlatformCompat.Stub { } /** - * Register the observer for - * {@link android.provider.Settings.Global#FORCE_NON_DEBUGGABLE_FINAL_BUILD_FOR_COMPAT} + * Registers the observer for + * {@link android.provider.Settings.Global#FORCE_NON_DEBUGGABLE_FINAL_BUILD_FOR_COMPAT}. */ public void registerContentObserver() { mCompatConfig.registerContentObserver(); diff --git a/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java b/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java index 1024556c17eb..26244e62696b 100644 --- a/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java +++ b/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java @@ -368,6 +368,7 @@ final public class IpConnectivityMetrics extends SystemService { @Override public void logDefaultNetworkValidity(boolean valid) { + NetworkStack.checkNetworkStackPermission(getContext()); mDefaultNetworkMetrics.logDefaultNetworkValidity(SystemClock.elapsedRealtime(), valid); } @@ -375,6 +376,7 @@ final public class IpConnectivityMetrics extends SystemService { public void logDefaultNetworkEvent(Network defaultNetwork, int score, boolean validated, LinkProperties lp, NetworkCapabilities nc, Network previousDefaultNetwork, int previousScore, LinkProperties previousLp, NetworkCapabilities previousNc) { + NetworkStack.checkNetworkStackPermission(getContext()); final long timeMs = SystemClock.elapsedRealtime(); mDefaultNetworkMetrics.logDefaultNetworkEvent(timeMs, defaultNetwork, score, validated, lp, nc, previousDefaultNetwork, previousScore, previousLp, previousNc); diff --git a/services/core/java/com/android/server/connectivity/Nat464Xlat.java b/services/core/java/com/android/server/connectivity/Nat464Xlat.java index c1b1b6a2f26c..952193b77681 100644 --- a/services/core/java/com/android/server/connectivity/Nat464Xlat.java +++ b/services/core/java/com/android/server/connectivity/Nat464Xlat.java @@ -246,11 +246,6 @@ public class Nat464Xlat extends BaseNetworkObserver { return; } - if (mNetwork.linkProperties == null) { - Log.e(TAG, "startClat: Can't start clat with null LinkProperties"); - return; - } - String baseIface = mNetwork.linkProperties.getInterfaceName(); if (baseIface == null) { Log.e(TAG, "startClat: Can't start clat on null interface"); diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java index b0a73f105725..e3663baaf9f7 100644 --- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java +++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java @@ -37,7 +37,6 @@ import android.net.NetworkMonitorManager; import android.net.NetworkRequest; import android.net.NetworkState; import android.net.TcpKeepalivePacketData; -import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.INetworkManagementService; @@ -53,7 +52,6 @@ import com.android.internal.util.WakeupMessage; import com.android.server.ConnectivityService; import java.io.PrintWriter; -import java.util.ArrayList; import java.util.List; import java.util.NoSuchElementException; import java.util.Objects; @@ -136,12 +134,12 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { // This Network object should always be used if possible, so as to encourage reuse of the // enclosed socket factory and connection pool. Avoid creating other Network objects. // This Network object is always valid. - public final Network network; - public LinkProperties linkProperties; + @NonNull public final Network network; + @NonNull public LinkProperties linkProperties; // This should only be modified by ConnectivityService, via setNetworkCapabilities(). // TODO: make this private with a getter. - public NetworkCapabilities networkCapabilities; - public final NetworkAgentConfig networkAgentConfig; + @NonNull public NetworkCapabilities networkCapabilities; + @NonNull public final NetworkAgentConfig networkAgentConfig; // Underlying networks declared by the agent. Only set if supportsUnderlyingNetworks is true. // The networks in this list might be declared by a VPN app using setUnderlyingNetworks and are @@ -329,6 +327,12 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { Handler handler, NetworkAgentConfig config, ConnectivityService connService, INetd netd, IDnsResolver dnsResolver, INetworkManagementService nms, int factorySerialNumber, int creatorUid) { + Objects.requireNonNull(net); + Objects.requireNonNull(info); + Objects.requireNonNull(lp); + Objects.requireNonNull(nc); + Objects.requireNonNull(context); + Objects.requireNonNull(config); networkAgent = na; network = net; networkInfo = info; @@ -536,19 +540,22 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { } @Override - public void sendNetworkCapabilities(NetworkCapabilities nc) { + public void sendNetworkCapabilities(@NonNull NetworkCapabilities nc) { + Objects.requireNonNull(nc); mHandler.obtainMessage(NetworkAgent.EVENT_NETWORK_CAPABILITIES_CHANGED, new Pair<>(NetworkAgentInfo.this, nc)).sendToTarget(); } @Override - public void sendLinkProperties(LinkProperties lp) { + public void sendLinkProperties(@NonNull LinkProperties lp) { + Objects.requireNonNull(lp); mHandler.obtainMessage(NetworkAgent.EVENT_NETWORK_PROPERTIES_CHANGED, new Pair<>(NetworkAgentInfo.this, lp)).sendToTarget(); } @Override - public void sendNetworkInfo(NetworkInfo info) { + public void sendNetworkInfo(@NonNull NetworkInfo info) { + Objects.requireNonNull(info); mHandler.obtainMessage(NetworkAgent.EVENT_NETWORK_INFO_CHANGED, new Pair<>(NetworkAgentInfo.this, info)).sendToTarget(); } @@ -574,16 +581,8 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { @Override public void sendUnderlyingNetworks(@Nullable List<Network> networks) { - final Bundle args = new Bundle(); - if (networks instanceof ArrayList<?>) { - args.putParcelableArrayList(NetworkAgent.UNDERLYING_NETWORKS_KEY, - (ArrayList<Network>) networks); - } else { - args.putParcelableArrayList(NetworkAgent.UNDERLYING_NETWORKS_KEY, - networks == null ? null : new ArrayList<>(networks)); - } mHandler.obtainMessage(NetworkAgent.EVENT_UNDERLYING_NETWORKS_CHANGED, - new Pair<>(NetworkAgentInfo.this, args)).sendToTarget(); + new Pair<>(NetworkAgentInfo.this, networks)).sendToTarget(); } } @@ -603,7 +602,7 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { * * @return the old capabilities of this network. */ - public synchronized NetworkCapabilities getAndSetNetworkCapabilities( + @NonNull public synchronized NetworkCapabilities getAndSetNetworkCapabilities( @NonNull final NetworkCapabilities nc) { final NetworkCapabilities oldNc = networkCapabilities; networkCapabilities = nc; diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java index a65f8097121d..fb1e8197ccff 100644 --- a/services/core/java/com/android/server/connectivity/Vpn.java +++ b/services/core/java/com/android/server/connectivity/Vpn.java @@ -439,6 +439,11 @@ public class Vpn { mEnableTeardown = enableTeardown; } + @VisibleForTesting + public boolean getEnableTeardown() { + return mEnableTeardown; + } + /** * Update current state, dispatching event to listeners. */ @@ -2146,6 +2151,11 @@ public class Vpn { // Start a new LegacyVpnRunner and we are done! mVpnRunner = new LegacyVpnRunner(config, racoon, mtpd, profile); + startLegacyVpnRunner(); + } + + @VisibleForTesting + protected void startLegacyVpnRunner() { mVpnRunner.start(); } diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java index d003b89e8877..c005af4e9696 100644 --- a/services/core/java/com/android/server/locksettings/LockSettingsService.java +++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java @@ -89,6 +89,7 @@ import android.os.storage.StorageManager; import android.provider.Settings; import android.provider.Settings.Secure; import android.provider.Settings.SettingNotFoundException; +import android.security.Authorization; import android.security.KeyStore; import android.security.keystore.AndroidKeyStoreProvider; import android.security.keystore.KeyProperties; @@ -1272,6 +1273,7 @@ public class LockSettingsService extends ILockSettings.Stub { private void unlockKeystore(byte[] password, int userHandle) { if (DEBUG) Slog.v(TAG, "Unlock keystore for user: " + userHandle); + new Authorization().onLockScreenEvent(false, userHandle, password); // TODO(b/120484642): Update keystore to accept byte[] passwords String passwordString = password == null ? null : new String(password); final KeyStore ks = KeyStore.getInstance(); diff --git a/services/core/java/com/android/server/media/MediaRoute2Provider.java b/services/core/java/com/android/server/media/MediaRoute2Provider.java index f882c57e49ba..edc9d7c64146 100644 --- a/services/core/java/com/android/server/media/MediaRoute2Provider.java +++ b/services/core/java/com/android/server/media/MediaRoute2Provider.java @@ -77,7 +77,7 @@ abstract class MediaRoute2Provider { @NonNull public List<RoutingSessionInfo> getSessionInfos() { synchronized (mLock) { - return mSessionInfos; + return new ArrayList<>(mSessionInfos); } } diff --git a/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java b/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java index 85af346aa88a..ab38dca2387d 100644 --- a/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java +++ b/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java @@ -108,8 +108,8 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider mLastDiscoveryPreference = discoveryPreference; if (mConnectionReady) { mActiveConnection.updateDiscoveryPreference(discoveryPreference); - updateBinding(); } + updateBinding(); } @Override @@ -205,9 +205,11 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider } private boolean shouldBind() { - //TODO: Binding could be delayed until it's necessary. if (mRunning) { - return true; + // Bind when there is a discovery preference or an active route session. + return (mLastDiscoveryPreference != null + && !mLastDiscoveryPreference.getPreferredFeatures().isEmpty()) + || !getSessionInfos().isEmpty(); } return false; } diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java index 1114fe0d9bf8..31edf43679e9 100644 --- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java +++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java @@ -16,6 +16,7 @@ package com.android.server.media; +import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND; import static android.media.MediaRoute2ProviderService.REASON_UNKNOWN_ERROR; import static android.media.MediaRouter2Utils.getOriginalId; import static android.media.MediaRouter2Utils.getProviderId; @@ -73,10 +74,12 @@ class MediaRouter2ServiceImpl { // TODO: (In Android S or later) if we add callback methods for generic failures // in MediaRouter2, remove this constant and replace the usages with the real request IDs. private static final long DUMMY_REQUEST_ID = -1; + private static final int PACKAGE_IMPORTANCE_FOR_DISCOVERY = IMPORTANCE_FOREGROUND; private final Context mContext; private final Object mLock = new Object(); final AtomicInteger mNextRouterOrManagerId = new AtomicInteger(1); + final ActivityManager mActivityManager; @GuardedBy("mLock") private final SparseArray<UserRecord> mUserRecords = new SparseArray<>(); @@ -87,8 +90,21 @@ class MediaRouter2ServiceImpl { @GuardedBy("mLock") private int mCurrentUserId = -1; + private final ActivityManager.OnUidImportanceListener mOnUidImportanceListener = + (uid, importance) -> { + synchronized (mLock) { + final int count = mUserRecords.size(); + for (int i = 0; i < count; i++) { + mUserRecords.valueAt(i).mHandler.maybeUpdateDiscoveryPreferenceForUid(uid); + } + } + }; + MediaRouter2ServiceImpl(Context context) { mContext = context; + mActivityManager = mContext.getSystemService(ActivityManager.class); + mActivityManager.addOnUidImportanceListener(mOnUidImportanceListener, + PACKAGE_IMPORTANCE_FOR_DISCOVERY); } //////////////////////////////////////////////////////////////// @@ -388,6 +404,30 @@ class MediaRouter2ServiceImpl { } } + public void startScan(IMediaRouter2Manager manager) { + Objects.requireNonNull(manager, "manager must not be null"); + final long token = Binder.clearCallingIdentity(); + try { + synchronized (mLock) { + startScanLocked(manager); + } + } finally { + Binder.restoreCallingIdentity(token); + } + } + + public void stopScan(IMediaRouter2Manager manager) { + Objects.requireNonNull(manager, "manager must not be null"); + final long token = Binder.clearCallingIdentity(); + try { + synchronized (mLock) { + stopScanLocked(manager); + } + } finally { + Binder.restoreCallingIdentity(token); + } + } + public void setRouteVolumeWithManager(IMediaRouter2Manager manager, int requestId, MediaRoute2Info route, int volume) { Objects.requireNonNull(manager, "manager must not be null"); @@ -839,6 +879,24 @@ class MediaRouter2ServiceImpl { disposeUserIfNeededLocked(userRecord); // since manager removed from user } + private void startScanLocked(@NonNull IMediaRouter2Manager manager) { + final IBinder binder = manager.asBinder(); + ManagerRecord managerRecord = mAllManagerRecords.get(binder); + if (managerRecord == null) { + return; + } + managerRecord.startScan(); + } + + private void stopScanLocked(@NonNull IMediaRouter2Manager manager) { + final IBinder binder = manager.asBinder(); + ManagerRecord managerRecord = mAllManagerRecords.get(binder); + if (managerRecord == null) { + return; + } + managerRecord.stopScan(); + } + private void setRouteVolumeWithManagerLocked(int requestId, @NonNull IMediaRouter2Manager manager, @NonNull MediaRoute2Info route, int volume) { @@ -1122,6 +1180,7 @@ class MediaRouter2ServiceImpl { public final String mPackageName; public final int mManagerId; public SessionCreationRequest mLastSessionCreationRequest; + public boolean mIsScanning; ManagerRecord(UserRecord userRecord, IMediaRouter2Manager manager, int uid, int pid, String packageName) { @@ -1146,6 +1205,24 @@ class MediaRouter2ServiceImpl { pw.println(prefix + this); } + public void startScan() { + if (mIsScanning) { + return; + } + mIsScanning = true; + mUserRecord.mHandler.sendMessage(PooledLambda.obtainMessage( + UserHandler::updateDiscoveryPreferenceOnHandler, mUserRecord.mHandler)); + } + + public void stopScan() { + if (!mIsScanning) { + return; + } + mIsScanning = false; + mUserRecord.mHandler.sendMessage(PooledLambda.obtainMessage( + UserHandler::updateDiscoveryPreferenceOnHandler, mUserRecord.mHandler)); + } + @Override public String toString() { return "Manager " + mPackageName + " (pid " + mPid + ")"; @@ -1262,6 +1339,24 @@ class MediaRouter2ServiceImpl { return null; } + public void maybeUpdateDiscoveryPreferenceForUid(int uid) { + MediaRouter2ServiceImpl service = mServiceRef.get(); + if (service == null) { + return; + } + boolean isUidRelevant; + synchronized (service.mLock) { + isUidRelevant = mUserRecord.mRouterRecords.stream().anyMatch( + router -> router.mUid == uid) + | mUserRecord.mManagerRecords.stream().anyMatch( + manager -> manager.mUid == uid); + } + if (isUidRelevant) { + sendMessage(PooledLambda.obtainMessage( + UserHandler::updateDiscoveryPreferenceOnHandler, this)); + } + } + private void onProviderStateChangedOnHandler(@NonNull MediaRoute2Provider provider) { int providerInfoIndex = getLastProviderInfoIndex(provider.getUniqueId()); MediaRoute2ProviderInfo currentInfo = provider.getProviderInfo(); @@ -1767,6 +1862,16 @@ class MediaRouter2ServiceImpl { return managers; } + private List<RouterRecord> getRouterRecords() { + MediaRouter2ServiceImpl service = mServiceRef.get(); + if (service == null) { + return Collections.emptyList(); + } + synchronized (service.mLock) { + return new ArrayList<>(mUserRecord.mRouterRecords); + } + } + private List<ManagerRecord> getManagerRecords() { MediaRouter2ServiceImpl service = mServiceRef.get(); if (service == null) { @@ -2001,13 +2106,28 @@ class MediaRouter2ServiceImpl { return; } List<RouteDiscoveryPreference> discoveryPreferences = new ArrayList<>(); - synchronized (service.mLock) { - for (RouterRecord routerRecord : mUserRecord.mRouterRecords) { + List<RouterRecord> routerRecords = getRouterRecords(); + List<ManagerRecord> managerRecords = getManagerRecords(); + boolean isAnyManagerScanning = + managerRecords.stream().anyMatch(manager -> manager.mIsScanning + && service.mActivityManager.getPackageImportance(manager.mPackageName) + <= PACKAGE_IMPORTANCE_FOR_DISCOVERY); + + for (RouterRecord routerRecord : routerRecords) { + if (isAnyManagerScanning + || service.mActivityManager.getPackageImportance(routerRecord.mPackageName) + <= PACKAGE_IMPORTANCE_FOR_DISCOVERY) { discoveryPreferences.add(routerRecord.mDiscoveryPreference); } - mUserRecord.mCompositeDiscoveryPreference = - new RouteDiscoveryPreference.Builder(discoveryPreferences) - .build(); + } + + synchronized (service.mLock) { + RouteDiscoveryPreference newPreference = + new RouteDiscoveryPreference.Builder(discoveryPreferences).build(); + if (newPreference.equals(mUserRecord.mCompositeDiscoveryPreference)) { + return; + } + mUserRecord.mCompositeDiscoveryPreference = newPreference; } for (MediaRoute2Provider provider : mRouteProviders) { provider.updateDiscoveryPreference(mUserRecord.mCompositeDiscoveryPreference); diff --git a/services/core/java/com/android/server/media/MediaRouterService.java b/services/core/java/com/android/server/media/MediaRouterService.java index 0e52a67c8d39..b6d6cc48d0cd 100644 --- a/services/core/java/com/android/server/media/MediaRouterService.java +++ b/services/core/java/com/android/server/media/MediaRouterService.java @@ -544,6 +544,18 @@ public final class MediaRouterService extends IMediaRouterService.Stub // Binder call @Override + public void startScan(IMediaRouter2Manager manager) { + mService2.startScan(manager); + } + + // Binder call + @Override + public void stopScan(IMediaRouter2Manager manager) { + mService2.stopScan(manager); + } + + // Binder call + @Override public void setRouteVolumeWithManager(IMediaRouter2Manager manager, int requestId, MediaRoute2Info route, int volume) { mService2.setRouteVolumeWithManager(manager, requestId, route, volume); diff --git a/services/core/java/com/android/server/net/LockdownVpnTracker.java b/services/core/java/com/android/server/net/LockdownVpnTracker.java index ea1d8da74185..ea2788c0c3d8 100644 --- a/services/core/java/com/android/server/net/LockdownVpnTracker.java +++ b/services/core/java/com/android/server/net/LockdownVpnTracker.java @@ -34,7 +34,6 @@ import android.net.NetworkInfo; import android.net.NetworkInfo.DetailedState; import android.net.NetworkInfo.State; import android.os.Handler; -import android.security.Credentials; import android.security.KeyStore; import android.text.TextUtils; import android.util.Log; @@ -70,6 +69,7 @@ public class LockdownVpnTracker { @NonNull private final Handler mHandler; @NonNull private final Vpn mVpn; @NonNull private final VpnProfile mProfile; + @NonNull private final KeyStore mKeyStore; @NonNull private final Object mStateLock = new Object(); @@ -81,13 +81,10 @@ public class LockdownVpnTracker { private int mErrorCount; - public static boolean isEnabled() { - return KeyStore.getInstance().contains(Credentials.LOCKDOWN_VPN); - } - public LockdownVpnTracker(@NonNull Context context, @NonNull ConnectivityService connService, @NonNull Handler handler, + @NonNull KeyStore keyStore, @NonNull Vpn vpn, @NonNull VpnProfile profile) { mContext = Objects.requireNonNull(context); @@ -95,6 +92,7 @@ public class LockdownVpnTracker { mHandler = Objects.requireNonNull(handler); mVpn = Objects.requireNonNull(vpn); mProfile = Objects.requireNonNull(profile); + mKeyStore = Objects.requireNonNull(keyStore); mNotificationManager = mContext.getSystemService(NotificationManager.class); final Intent configIntent = new Intent(ACTION_VPN_SETTINGS); @@ -157,7 +155,7 @@ public class LockdownVpnTracker { try { // Use the privileged method because Lockdown VPN is initiated by the system, so // no additional permission checks are necessary. - mVpn.startLegacyVpnPrivileged(mProfile, KeyStore.getInstance(), egressProp); + mVpn.startLegacyVpnPrivileged(mProfile, mKeyStore, egressProp); } catch (IllegalStateException e) { mAcceptedEgressIface = null; Log.e(TAG, "Failed to start VPN", e); diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java index 0f8c9c789a3f..fc5654144b3f 100644 --- a/services/core/java/com/android/server/om/OverlayManagerService.java +++ b/services/core/java/com/android/server/om/OverlayManagerService.java @@ -24,11 +24,15 @@ import static android.content.Intent.ACTION_PACKAGE_REMOVED; import static android.content.Intent.ACTION_USER_ADDED; import static android.content.Intent.ACTION_USER_REMOVED; import static android.content.Intent.EXTRA_REASON; +import static android.content.om.OverlayManagerTransaction.Request.TYPE_SET_DISABLED; +import static android.content.om.OverlayManagerTransaction.Request.TYPE_SET_ENABLED; import static android.content.pm.PackageManager.SIGNATURE_MATCH; import static android.os.Trace.TRACE_TAG_RRO; import static android.os.Trace.traceBegin; import static android.os.Trace.traceEnd; +import static com.android.server.om.OverlayManagerServiceImpl.OperationFailedException; + import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; @@ -39,6 +43,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.om.IOverlayManager; import android.content.om.OverlayInfo; +import android.content.om.OverlayManagerTransaction; import android.content.om.OverlayableInfo; import android.content.pm.IPackageManager; import android.content.pm.PackageInfo; @@ -48,6 +53,7 @@ import android.content.res.ApkAssets; import android.net.Uri; import android.os.Binder; import android.os.Environment; +import android.os.HandlerThread; import android.os.IBinder; import android.os.RemoteException; import android.os.ResultReceiver; @@ -64,7 +70,6 @@ import android.util.SparseArray; import com.android.internal.content.om.OverlayConfig; import com.android.server.FgThread; -import com.android.server.IoThread; import com.android.server.LocalServices; import com.android.server.SystemConfig; import com.android.server.SystemService; @@ -82,12 +87,15 @@ import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.concurrent.atomic.AtomicBoolean; +import java.util.Optional; +import java.util.Set; +import java.util.function.Consumer; /** * Service to manage asset overlays. @@ -236,7 +244,14 @@ public final class OverlayManagerService extends SystemService { private final OverlayActorEnforcer mActorEnforcer; - private final AtomicBoolean mPersistSettingsScheduled = new AtomicBoolean(false); + private final Consumer<PackageAndUser> mPropagateOverlayChange = (pair) -> { + persistSettings(); + FgThread.getHandler().post(() -> { + List<String> affectedTargets = updatePackageManager(pair.packageName, pair.userId); + updateActivityManager(affectedTargets, pair.userId); + broadcastActionOverlayChanged(pair.packageName, pair.userId); + }); + }; public OverlayManagerService(@NonNull final Context context) { super(context); @@ -249,17 +264,19 @@ public final class OverlayManagerService extends SystemService { IdmapManager im = new IdmapManager(IdmapDaemon.getInstance(), mPackageManager); mSettings = new OverlayManagerSettings(); mImpl = new OverlayManagerServiceImpl(mPackageManager, im, mSettings, - OverlayConfig.getSystemInstance(), getDefaultOverlayPackages(), - new OverlayChangeListener()); + OverlayConfig.getSystemInstance(), getDefaultOverlayPackages()); mActorEnforcer = new OverlayActorEnforcer(mPackageManager); + HandlerThread packageReceiverThread = new HandlerThread(TAG); + packageReceiverThread.start(); + final IntentFilter packageFilter = new IntentFilter(); packageFilter.addAction(ACTION_PACKAGE_ADDED); packageFilter.addAction(ACTION_PACKAGE_CHANGED); packageFilter.addAction(ACTION_PACKAGE_REMOVED); packageFilter.addDataScheme("package"); getContext().registerReceiverAsUser(new PackageReceiver(), UserHandle.ALL, - packageFilter, null, null); + packageFilter, null, packageReceiverThread.getThreadHandler()); final IntentFilter userFilter = new IntentFilter(); userFilter.addAction(ACTION_USER_ADDED); @@ -292,11 +309,11 @@ public final class OverlayManagerService extends SystemService { for (int i = 0; i < userCount; i++) { final UserInfo userInfo = users.get(i); if (!userInfo.supportsSwitchTo() && userInfo.id != UserHandle.USER_SYSTEM) { - // Initialize any users that can't be switched to, as there state would + // Initialize any users that can't be switched to, as their state would // never be setup in onSwitchUser(). We will switch to the system user right // after this, and its state will be setup there. final List<String> targets = mImpl.updateOverlaysForUser(users.get(i).id); - updateOverlayPaths(users.get(i).id, targets); + updatePackageManager(targets, users.get(i).id); } } } @@ -310,9 +327,10 @@ public final class OverlayManagerService extends SystemService { // any asset changes to the rest of the system synchronized (mLock) { final List<String> targets = mImpl.updateOverlaysForUser(newUserId); - updateAssets(newUserId, targets); + final List<String> affectedTargets = updatePackageManager(targets, newUserId); + updateActivityManager(affectedTargets, newUserId); } - schedulePersistSettings(); + persistSettings(); } finally { traceEnd(TRACE_TAG_RRO); } @@ -396,10 +414,17 @@ public final class OverlayManagerService extends SystemService { false); if (pi != null && !pi.applicationInfo.isInstantApp()) { mPackageManager.cachePackageInfo(packageName, userId, pi); - if (pi.isOverlayPackage()) { - mImpl.onOverlayPackageAdded(packageName, userId); - } else { - mImpl.onTargetPackageAdded(packageName, userId); + + try { + if (pi.isOverlayPackage()) { + mImpl.onOverlayPackageAdded(packageName, userId) + .ifPresent(mPropagateOverlayChange); + } else { + mImpl.onTargetPackageAdded(packageName, userId) + .ifPresent(mPropagateOverlayChange); + } + } catch (OperationFailedException e) { + Slog.e(TAG, "onPackageAdded internal error", e); } } } @@ -419,10 +444,17 @@ public final class OverlayManagerService extends SystemService { false); if (pi != null && pi.applicationInfo.isInstantApp()) { mPackageManager.cachePackageInfo(packageName, userId, pi); - if (pi.isOverlayPackage()) { - mImpl.onOverlayPackageChanged(packageName, userId); - } else { - mImpl.onTargetPackageChanged(packageName, userId); + + try { + if (pi.isOverlayPackage()) { + mImpl.onOverlayPackageChanged(packageName, userId) + .ifPresent(mPropagateOverlayChange); + } else { + mImpl.onTargetPackageChanged(packageName, userId) + .ifPresent(mPropagateOverlayChange); + } + } catch (OperationFailedException e) { + Slog.e(TAG, "onPackageChanged internal error", e); } } } @@ -441,7 +473,12 @@ public final class OverlayManagerService extends SystemService { mPackageManager.forgetPackageInfo(packageName, userId); final OverlayInfo oi = mImpl.getOverlayInfo(packageName, userId); if (oi != null) { - mImpl.onOverlayPackageReplacing(packageName, userId); + try { + mImpl.onOverlayPackageReplacing(packageName, userId) + .ifPresent(mPropagateOverlayChange); + } catch (OperationFailedException e) { + Slog.e(TAG, "onPackageReplacing internal error", e); + } } } } @@ -460,10 +497,16 @@ public final class OverlayManagerService extends SystemService { false); if (pi != null && !pi.applicationInfo.isInstantApp()) { mPackageManager.cachePackageInfo(packageName, userId, pi); - if (pi.isOverlayPackage()) { - mImpl.onOverlayPackageReplaced(packageName, userId); - } else { - mImpl.onTargetPackageReplaced(packageName, userId); + try { + if (pi.isOverlayPackage()) { + mImpl.onOverlayPackageReplaced(packageName, userId) + .ifPresent(mPropagateOverlayChange); + } else { + mImpl.onTargetPackageReplaced(packageName, userId) + .ifPresent(mPropagateOverlayChange); + } + } catch (OperationFailedException e) { + Slog.e(TAG, "onPackageReplaced internal error", e); } } } @@ -481,10 +524,17 @@ public final class OverlayManagerService extends SystemService { synchronized (mLock) { mPackageManager.forgetPackageInfo(packageName, userId); final OverlayInfo oi = mImpl.getOverlayInfo(packageName, userId); - if (oi != null) { - mImpl.onOverlayPackageRemoved(packageName, userId); - } else { - mImpl.onTargetPackageRemoved(packageName, userId); + + try { + if (oi != null) { + mImpl.onOverlayPackageRemoved(packageName, userId) + .ifPresent(mPropagateOverlayChange); + } else { + mImpl.onTargetPackageRemoved(packageName, userId) + .ifPresent(mPropagateOverlayChange); + } + } catch (OperationFailedException e) { + Slog.e(TAG, "onPackageRemoved internal error", e); } } } @@ -507,7 +557,7 @@ public final class OverlayManagerService extends SystemService { synchronized (mLock) { targets = mImpl.updateOverlaysForUser(userId); } - updateOverlayPaths(userId, targets); + updatePackageManager(targets, userId); } finally { traceEnd(TRACE_TAG_RRO); } @@ -602,7 +652,13 @@ public final class OverlayManagerService extends SystemService { final long ident = Binder.clearCallingIdentity(); try { synchronized (mLock) { - return mImpl.setEnabled(packageName, enable, realUserId); + try { + mImpl.setEnabled(packageName, enable, realUserId) + .ifPresent(mPropagateOverlayChange); + return true; + } catch (OperationFailedException e) { + return false; + } } } finally { Binder.restoreCallingIdentity(ident); @@ -627,8 +683,14 @@ public final class OverlayManagerService extends SystemService { final long ident = Binder.clearCallingIdentity(); try { synchronized (mLock) { - return mImpl.setEnabledExclusive(packageName, false /* withinCategory */, - realUserId); + try { + mImpl.setEnabledExclusive(packageName, + false /* withinCategory */, realUserId) + .ifPresent(mPropagateOverlayChange); + return true; + } catch (OperationFailedException e) { + return false; + } } } finally { Binder.restoreCallingIdentity(ident); @@ -654,8 +716,14 @@ public final class OverlayManagerService extends SystemService { final long ident = Binder.clearCallingIdentity(); try { synchronized (mLock) { - return mImpl.setEnabledExclusive(packageName, true /* withinCategory */, - realUserId); + try { + mImpl.setEnabledExclusive(packageName, + true /* withinCategory */, realUserId) + .ifPresent(mPropagateOverlayChange); + return true; + } catch (OperationFailedException e) { + return false; + } } } finally { Binder.restoreCallingIdentity(ident); @@ -681,7 +749,13 @@ public final class OverlayManagerService extends SystemService { final long ident = Binder.clearCallingIdentity(); try { synchronized (mLock) { - return mImpl.setPriority(packageName, parentPackageName, realUserId); + try { + mImpl.setPriority(packageName, parentPackageName, realUserId) + .ifPresent(mPropagateOverlayChange); + return true; + } catch (OperationFailedException e) { + return false; + } } } finally { Binder.restoreCallingIdentity(ident); @@ -705,7 +779,13 @@ public final class OverlayManagerService extends SystemService { final long ident = Binder.clearCallingIdentity(); try { synchronized (mLock) { - return mImpl.setHighestPriority(packageName, realUserId); + try { + mImpl.setHighestPriority(packageName, realUserId) + .ifPresent(mPropagateOverlayChange); + return true; + } catch (OperationFailedException e) { + return false; + } } } finally { Binder.restoreCallingIdentity(ident); @@ -729,7 +809,13 @@ public final class OverlayManagerService extends SystemService { final long ident = Binder.clearCallingIdentity(); try { synchronized (mLock) { - return mImpl.setLowestPriority(packageName, realUserId); + try { + mImpl.setLowestPriority(packageName, realUserId) + .ifPresent(mPropagateOverlayChange); + return true; + } catch (OperationFailedException e) { + return false; + } } } finally { Binder.restoreCallingIdentity(ident); @@ -778,6 +864,129 @@ public final class OverlayManagerService extends SystemService { } @Override + public void commit(@NonNull final OverlayManagerTransaction transaction) + throws RemoteException { + try { + traceBegin(TRACE_TAG_RRO, "OMS#commit " + transaction); + try { + executeAllRequests(transaction); + } catch (Exception e) { + final long ident = Binder.clearCallingIdentity(); + try { + restoreSettings(); + } finally { + Binder.restoreCallingIdentity(ident); + } + Slog.d(TAG, "commit failed: " + e.getMessage(), e); + throw new SecurityException("commit failed" + + (DEBUG ? ": " + e.getMessage() : "")); + } + } finally { + traceEnd(TRACE_TAG_RRO); + } + } + + private Optional<PackageAndUser> executeRequest( + @NonNull final OverlayManagerTransaction.Request request) throws Exception { + final int realUserId = handleIncomingUser(request.userId, request.typeToString()); + enforceActor(request.packageName, request.typeToString(), realUserId); + + final long ident = Binder.clearCallingIdentity(); + try { + switch (request.type) { + case TYPE_SET_ENABLED: + Optional<PackageAndUser> opt1 = + mImpl.setEnabled(request.packageName, true, request.userId); + Optional<PackageAndUser> opt2 = + mImpl.setHighestPriority(request.packageName, request.userId); + // Both setEnabled and setHighestPriority affected the same + // target package and user: if both return non-empty + // Optionals, they are identical + return opt1.isPresent() ? opt1 : opt2; + case TYPE_SET_DISABLED: + return mImpl.setEnabled(request.packageName, false, request.userId); + default: + throw new IllegalArgumentException("unsupported request: " + request); + } + } finally { + Binder.restoreCallingIdentity(ident); + } + } + + private void executeAllRequests(@NonNull final OverlayManagerTransaction transaction) + throws Exception { + if (DEBUG) { + Slog.d(TAG, "commit " + transaction); + } + if (transaction == null) { + throw new IllegalArgumentException("null transaction"); + } + + // map: userId -> set<package-name>: target packages of overlays in + // this transaction + SparseArray<Set<String>> transactionTargets = new SparseArray<>(); + + // map: userId -> set<package-name>: packages that need to reload + // their resources due to changes to the overlays in this + // transaction + SparseArray<List<String>> affectedPackagesToUpdate = new SparseArray<>(); + + synchronized (mLock) { + + // execute the requests (as calling user) + for (final OverlayManagerTransaction.Request request : transaction) { + executeRequest(request).ifPresent(target -> { + Set<String> userTargets = transactionTargets.get(target.userId); + if (userTargets == null) { + userTargets = new ArraySet<String>(); + transactionTargets.put(target.userId, userTargets); + } + userTargets.add(target.packageName); + }); + } + + // past the point of no return: the entire transaction has been + // processed successfully, we can no longer fail: continue as + // system_server + final long ident = Binder.clearCallingIdentity(); + try { + persistSettings(); + + // inform the package manager about the new paths + for (int index = 0; index < transactionTargets.size(); index++) { + final int userId = transactionTargets.keyAt(index); + final List<String> affectedTargets = + updatePackageManager(transactionTargets.valueAt(index), userId); + affectedPackagesToUpdate.put(userId, affectedTargets); + } + } finally { + Binder.restoreCallingIdentity(ident); + } + } // synchronized (mLock) + + FgThread.getHandler().post(() -> { + final long ident = Binder.clearCallingIdentity(); + try { + // schedule apps to refresh + for (int index = 0; index < affectedPackagesToUpdate.size(); index++) { + final int userId = affectedPackagesToUpdate.keyAt(index); + updateActivityManager(affectedPackagesToUpdate.valueAt(index), userId); + } + + // broadcast the ACTION_OVERLAY_CHANGED intents + for (int index = 0; index < transactionTargets.size(); index++) { + final int userId = transactionTargets.keyAt(index); + for (String pkg: transactionTargets.valueAt(index)) { + broadcastActionOverlayChanged(pkg, userId); + } + } + } finally { + Binder.restoreCallingIdentity(ident); + } + }); + } + + @Override public void onShellCommand(@NonNull final FileDescriptor in, @NonNull final FileDescriptor out, @NonNull final FileDescriptor err, @NonNull final String[] args, @NonNull final ShellCallback callback, @@ -898,162 +1107,7 @@ public final class OverlayManagerService extends SystemService { } }; - private final class OverlayChangeListener - implements OverlayManagerServiceImpl.OverlayChangeListener { - @Override - public void onOverlaysChanged(@NonNull final String targetPackageName, final int userId) { - schedulePersistSettings(); - FgThread.getHandler().post(() -> { - updateAssets(userId, targetPackageName); - - final Intent intent = new Intent(ACTION_OVERLAY_CHANGED, - Uri.fromParts("package", targetPackageName, null)); - intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); - - if (DEBUG) { - Slog.d(TAG, "send broadcast " + intent); - } - - try { - ActivityManager.getService().broadcastIntentWithFeature(null, null, intent, - null, null, 0, null, null, null, android.app.AppOpsManager.OP_NONE, - null, false, false, userId); - } catch (RemoteException e) { - // Intentionally left empty. - } - }); - } - } - - /** - * Updates the target packages' set of enabled overlays in PackageManager. - */ - private ArrayList<String> updateOverlayPaths(int userId, List<String> targetPackageNames) { - try { - traceBegin(TRACE_TAG_RRO, "OMS#updateOverlayPaths " + targetPackageNames); - if (DEBUG) { - Slog.d(TAG, "Updating overlay assets"); - } - final PackageManagerInternal pm = - LocalServices.getService(PackageManagerInternal.class); - final boolean updateFrameworkRes = targetPackageNames.contains("android"); - if (updateFrameworkRes) { - targetPackageNames = pm.getTargetPackageNames(userId); - } - - final Map<String, List<String>> pendingChanges = - new ArrayMap<>(targetPackageNames.size()); - synchronized (mLock) { - final List<String> frameworkOverlays = - mImpl.getEnabledOverlayPackageNames("android", userId); - final int n = targetPackageNames.size(); - for (int i = 0; i < n; i++) { - final String targetPackageName = targetPackageNames.get(i); - List<String> list = new ArrayList<>(); - if (!"android".equals(targetPackageName)) { - list.addAll(frameworkOverlays); - } - list.addAll(mImpl.getEnabledOverlayPackageNames(targetPackageName, userId)); - pendingChanges.put(targetPackageName, list); - } - } - - final HashSet<String> updatedPackages = new HashSet<>(); - final int n = targetPackageNames.size(); - for (int i = 0; i < n; i++) { - final String targetPackageName = targetPackageNames.get(i); - if (DEBUG) { - Slog.d(TAG, "-> Updating overlay: target=" + targetPackageName + " overlays=[" - + TextUtils.join(",", pendingChanges.get(targetPackageName)) - + "] userId=" + userId); - } - - if (!pm.setEnabledOverlayPackages( - userId, targetPackageName, pendingChanges.get(targetPackageName), - updatedPackages)) { - Slog.e(TAG, String.format("Failed to change enabled overlays for %s user %d", - targetPackageName, userId)); - } - } - return new ArrayList<>(updatedPackages); - } finally { - traceEnd(TRACE_TAG_RRO); - } - } - - private void updateAssets(final int userId, final String targetPackageName) { - updateAssets(userId, Collections.singletonList(targetPackageName)); - } - - private void updateAssets(final int userId, List<String> targetPackageNames) { - final IActivityManager am = ActivityManager.getService(); - try { - final ArrayList<String> updatedPaths = updateOverlayPaths(userId, targetPackageNames); - am.scheduleApplicationInfoChanged(updatedPaths, userId); - } catch (RemoteException e) { - // Intentionally left empty. - } - } - - private void schedulePersistSettings() { - if (mPersistSettingsScheduled.getAndSet(true)) { - return; - } - IoThread.getHandler().post(() -> { - mPersistSettingsScheduled.set(false); - if (DEBUG) { - Slog.d(TAG, "Writing overlay settings"); - } - synchronized (mLock) { - FileOutputStream stream = null; - try { - stream = mSettingsFile.startWrite(); - mSettings.persist(stream); - mSettingsFile.finishWrite(stream); - } catch (IOException | XmlPullParserException e) { - mSettingsFile.failWrite(stream); - Slog.e(TAG, "failed to persist overlay state", e); - } - } - }); - } - - private void restoreSettings() { - try { - traceBegin(TRACE_TAG_RRO, "OMS#restoreSettings"); - synchronized (mLock) { - if (!mSettingsFile.getBaseFile().exists()) { - return; - } - try (FileInputStream stream = mSettingsFile.openRead()) { - mSettings.restore(stream); - - // We might have data for dying users if the device was - // restarted before we received USER_REMOVED. Remove data for - // users that will not exist after the system is ready. - - final List<UserInfo> liveUsers = mUserManager.getUsers(true /*excludeDying*/); - final int[] liveUserIds = new int[liveUsers.size()]; - for (int i = 0; i < liveUsers.size(); i++) { - liveUserIds[i] = liveUsers.get(i).getUserHandle().getIdentifier(); - } - Arrays.sort(liveUserIds); - - for (int userId : mSettings.getUsers()) { - if (Arrays.binarySearch(liveUserIds, userId) < 0) { - mSettings.removeUser(userId); - } - } - } catch (IOException | XmlPullParserException e) { - Slog.e(TAG, "failed to restore overlay state", e); - } - } - } finally { - traceEnd(TRACE_TAG_RRO); - } - } - - private static final class PackageManagerHelperImpl implements PackageManagerHelper { + private static final class PackageManagerHelperImpl implements PackageManagerHelper { private final Context mContext; private final IPackageManager mPackageManager; @@ -1263,4 +1317,144 @@ public final class OverlayManagerService extends SystemService { } } } + + // Helper methods to update other parts of the system or read/write + // settings: these methods should never call into each other! + + private void broadcastActionOverlayChanged(@NonNull final String targetPackageName, + final int userId) { + final Intent intent = new Intent(ACTION_OVERLAY_CHANGED, + Uri.fromParts("package", targetPackageName, null)); + intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); + try { + ActivityManager.getService().broadcastIntent(null, intent, null, null, 0, null, null, + null, android.app.AppOpsManager.OP_NONE, null, false, false, userId); + } catch (RemoteException e) { + // Intentionally left empty. + } + } + + /** + * Tell the activity manager to tell a set of packages to reload their + * resources. + */ + private void updateActivityManager(List<String> targetPackageNames, final int userId) { + final IActivityManager am = ActivityManager.getService(); + try { + am.scheduleApplicationInfoChanged(targetPackageNames, userId); + } catch (RemoteException e) { + // Intentionally left empty. + } + } + + private ArrayList<String> updatePackageManager(String targetPackageNames, final int userId) { + return updatePackageManager(Collections.singletonList(targetPackageNames), userId); + } + + /** + * Updates the target packages' set of enabled overlays in PackageManager. + * @return the package names of affected targets (a superset of + * targetPackageNames: the target themserlves and shared libraries) + */ + private ArrayList<String> updatePackageManager(@NonNull Collection<String> targetPackageNames, + final int userId) { + try { + traceBegin(TRACE_TAG_RRO, "OMS#updatePackageManager " + targetPackageNames); + if (DEBUG) { + Slog.d(TAG, "Update package manager about changed overlays"); + } + final PackageManagerInternal pm = + LocalServices.getService(PackageManagerInternal.class); + final boolean updateFrameworkRes = targetPackageNames.contains("android"); + if (updateFrameworkRes) { + targetPackageNames = pm.getTargetPackageNames(userId); + } + + final Map<String, List<String>> pendingChanges = + new ArrayMap<>(targetPackageNames.size()); + synchronized (mLock) { + final List<String> frameworkOverlays = + mImpl.getEnabledOverlayPackageNames("android", userId); + for (final String targetPackageName : targetPackageNames) { + List<String> list = new ArrayList<>(); + if (!"android".equals(targetPackageName)) { + list.addAll(frameworkOverlays); + } + list.addAll(mImpl.getEnabledOverlayPackageNames(targetPackageName, userId)); + pendingChanges.put(targetPackageName, list); + } + } + + final HashSet<String> updatedPackages = new HashSet<>(); + for (final String targetPackageName : targetPackageNames) { + if (DEBUG) { + Slog.d(TAG, "-> Updating overlay: target=" + targetPackageName + " overlays=[" + + TextUtils.join(",", pendingChanges.get(targetPackageName)) + + "] userId=" + userId); + } + + if (!pm.setEnabledOverlayPackages( + userId, targetPackageName, pendingChanges.get(targetPackageName), + updatedPackages)) { + Slog.e(TAG, String.format("Failed to change enabled overlays for %s user %d", + targetPackageName, userId)); + } + } + return new ArrayList<>(updatedPackages); + } finally { + traceEnd(TRACE_TAG_RRO); + } + } + + private void persistSettings() { + if (DEBUG) { + Slog.d(TAG, "Writing overlay settings"); + } + synchronized (mLock) { + FileOutputStream stream = null; + try { + stream = mSettingsFile.startWrite(); + mSettings.persist(stream); + mSettingsFile.finishWrite(stream); + } catch (IOException | XmlPullParserException e) { + mSettingsFile.failWrite(stream); + Slog.e(TAG, "failed to persist overlay state", e); + } + } + } + + private void restoreSettings() { + try { + traceBegin(TRACE_TAG_RRO, "OMS#restoreSettings"); + synchronized (mLock) { + if (!mSettingsFile.getBaseFile().exists()) { + return; + } + try (FileInputStream stream = mSettingsFile.openRead()) { + mSettings.restore(stream); + + // We might have data for dying users if the device was + // restarted before we received USER_REMOVED. Remove data for + // users that will not exist after the system is ready. + + final List<UserInfo> liveUsers = mUserManager.getUsers(true /*excludeDying*/); + final int[] liveUserIds = new int[liveUsers.size()]; + for (int i = 0; i < liveUsers.size(); i++) { + liveUserIds[i] = liveUsers.get(i).getUserHandle().getIdentifier(); + } + Arrays.sort(liveUserIds); + + for (int userId : mSettings.getUsers()) { + if (Arrays.binarySearch(liveUserIds, userId) < 0) { + mSettings.removeUser(userId); + } + } + } catch (IOException | XmlPullParserException e) { + Slog.e(TAG, "failed to restore overlay state", e); + } + } + } finally { + traceEnd(TRACE_TAG_RRO); + } + } } diff --git a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java index 05a4a38feef1..e60411bb78c5 100644 --- a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java +++ b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java @@ -45,6 +45,7 @@ import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Optional; import java.util.Set; /** @@ -71,7 +72,6 @@ final class OverlayManagerServiceImpl { private final OverlayManagerSettings mSettings; private final OverlayConfig mOverlayConfig; private final String[] mDefaultOverlays; - private final OverlayChangeListener mListener; /** * Helper method to merge the overlay manager's (as read from overlays.xml) @@ -114,14 +114,12 @@ final class OverlayManagerServiceImpl { @NonNull final IdmapManager idmapManager, @NonNull final OverlayManagerSettings settings, @NonNull final OverlayConfig overlayConfig, - @NonNull final String[] defaultOverlays, - @NonNull final OverlayChangeListener listener) { + @NonNull final String[] defaultOverlays) { mPackageManager = packageManager; mIdmapManager = idmapManager; mSettings = settings; mOverlayConfig = overlayConfig; mDefaultOverlays = defaultOverlays; - mListener = listener; } /** @@ -259,52 +257,58 @@ final class OverlayManagerServiceImpl { mSettings.removeUser(userId); } - void onTargetPackageAdded(@NonNull final String packageName, final int userId) { + Optional<PackageAndUser> onTargetPackageAdded(@NonNull final String packageName, + final int userId) throws OperationFailedException { if (DEBUG) { Slog.d(TAG, "onTargetPackageAdded packageName=" + packageName + " userId=" + userId); } - updateAndRefreshOverlaysForTarget(packageName, userId, 0); + return updateAndRefreshOverlaysForTarget(packageName, userId, 0); } - void onTargetPackageChanged(@NonNull final String packageName, final int userId) { + Optional<PackageAndUser> onTargetPackageChanged(@NonNull final String packageName, + final int userId) throws OperationFailedException { if (DEBUG) { Slog.d(TAG, "onTargetPackageChanged packageName=" + packageName + " userId=" + userId); } - updateAndRefreshOverlaysForTarget(packageName, userId, 0); + return updateAndRefreshOverlaysForTarget(packageName, userId, 0); } - void onTargetPackageReplacing(@NonNull final String packageName, final int userId) { + Optional<PackageAndUser> onTargetPackageReplacing(@NonNull final String packageName, + final int userId) throws OperationFailedException { if (DEBUG) { Slog.d(TAG, "onTargetPackageReplacing packageName=" + packageName + " userId=" + userId); } - updateAndRefreshOverlaysForTarget(packageName, userId, 0); + return updateAndRefreshOverlaysForTarget(packageName, userId, 0); } - void onTargetPackageReplaced(@NonNull final String packageName, final int userId) { + Optional<PackageAndUser> onTargetPackageReplaced(@NonNull final String packageName, + final int userId) throws OperationFailedException { if (DEBUG) { Slog.d(TAG, "onTargetPackageReplaced packageName=" + packageName + " userId=" + userId); } - updateAndRefreshOverlaysForTarget(packageName, userId, 0); + return updateAndRefreshOverlaysForTarget(packageName, userId, 0); } - void onTargetPackageRemoved(@NonNull final String packageName, final int userId) { + Optional<PackageAndUser> onTargetPackageRemoved(@NonNull final String packageName, + final int userId) throws OperationFailedException { if (DEBUG) { Slog.d(TAG, "onTargetPackageRemoved packageName=" + packageName + " userId=" + userId); } - updateAndRefreshOverlaysForTarget(packageName, userId, 0); + return updateAndRefreshOverlaysForTarget(packageName, userId, 0); } /** * Update the state of any overlays for this target. */ - private void updateAndRefreshOverlaysForTarget(@NonNull final String targetPackageName, - final int userId, final int flags) { + private Optional<PackageAndUser> updateAndRefreshOverlaysForTarget( + @NonNull final String targetPackageName, final int userId, final int flags) + throws OperationFailedException { final List<OverlayInfo> targetOverlays = mSettings.getOverlaysForTarget(targetPackageName, userId); @@ -364,11 +368,13 @@ final class OverlayManagerServiceImpl { } if (modified) { - mListener.onOverlaysChanged(targetPackageName, userId); + return Optional.of(new PackageAndUser(targetPackageName, userId)); } + return Optional.empty(); } - void onOverlayPackageAdded(@NonNull final String packageName, final int userId) { + Optional<PackageAndUser> onOverlayPackageAdded(@NonNull final String packageName, + final int userId) throws OperationFailedException { if (DEBUG) { Slog.d(TAG, "onOverlayPackageAdded packageName=" + packageName + " userId=" + userId); } @@ -376,8 +382,7 @@ final class OverlayManagerServiceImpl { final PackageInfo overlayPackage = mPackageManager.getPackageInfo(packageName, userId); if (overlayPackage == null) { Slog.w(TAG, "overlay package " + packageName + " was added, but couldn't be found"); - onOverlayPackageRemoved(packageName, userId); - return; + return onOverlayPackageRemoved(packageName, userId); } mSettings.init(packageName, userId, overlayPackage.overlayTarget, @@ -389,15 +394,17 @@ final class OverlayManagerServiceImpl { overlayPackage.overlayCategory); try { if (updateState(overlayPackage.overlayTarget, packageName, userId, 0)) { - mListener.onOverlaysChanged(overlayPackage.overlayTarget, userId); + return Optional.of(new PackageAndUser(overlayPackage.overlayTarget, userId)); } + return Optional.empty(); } catch (OverlayManagerSettings.BadKeyException e) { - Slog.e(TAG, "failed to update settings", e); mSettings.remove(packageName, userId); + throw new OperationFailedException("failed to update settings", e); } } - void onOverlayPackageChanged(@NonNull final String packageName, final int userId) { + Optional<PackageAndUser> onOverlayPackageChanged(@NonNull final String packageName, + final int userId) throws OperationFailedException { if (DEBUG) { Slog.d(TAG, "onOverlayPackageChanged packageName=" + packageName + " userId=" + userId); } @@ -405,14 +412,16 @@ final class OverlayManagerServiceImpl { try { final OverlayInfo oi = mSettings.getOverlayInfo(packageName, userId); if (updateState(oi.targetPackageName, packageName, userId, 0)) { - mListener.onOverlaysChanged(oi.targetPackageName, userId); + return Optional.of(new PackageAndUser(oi.targetPackageName, userId)); } + return Optional.empty(); } catch (OverlayManagerSettings.BadKeyException e) { - Slog.e(TAG, "failed to update settings", e); + throw new OperationFailedException("failed to update settings", e); } } - void onOverlayPackageReplacing(@NonNull final String packageName, final int userId) { + Optional<PackageAndUser> onOverlayPackageReplacing(@NonNull final String packageName, + final int userId) throws OperationFailedException { if (DEBUG) { Slog.d(TAG, "onOverlayPackageReplacing packageName=" + packageName + " userId=" + userId); @@ -423,14 +432,16 @@ final class OverlayManagerServiceImpl { if (updateState(oi.targetPackageName, packageName, userId, FLAG_OVERLAY_IS_BEING_REPLACED)) { removeIdmapIfPossible(oi); - mListener.onOverlaysChanged(oi.targetPackageName, userId); + return Optional.of(new PackageAndUser(oi.targetPackageName, userId)); } + return Optional.empty(); } catch (OverlayManagerSettings.BadKeyException e) { - Slog.e(TAG, "failed to update settings", e); + throw new OperationFailedException("failed to update settings", e); } } - void onOverlayPackageReplaced(@NonNull final String packageName, final int userId) { + Optional<PackageAndUser> onOverlayPackageReplaced(@NonNull final String packageName, + final int userId) throws OperationFailedException { if (DEBUG) { Slog.d(TAG, "onOverlayPackageReplaced packageName=" + packageName + " userId=" + userId); @@ -439,16 +450,12 @@ final class OverlayManagerServiceImpl { final PackageInfo pkg = mPackageManager.getPackageInfo(packageName, userId); if (pkg == null) { Slog.w(TAG, "overlay package " + packageName + " was replaced, but couldn't be found"); - onOverlayPackageRemoved(packageName, userId); - return; + return onOverlayPackageRemoved(packageName, userId); } try { final OverlayInfo oldOi = mSettings.getOverlayInfo(packageName, userId); if (mustReinitializeOverlay(pkg, oldOi)) { - if (oldOi != null && !oldOi.targetPackageName.equals(pkg.overlayTarget)) { - mListener.onOverlaysChanged(pkg.overlayTarget, userId); - } mSettings.init(packageName, userId, pkg.overlayTarget, pkg.targetOverlayableName, pkg.applicationInfo.getBaseCodePath(), isPackageConfiguredMutable(pkg.packageName), @@ -457,22 +464,25 @@ final class OverlayManagerServiceImpl { } if (updateState(pkg.overlayTarget, packageName, userId, 0)) { - mListener.onOverlaysChanged(pkg.overlayTarget, userId); + return Optional.of(new PackageAndUser(pkg.overlayTarget, userId)); } + return Optional.empty(); } catch (OverlayManagerSettings.BadKeyException e) { - Slog.e(TAG, "failed to update settings", e); + throw new OperationFailedException("failed to update settings", e); } } - void onOverlayPackageRemoved(@NonNull final String packageName, final int userId) { + Optional<PackageAndUser> onOverlayPackageRemoved(@NonNull final String packageName, + final int userId) throws OperationFailedException { try { final OverlayInfo overlayInfo = mSettings.getOverlayInfo(packageName, userId); if (mSettings.remove(packageName, userId)) { removeIdmapIfPossible(overlayInfo); - mListener.onOverlaysChanged(overlayInfo.targetPackageName, userId); + return Optional.of(new PackageAndUser(overlayInfo.targetPackageName, userId)); } + return Optional.empty(); } catch (OverlayManagerSettings.BadKeyException e) { - Slog.e(TAG, "failed to remove overlay", e); + throw new OperationFailedException("failed to remove overlay", e); } } @@ -493,8 +503,8 @@ final class OverlayManagerServiceImpl { return mSettings.getOverlaysForUser(userId); } - boolean setEnabled(@NonNull final String packageName, final boolean enable, - final int userId) { + Optional<PackageAndUser> setEnabled(@NonNull final String packageName, final boolean enable, + final int userId) throws OperationFailedException { if (DEBUG) { Slog.d(TAG, String.format("setEnabled packageName=%s enable=%s userId=%d", packageName, enable, userId)); @@ -502,30 +512,33 @@ final class OverlayManagerServiceImpl { final PackageInfo overlayPackage = mPackageManager.getPackageInfo(packageName, userId); if (overlayPackage == null) { - return false; + throw new OperationFailedException( + String.format("failed to find overlay package %s for user %d", + packageName, userId)); } try { final OverlayInfo oi = mSettings.getOverlayInfo(packageName, userId); if (!oi.isMutable) { // Ignore immutable overlays. - return false; + throw new OperationFailedException( + "cannot enable immutable overlay packages in runtime"); } boolean modified = mSettings.setEnabled(packageName, userId, enable); modified |= updateState(oi.targetPackageName, oi.packageName, userId, 0); if (modified) { - mListener.onOverlaysChanged(oi.targetPackageName, userId); + return Optional.of(new PackageAndUser(oi.targetPackageName, userId)); } - return true; + return Optional.empty(); } catch (OverlayManagerSettings.BadKeyException e) { - return false; + throw new OperationFailedException("failed to update settings", e); } } - boolean setEnabledExclusive(@NonNull final String packageName, boolean withinCategory, - final int userId) { + Optional<PackageAndUser> setEnabledExclusive(@NonNull final String packageName, + boolean withinCategory, final int userId) throws OperationFailedException { if (DEBUG) { Slog.d(TAG, String.format("setEnabledExclusive packageName=%s" + " withinCategory=%s userId=%d", packageName, withinCategory, userId)); @@ -533,7 +546,8 @@ final class OverlayManagerServiceImpl { final PackageInfo overlayPackage = mPackageManager.getPackageInfo(packageName, userId); if (overlayPackage == null) { - return false; + throw new OperationFailedException(String.format( + "failed to find overlay package %s for user %d", packageName, userId)); } try { @@ -576,11 +590,11 @@ final class OverlayManagerServiceImpl { modified |= updateState(targetPackageName, packageName, userId, 0); if (modified) { - mListener.onOverlaysChanged(targetPackageName, userId); + return Optional.of(new PackageAndUser(targetPackageName, userId)); } - return true; + return Optional.empty(); } catch (OverlayManagerSettings.BadKeyException e) { - return false; + throw new OperationFailedException("failed to update settings", e); } } @@ -596,66 +610,75 @@ final class OverlayManagerServiceImpl { return mOverlayConfig.isEnabled(packageName); } - boolean setPriority(@NonNull final String packageName, - @NonNull final String newParentPackageName, final int userId) { + Optional<PackageAndUser> setPriority(@NonNull final String packageName, + @NonNull final String newParentPackageName, final int userId) + throws OperationFailedException { if (DEBUG) { Slog.d(TAG, "setPriority packageName=" + packageName + " newParentPackageName=" + newParentPackageName + " userId=" + userId); } if (!isPackageConfiguredMutable(packageName)) { - return false; + throw new OperationFailedException(String.format( + "overlay package %s user %d is not updatable", packageName, userId)); } final PackageInfo overlayPackage = mPackageManager.getPackageInfo(packageName, userId); if (overlayPackage == null) { - return false; + throw new OperationFailedException(String.format( + "failed to find overlay package %s for user %d", packageName, userId)); } if (mSettings.setPriority(packageName, newParentPackageName, userId)) { - mListener.onOverlaysChanged(overlayPackage.overlayTarget, userId); + return Optional.of(new PackageAndUser(overlayPackage.overlayTarget, userId)); } - return true; + return Optional.empty(); } - boolean setHighestPriority(@NonNull final String packageName, final int userId) { + Optional<PackageAndUser> setHighestPriority(@NonNull final String packageName, + final int userId) throws OperationFailedException { if (DEBUG) { Slog.d(TAG, "setHighestPriority packageName=" + packageName + " userId=" + userId); } if (!isPackageConfiguredMutable(packageName)) { - return false; + throw new OperationFailedException(String.format( + "overlay package %s user %d is not updatable", packageName, userId)); } final PackageInfo overlayPackage = mPackageManager.getPackageInfo(packageName, userId); if (overlayPackage == null) { - return false; + throw new OperationFailedException(String.format( + "failed to find overlay package %s for user %d", packageName, userId)); } if (mSettings.setHighestPriority(packageName, userId)) { - mListener.onOverlaysChanged(overlayPackage.overlayTarget, userId); + return Optional.of(new PackageAndUser(overlayPackage.overlayTarget, userId)); } - return true; + return Optional.empty(); } - boolean setLowestPriority(@NonNull final String packageName, final int userId) { + Optional<PackageAndUser> setLowestPriority(@NonNull final String packageName, final int userId) + throws OperationFailedException { if (DEBUG) { Slog.d(TAG, "setLowestPriority packageName=" + packageName + " userId=" + userId); } if (!isPackageConfiguredMutable(packageName)) { - return false; + throw new OperationFailedException(String.format( + "overlay package %s user %d is not updatable", packageName, userId)); } final PackageInfo overlayPackage = mPackageManager.getPackageInfo(packageName, userId); if (overlayPackage == null) { - return false; + throw new OperationFailedException(String.format( + "failed to find overlay package %s for user %d", packageName, userId)); } if (mSettings.setLowestPriority(packageName, userId)) { - mListener.onOverlaysChanged(overlayPackage.overlayTarget, userId); + return Optional.of(new PackageAndUser(overlayPackage.overlayTarget, userId)); } - return true; + return Optional.empty(); } void dump(@NonNull final PrintWriter pw, @NonNull DumpState dumpState) { @@ -797,12 +820,13 @@ final class OverlayManagerServiceImpl { mIdmapManager.removeIdmap(oi, oi.userId); } - interface OverlayChangeListener { + static final class OperationFailedException extends Exception { + OperationFailedException(@NonNull final String message) { + super(message); + } - /** - * An event triggered by changes made to overlay state or settings as well as changes that - * add or remove target packages of overlays. - **/ - void onOverlaysChanged(@NonNull String targetPackage, int userId); + OperationFailedException(@NonNull final String message, @NonNull Throwable cause) { + super(message, cause); + } } } diff --git a/services/core/java/com/android/server/om/PackageAndUser.java b/services/core/java/com/android/server/om/PackageAndUser.java new file mode 100644 index 000000000000..5c38ba7ce97b --- /dev/null +++ b/services/core/java/com/android/server/om/PackageAndUser.java @@ -0,0 +1,57 @@ +/* + * 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.server.om; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.UserIdInt; + +final class PackageAndUser { + public final @NonNull String packageName; + public final @UserIdInt int userId; + + PackageAndUser(@NonNull String packageName, @UserIdInt int userId) { + this.packageName = packageName; + this.userId = userId; + } + + @Override + public boolean equals(@Nullable Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof PackageAndUser)) { + return false; + } + PackageAndUser other = (PackageAndUser) obj; + return packageName.equals(other.packageName) && userId == other.userId; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + packageName.hashCode(); + result = prime * result + userId; + return result; + } + + @Override + public String toString() { + return String.format("PackageAndUser{packageName=%s, userId=%d}", packageName, userId); + } +} diff --git a/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java b/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java index dd507a3b1f81..ef0f0eeb56f8 100644 --- a/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java +++ b/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java @@ -21,6 +21,7 @@ import android.annotation.RequiresPermission; import android.app.ActivityManager; import android.app.AppOpsManager; import android.content.Context; +import android.content.pm.PackageManager; import android.content.pm.UserInfo; import android.os.Binder; import android.os.BugreportParams; @@ -31,6 +32,7 @@ import android.os.ServiceManager; import android.os.SystemClock; import android.os.SystemProperties; import android.os.UserManager; +import android.telephony.TelephonyManager; import android.util.ArraySet; import android.util.Slog; @@ -53,11 +55,13 @@ class BugreportManagerServiceImpl extends IDumpstate.Stub { private final Object mLock = new Object(); private final Context mContext; private final AppOpsManager mAppOps; + private final TelephonyManager mTelephonyManager; private final ArraySet<String> mBugreportWhitelistedPackages; BugreportManagerServiceImpl(Context context) { mContext = context; - mAppOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); + mAppOps = context.getSystemService(AppOpsManager.class); + mTelephonyManager = context.getSystemService(TelephonyManager.class); mBugreportWhitelistedPackages = SystemConfig.getInstance().getBugreportWhitelistedPackages(); } @@ -67,11 +71,14 @@ class BugreportManagerServiceImpl extends IDumpstate.Stub { public void startBugreport(int callingUidUnused, String callingPackage, FileDescriptor bugreportFd, FileDescriptor screenshotFd, int bugreportMode, IDumpstateListener listener, boolean isScreenshotRequested) { - mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, "startBugreport"); Objects.requireNonNull(callingPackage); Objects.requireNonNull(bugreportFd); Objects.requireNonNull(listener); validateBugreportMode(bugreportMode); + + int callingUid = Binder.getCallingUid(); + enforcePermission(callingPackage, callingUid, bugreportMode + == BugreportParams.BUGREPORT_MODE_TELEPHONY /* checkCarrierPrivileges */); final long identity = Binder.clearCallingIdentity(); try { ensureIsPrimaryUser(); @@ -79,13 +86,6 @@ class BugreportManagerServiceImpl extends IDumpstate.Stub { Binder.restoreCallingIdentity(identity); } - int callingUid = Binder.getCallingUid(); - mAppOps.checkPackage(callingUid, callingPackage); - - if (!mBugreportWhitelistedPackages.contains(callingPackage)) { - throw new SecurityException( - callingPackage + " is not whitelisted to use Bugreport API"); - } synchronized (mLock) { startBugreportLocked(callingUid, callingPackage, bugreportFd, screenshotFd, bugreportMode, listener, isScreenshotRequested); @@ -93,10 +93,11 @@ class BugreportManagerServiceImpl extends IDumpstate.Stub { } @Override - @RequiresPermission(android.Manifest.permission.DUMP) - public void cancelBugreport() { - mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, - "cancelBugreport"); + @RequiresPermission(android.Manifest.permission.DUMP) // or carrier privileges + public void cancelBugreport(int callingUidUnused, String callingPackage) { + int callingUid = Binder.getCallingUid(); + enforcePermission(callingPackage, callingUid, true /* checkCarrierPrivileges */); + synchronized (mLock) { IDumpstate ds = getDumpstateBinderServiceLocked(); if (ds == null) { @@ -104,7 +105,11 @@ class BugreportManagerServiceImpl extends IDumpstate.Stub { return; } try { - ds.cancelBugreport(); + // Note: this may throw SecurityException back out to the caller if they aren't + // allowed to cancel the report, in which case we should NOT be setting ctl.stop, + // since that would unintentionally kill some other app's bugreport, which we + // specifically disallow. + ds.cancelBugreport(callingUid, callingPackage); } catch (RemoteException e) { Slog.e(TAG, "RemoteException in cancelBugreport", e); } @@ -127,6 +132,34 @@ class BugreportManagerServiceImpl extends IDumpstate.Stub { } } + private void enforcePermission( + String callingPackage, int callingUid, boolean checkCarrierPrivileges) { + mAppOps.checkPackage(callingUid, callingPackage); + + // To gain access through the DUMP permission, the OEM has to allow this package explicitly + // via sysconfig and privileged permissions. + if (mBugreportWhitelistedPackages.contains(callingPackage) + && mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) + == PackageManager.PERMISSION_GRANTED) { + return; + } + // For carrier privileges, this can include user-installed apps. This is essentially a + // function of the current active SIM(s) in the device to let carrier apps through. + if (checkCarrierPrivileges + && mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(callingPackage) + == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) { + return; + } + + String message = + callingPackage + + " does not hold the DUMP permission or is not bugreport-whitelisted " + + (checkCarrierPrivileges ? "and does not have carrier privileges " : "") + + "to request a bugreport"; + Slog.w(TAG, message); + throw new SecurityException(message); + } + /** * Validates that the current user is the primary user. * @@ -182,7 +215,7 @@ class BugreportManagerServiceImpl extends IDumpstate.Stub { // lifecycle correctly. If we don't subsequent callers will get // BUGREPORT_ERROR_ANOTHER_REPORT_IN_PROGRESS error. // Note that listener will be notified by the death recipient below. - cancelBugreport(); + cancelBugreport(callingUid, callingPackage); } } diff --git a/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java b/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java index 5c01e43af5a9..fd2d8e1b834b 100644 --- a/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java +++ b/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java @@ -20,6 +20,7 @@ import android.annotation.IntDef; import android.content.Context; import android.content.IntentSender; import android.content.pm.PackageManager; +import android.hardware.boot.V1_0.IBootControl; import android.net.LocalSocket; import android.net.LocalSocketAddress; import android.os.Binder; @@ -73,6 +74,8 @@ public class RecoverySystemService extends IRecoverySystem.Stub implements Reboo static final String INIT_SERVICE_SETUP_BCB = "init.svc.setup-bcb"; @VisibleForTesting static final String INIT_SERVICE_CLEAR_BCB = "init.svc.clear-bcb"; + @VisibleForTesting + static final String AB_UPDATE = "ro.build.ab_update"; private static final Object sRequestLock = new Object(); @@ -177,6 +180,25 @@ public class RecoverySystemService extends IRecoverySystem.Stub implements Reboo return socket; } + /** + * Throws remote exception if there's an error getting the boot control HAL. + * Returns null if the boot control HAL's version is older than V1_2. + */ + public android.hardware.boot.V1_2.IBootControl getBootControl() throws RemoteException { + IBootControl bootControlV10 = IBootControl.getService(true); + if (bootControlV10 == null) { + throw new RemoteException("Failed to get boot control HAL V1_0."); + } + + android.hardware.boot.V1_2.IBootControl bootControlV12 = + android.hardware.boot.V1_2.IBootControl.castFrom(bootControlV10); + if (bootControlV12 == null) { + Slog.w(TAG, "Device doesn't implement boot control HAL V1_2."); + return null; + } + return bootControlV12; + } + public void threadSleep(long millis) throws InterruptedException { Thread.sleep(millis); } @@ -476,6 +498,56 @@ public class RecoverySystemService extends IRecoverySystem.Stub implements Reboo return needClear ? ROR_REQUESTED_NEED_CLEAR : ROR_REQUESTED_SKIP_CLEAR; } + private boolean isAbDevice() { + return "true".equalsIgnoreCase(mInjector.systemPropertiesGet(AB_UPDATE)); + } + + private boolean verifySlotForNextBoot(boolean slotSwitch) { + if (!isAbDevice()) { + Slog.w(TAG, "Device isn't a/b, skipping slot verification."); + return true; + } + + android.hardware.boot.V1_2.IBootControl bootControl; + try { + bootControl = mInjector.getBootControl(); + } catch (RemoteException e) { + Slog.w(TAG, "Failed to get the boot control HAL " + e); + return false; + } + + // TODO(xunchang) enforce boot control V1_2 HAL on devices using multi client RoR + if (bootControl == null) { + Slog.w(TAG, "Cannot get the boot control HAL, skipping slot verification."); + return true; + } + + int current_slot; + int next_active_slot; + try { + current_slot = bootControl.getCurrentSlot(); + if (current_slot != 0 && current_slot != 1) { + throw new IllegalStateException("Current boot slot should be 0 or 1, got " + + current_slot); + } + next_active_slot = bootControl.getActiveBootSlot(); + } catch (RemoteException e) { + Slog.w(TAG, "Failed to query the active slots", e); + return false; + } + + int expected_active_slot = current_slot; + if (slotSwitch) { + expected_active_slot = current_slot == 0 ? 1 : 0; + } + if (next_active_slot != expected_active_slot) { + Slog.w(TAG, "The next active boot slot doesn't match the expected value, " + + "expected " + expected_active_slot + ", got " + next_active_slot); + return false; + } + return true; + } + private boolean rebootWithLskfImpl(String packageName, String reason, boolean slotSwitch) { if (packageName == null) { Slog.w(TAG, "Missing packageName when rebooting with lskf."); @@ -485,7 +557,10 @@ public class RecoverySystemService extends IRecoverySystem.Stub implements Reboo return false; } - // TODO(xunchang) check the slot to boot into, and fail the reboot upon slot mismatch. + if (!verifySlotForNextBoot(slotSwitch)) { + return false; + } + // TODO(xunchang) write the vbmeta digest along with the escrowKey before reboot. if (!mInjector.getLockSettingsService().armRebootEscrow()) { Slog.w(TAG, "Failure to escrow key for reboot"); diff --git a/services/core/java/com/android/server/recoverysystem/RecoverySystemShellCommand.java b/services/core/java/com/android/server/recoverysystem/RecoverySystemShellCommand.java index f20d80d57476..ae71c1a1e444 100644 --- a/services/core/java/com/android/server/recoverysystem/RecoverySystemShellCommand.java +++ b/services/core/java/com/android/server/recoverysystem/RecoverySystemShellCommand.java @@ -76,7 +76,7 @@ public class RecoverySystemShellCommand extends ShellCommand { private int rebootAndApply() throws RemoteException { String packageName = getNextArgRequired(); String rebootReason = getNextArgRequired(); - boolean success = mService.rebootWithLskf(packageName, rebootReason, true); + boolean success = mService.rebootWithLskf(packageName, rebootReason, false); PrintWriter pw = getOutPrintWriter(); // Keep the old message for cts test. pw.printf("%s Reboot and apply status: %s\n", packageName, diff --git a/services/core/java/com/android/server/storage/StorageSessionController.java b/services/core/java/com/android/server/storage/StorageSessionController.java index 0d059ae389e9..8345424712dd 100644 --- a/services/core/java/com/android/server/storage/StorageSessionController.java +++ b/services/core/java/com/android/server/storage/StorageSessionController.java @@ -361,7 +361,11 @@ public final class StorageSessionController { } } + private static boolean isSupportedVolume(VolumeInfo vol) { + return isEmulatedOrPublic(vol) || vol.type == VolumeInfo.TYPE_STUB; + } + private boolean shouldHandle(@Nullable VolumeInfo vol) { - return mIsFuseEnabled && !mIsResetting && (vol == null || isEmulatedOrPublic(vol)); + return mIsFuseEnabled && !mIsResetting && (vol == null || isSupportedVolume(vol)); } } diff --git a/services/core/java/com/android/server/textservices/OWNERS b/services/core/java/com/android/server/textservices/OWNERS new file mode 100644 index 000000000000..9fa9b296706d --- /dev/null +++ b/services/core/java/com/android/server/textservices/OWNERS @@ -0,0 +1,3 @@ +# Bug component: 816455 + +include /services/core/java/com/android/server/inputmethod/OWNERS diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java index 25cd6416d9c8..75277d1c338d 100644 --- a/services/core/java/com/android/server/trust/TrustManagerService.java +++ b/services/core/java/com/android/server/trust/TrustManagerService.java @@ -53,6 +53,7 @@ import android.os.SystemClock; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; +import android.security.Authorization; import android.security.KeyStore; import android.service.trust.TrustAgentService; import android.text.TextUtils; @@ -185,6 +186,8 @@ public class TrustManagerService extends SystemService { private boolean mTrustAgentsCanRun = false; private int mCurrentUser = UserHandle.USER_SYSTEM; + private Authorization mAuthorizationService; + public TrustManagerService(Context context) { super(context); mContext = context; @@ -194,6 +197,7 @@ public class TrustManagerService extends SystemService { mStrongAuthTracker = new StrongAuthTracker(context); mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE); mSettingsObserver = new SettingsObserver(mHandler); + mAuthorizationService = new Authorization(); } @Override @@ -696,11 +700,13 @@ public class TrustManagerService extends SystemService { if (changed) { dispatchDeviceLocked(userId, locked); + mAuthorizationService.onLockScreenEvent(locked, userId, null); KeyStore.getInstance().onUserLockedStateChanged(userId, locked); // Also update the user's profiles who have unified challenge, since they // share the same unlocked state (see {@link #isDeviceLocked(int)}) for (int profileHandle : mUserManager.getEnabledProfileIds(userId)) { if (mLockPatternUtils.isManagedProfileWithUnifiedChallenge(profileHandle)) { + mAuthorizationService.onLockScreenEvent(locked, profileHandle, null); KeyStore.getInstance().onUserLockedStateChanged(profileHandle, locked); } } @@ -1252,6 +1258,7 @@ public class TrustManagerService extends SystemService { mDeviceLockedForUser.put(userId, locked); } + mAuthorizationService.onLockScreenEvent(locked, userId, null); KeyStore.getInstance().onUserLockedStateChanged(userId, locked); if (locked) { diff --git a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java index 7024e67a8204..4e0c0c54923b 100644 --- a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java +++ b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java @@ -123,7 +123,7 @@ public class VcnGatewayConnection extends StateMachine { private static final String DISCONNECT_REASON_UNDERLYING_NETWORK_LOST = "Underlying Network lost"; private static final String DISCONNECT_REASON_TEARDOWN = "teardown() called on VcnTunnel"; - private static final int TOKEN_ANY = Integer.MIN_VALUE; + private static final int TOKEN_ALL = Integer.MIN_VALUE; private static final int NETWORK_LOSS_DISCONNECT_TIMEOUT_SECONDS = 30; private static final int TEARDOWN_TIMEOUT_SECONDS = 5; @@ -139,7 +139,7 @@ public class VcnGatewayConnection extends StateMachine { * * <p>In the Connected state, this MAY indicate a mobility even occurred. * - * @param arg1 The "any" token; this event is always applicable. + * @param arg1 The "all" token; this event is always applicable. * @param obj @NonNull An EventUnderlyingNetworkChangedInfo instance with relevant data. */ private static final int EVENT_UNDERLYING_NETWORK_CHANGED = 1; @@ -175,7 +175,7 @@ public class VcnGatewayConnection extends StateMachine { * <p>Upon receipt of this signal, the state machine will transition from the Retry-timeout * state to the Connecting state. * - * @param arg1 The "any" token; no sessions are active in the RetryTimeoutState. + * @param arg1 The "all" token; no sessions are active in the RetryTimeoutState. */ private static final int EVENT_RETRY_TIMEOUT_EXPIRED = 2; @@ -318,7 +318,7 @@ public class VcnGatewayConnection extends StateMachine { * <p>Upon receipt of this signal, the state machine MUST tear down all active sessions, cancel * any pending work items, and move to the Disconnected state. * - * @param arg1 The "any" token; this signal is always honored. + * @param arg1 The "all" token; this signal is always honored. * @param obj @NonNull An EventDisconnectRequestedInfo instance with relevant data. */ private static final int EVENT_DISCONNECT_REQUESTED = 7; @@ -504,16 +504,9 @@ public class VcnGatewayConnection extends StateMachine { * <p>Once torn down, this VcnTunnel CANNOT be started again. */ public void teardownAsynchronously() { - mUnderlyingNetworkTracker.teardown(); - - // No need to call setInterfaceDown(); the IpSecInterface is being fully torn down. - if (mTunnelIface != null) { - mTunnelIface.close(); - } - sendMessage( EVENT_DISCONNECT_REQUESTED, - TOKEN_ANY, + TOKEN_ALL, new EventDisconnectRequestedInfo(DISCONNECT_REASON_TEARDOWN)); quit(); @@ -521,6 +514,16 @@ public class VcnGatewayConnection extends StateMachine { // is also called asynchronously when a NetworkAgent becomes unwanted } + @Override + protected void onQuitting() { + // No need to call setInterfaceDown(); the IpSecInterface is being fully torn down. + if (mTunnelIface != null) { + mTunnelIface.close(); + } + + mUnderlyingNetworkTracker.teardown(); + } + private class VcnUnderlyingNetworkTrackerCallback implements UnderlyingNetworkTrackerCallback { @Override public void onSelectedUnderlyingNetworkChanged( @@ -530,26 +533,24 @@ public class VcnGatewayConnection extends StateMachine { if (underlying == null) { sendMessageDelayed( EVENT_DISCONNECT_REQUESTED, - TOKEN_ANY, + TOKEN_ALL, new EventDisconnectRequestedInfo(DISCONNECT_REASON_UNDERLYING_NETWORK_LOST), TimeUnit.SECONDS.toMillis(NETWORK_LOSS_DISCONNECT_TIMEOUT_SECONDS)); - return; - } + } else if (getHandler() != null) { + // Cancel any existing disconnect due to loss of underlying network + // getHandler() can return null if the state machine has already quit. Since this is + // called from other classes, this condition must be verified. - // Cancel any existing disconnect due to loss of underlying network - // getHandler() can return null if the state machine has already quit. Since this is - // called - // from other classes, this condition must be verified. - if (getHandler() != null) { getHandler() .removeEqualMessages( EVENT_DISCONNECT_REQUESTED, new EventDisconnectRequestedInfo( DISCONNECT_REASON_UNDERLYING_NETWORK_LOST)); } + sendMessage( EVENT_UNDERLYING_NETWORK_CHANGED, - TOKEN_ANY, + TOKEN_ALL, new EventUnderlyingNetworkChangedInfo(underlying)); } } @@ -594,10 +595,101 @@ public class VcnGatewayConnection extends StateMachine { } private abstract class BaseState extends State { + @Override + public void enter() { + try { + enterState(); + } catch (Exception e) { + Slog.wtf(TAG, "Uncaught exception", e); + sendMessage( + EVENT_DISCONNECT_REQUESTED, + TOKEN_ALL, + new EventDisconnectRequestedInfo( + DISCONNECT_REASON_INTERNAL_ERROR + e.toString())); + } + } + protected void enterState() throws Exception {} + /** + * Top-level processMessage with safeguards to prevent crashing the System Server on non-eng + * builds. + */ + @Override + public boolean processMessage(Message msg) { + try { + processStateMsg(msg); + } catch (Exception e) { + Slog.wtf(TAG, "Uncaught exception", e); + sendMessage( + EVENT_DISCONNECT_REQUESTED, + TOKEN_ALL, + new EventDisconnectRequestedInfo( + DISCONNECT_REASON_INTERNAL_ERROR + e.toString())); + } + + return HANDLED; + } + protected abstract void processStateMsg(Message msg) throws Exception; + + protected void logUnhandledMessage(Message msg) { + // Log as unexpected all known messages, and log all else as unknown. + switch (msg.what) { + case EVENT_UNDERLYING_NETWORK_CHANGED: // Fallthrough + case EVENT_RETRY_TIMEOUT_EXPIRED: // Fallthrough + case EVENT_SESSION_LOST: // Fallthrough + case EVENT_SESSION_CLOSED: // Fallthrough + case EVENT_TRANSFORM_CREATED: // Fallthrough + case EVENT_SETUP_COMPLETED: // Fallthrough + case EVENT_DISCONNECT_REQUESTED: // Fallthrough + case EVENT_TEARDOWN_TIMEOUT_EXPIRED: + logUnexpectedEvent(msg.what); + break; + default: + logWtfUnknownEvent(msg.what); + break; + } + } + + protected void teardownNetwork() { + if (mNetworkAgent != null) { + mNetworkAgent.sendNetworkInfo(buildNetworkInfo(false /* isConnected */)); + mNetworkAgent = null; + } + } + + protected void teardownIke() { + if (mIkeSession != null) { + mIkeSession.close(); + } + } + + protected void handleDisconnectRequested(String msg) { + Slog.v(TAG, "Tearing down. Cause: " + msg); + teardownNetwork(); + teardownIke(); + + if (mIkeSession == null) { + // Already disconnected, go straight to DisconnectedState + transitionTo(mDisconnectedState); + } else { + // Still need to wait for full closure + transitionTo(mDisconnectingState); + } + } + + protected void logUnexpectedEvent(int what) { + Slog.d(TAG, String.format( + "Unexpected event code %d in state %s", what, this.getClass().getSimpleName())); + } + + protected void logWtfUnknownEvent(int what) { + Slog.wtf(TAG, String.format( + "Unknown event code %d in state %s", what, this.getClass().getSimpleName())); + } } + /** * State representing the a disconnected VCN tunnel. * @@ -608,7 +700,29 @@ public class VcnGatewayConnection extends StateMachine { protected void processStateMsg(Message msg) {} } - private abstract class ActiveBaseState extends BaseState {} + private abstract class ActiveBaseState extends BaseState { + /** + * Handles all incoming messages, discarding messages for previous networks. + * + * <p>States that handle mobility events may need to override this method to receive + * messages for all underlying networks. + */ + @Override + public boolean processMessage(Message msg) { + final int token = msg.arg1; + // Only process if a valid token is presented. + if (isValidToken(token)) { + return super.processMessage(msg); + } + + Slog.v(TAG, "Message called with obsolete token: " + token + "; what: " + msg.what); + return HANDLED; + } + + protected boolean isValidToken(int token) { + return (token == TOKEN_ALL || token == mCurrentToken); + } + } /** * Transitive state representing a VCN that is tearing down an IKE session. diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index 0542ef9b09a4..783037f6f171 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -3306,9 +3306,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { } final ActivityStack stack = r.getRootTask(); - final Task task = stack.getDisplayArea().createStack(stack.getWindowingMode(), - stack.getActivityType(), !ON_TOP, ainfo, intent, - false /* createdByOrganizer */); + final Task task = new ActivityStack(this, stack.getDisplayArea().getNextStackId(), + stack.getActivityType(), ainfo, intent, false /* createdByOrganizer */); if (!mRecentTasks.addToBottom(task)) { // The app has too many tasks already and we can't add any more diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplRebootTests.java b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplRebootTests.java index 391611b72dab..5468fba59c10 100644 --- a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplRebootTests.java +++ b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplRebootTests.java @@ -78,7 +78,7 @@ public class OverlayManagerServiceImplRebootTests extends OverlayManagerServiceI } @Test - public void testImmutableEnabledChange() { + public void testImmutableEnabledChange() throws Exception { final OverlayManagerServiceImpl impl = getImpl(); installNewPackage(target(TARGET), USER); installNewPackage(overlay(OVERLAY, TARGET), USER); @@ -106,7 +106,7 @@ public class OverlayManagerServiceImplRebootTests extends OverlayManagerServiceI } @Test - public void testMutableEnabledChangeHasNoEffect() { + public void testMutableEnabledChangeHasNoEffect() throws Exception { final OverlayManagerServiceImpl impl = getImpl(); installNewPackage(target(TARGET), USER); installNewPackage(overlay(OVERLAY, TARGET), USER); @@ -134,7 +134,7 @@ public class OverlayManagerServiceImplRebootTests extends OverlayManagerServiceI } @Test - public void testMutableEnabledToImmutableEnabled() { + public void testMutableEnabledToImmutableEnabled() throws Exception { final OverlayManagerServiceImpl impl = getImpl(); installNewPackage(target(TARGET), USER); installNewPackage(overlay(OVERLAY, TARGET), USER); @@ -178,7 +178,7 @@ public class OverlayManagerServiceImplRebootTests extends OverlayManagerServiceI } @Test - public void testMutablePriorityChange() { + public void testMutablePriorityChange() throws Exception { final OverlayManagerServiceImpl impl = getImpl(); installNewPackage(target(TARGET), USER); installNewPackage(overlay(OVERLAY, TARGET), USER); @@ -218,7 +218,7 @@ public class OverlayManagerServiceImplRebootTests extends OverlayManagerServiceI } @Test - public void testImmutablePriorityChange() { + public void testImmutablePriorityChange() throws Exception { final OverlayManagerServiceImpl impl = getImpl(); installNewPackage(target(TARGET), USER); installNewPackage(overlay(OVERLAY, TARGET), USER); diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java index 4f882ce13dd4..33dbcc0855be 100644 --- a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java +++ b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java @@ -22,11 +22,14 @@ import static android.content.om.OverlayInfo.STATE_MISSING_TARGET; import static android.os.OverlayablePolicy.CONFIG_SIGNATURE; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import static org.testng.Assert.assertThrows; import android.content.om.OverlayInfo; +import android.util.Pair; import androidx.test.runner.AndroidJUnit4; @@ -35,6 +38,7 @@ import org.junit.runner.RunWith; import java.util.List; import java.util.Map; +import java.util.Optional; @RunWith(AndroidJUnit4.class) public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTestsBase { @@ -55,7 +59,7 @@ public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTes private static final String CERT_CONFIG_NOK = "config_certificate_nok"; @Test - public void testGetOverlayInfo() { + public void testGetOverlayInfo() throws Exception { installNewPackage(overlay(OVERLAY, TARGET), USER); final OverlayManagerServiceImpl impl = getImpl(); @@ -67,7 +71,7 @@ public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTes } @Test - public void testGetOverlayInfosForTarget() { + public void testGetOverlayInfosForTarget() throws Exception { installNewPackage(overlay(OVERLAY, TARGET), USER); installNewPackage(overlay(OVERLAY2, TARGET), USER); installNewPackage(overlay(OVERLAY3, TARGET), USER2); @@ -92,7 +96,7 @@ public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTes } @Test - public void testGetOverlayInfosForUser() { + public void testGetOverlayInfosForUser() throws Exception { installNewPackage(target(TARGET), USER); installNewPackage(overlay(OVERLAY, TARGET), USER); installNewPackage(overlay(OVERLAY2, TARGET), USER); @@ -119,7 +123,7 @@ public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTes } @Test - public void testPriority() { + public void testPriority() throws Exception { installNewPackage(overlay(OVERLAY, TARGET), USER); installNewPackage(overlay(OVERLAY2, TARGET), USER); installNewPackage(overlay(OVERLAY3, TARGET), USER); @@ -131,18 +135,21 @@ public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTes assertOverlayInfoForTarget(TARGET, USER, o1, o2, o3); - assertTrue(impl.setLowestPriority(OVERLAY3, USER)); + assertEquals(impl.setLowestPriority(OVERLAY3, USER), + Optional.of(new PackageAndUser(TARGET, USER))); assertOverlayInfoForTarget(TARGET, USER, o3, o1, o2); - assertTrue(impl.setHighestPriority(OVERLAY3, USER)); + assertEquals(impl.setHighestPriority(OVERLAY3, USER), + Optional.of(new PackageAndUser(TARGET, USER))); assertOverlayInfoForTarget(TARGET, USER, o1, o2, o3); - assertTrue(impl.setPriority(OVERLAY, OVERLAY2, USER)); + assertEquals(impl.setPriority(OVERLAY, OVERLAY2, USER), + Optional.of(new PackageAndUser(TARGET, USER))); assertOverlayInfoForTarget(TARGET, USER, o2, o1, o3); } @Test - public void testOverlayInfoStateTransitions() { + public void testOverlayInfoStateTransitions() throws Exception { final OverlayManagerServiceImpl impl = getImpl(); assertNull(impl.getOverlayInfo(OVERLAY, USER)); @@ -153,7 +160,8 @@ public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTes installNewPackage(target, USER); assertState(STATE_DISABLED, OVERLAY, USER); - impl.setEnabled(OVERLAY, true, USER); + assertEquals(impl.setEnabled(OVERLAY, true, USER), + Optional.of(new PackageAndUser(TARGET, USER))); assertState(STATE_ENABLED, OVERLAY, USER); // target upgrades do not change the state of the overlay @@ -168,50 +176,40 @@ public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTes } @Test - public void testOnOverlayPackageUpgraded() { - final FakeListener listener = getListener(); + public void testOnOverlayPackageUpgraded() throws Exception { final FakeDeviceState.PackageBuilder target = target(TARGET); final FakeDeviceState.PackageBuilder overlay = overlay(OVERLAY, TARGET); installNewPackage(target, USER); installNewPackage(overlay, USER); - listener.count = 0; upgradePackage(overlay, USER); - assertEquals(2, listener.count); // upgrade to a version where the overlay has changed its target - // expect once for the old target package, once for the new target package - listener.count = 0; final FakeDeviceState.PackageBuilder overlay2 = overlay(OVERLAY, "some.other.target"); - upgradePackage(overlay2, USER); - assertEquals(3, listener.count); - - listener.count = 0; - upgradePackage(overlay2, USER); - assertEquals(2, listener.count); + final Pair<Optional<PackageAndUser>, Optional<PackageAndUser>> pair = + upgradePackage(overlay2, USER); + assertEquals(pair.first, Optional.of(new PackageAndUser(TARGET, USER))); + assertEquals(pair.second, Optional.of(new PackageAndUser("some.other.target", USER))); } @Test - public void testListener() { + public void testSetEnabledAtVariousConditions() throws Exception { final OverlayManagerServiceImpl impl = getImpl(); - final FakeListener listener = getListener(); - installNewPackage(overlay(OVERLAY, TARGET), USER); - assertEquals(1, listener.count); - listener.count = 0; + assertThrows(OverlayManagerServiceImpl.OperationFailedException.class, + () -> impl.setEnabled(OVERLAY, true, USER)); + // request succeeded, and there was a change that needs to be + // propagated to the rest of the system installNewPackage(target(TARGET), USER); - assertEquals(1, listener.count); - listener.count = 0; - - impl.setEnabled(OVERLAY, true, USER); - assertEquals(1, listener.count); - listener.count = 0; + installNewPackage(overlay(OVERLAY, TARGET), USER); + assertEquals(impl.setEnabled(OVERLAY, true, USER), + Optional.of(new PackageAndUser(TARGET, USER))); - impl.setEnabled(OVERLAY, true, USER); - assertEquals(0, listener.count); + // request succeeded, but nothing changed + assertFalse(impl.setEnabled(OVERLAY, true, USER).isPresent()); } @Test - public void testConfigSignaturePolicyOk() { + public void testConfigSignaturePolicyOk() throws Exception { setConfigSignaturePackageName(CONFIG_SIGNATURE_REFERENCE_PKG); reinitializeImpl(); @@ -229,7 +227,7 @@ public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTes } @Test - public void testConfigSignaturePolicyCertNok() { + public void testConfigSignaturePolicyCertNok() throws Exception { setConfigSignaturePackageName(CONFIG_SIGNATURE_REFERENCE_PKG); reinitializeImpl(); @@ -247,7 +245,7 @@ public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTes } @Test - public void testConfigSignaturePolicyNoConfig() { + public void testConfigSignaturePolicyNoConfig() throws Exception { addPackage(target(CONFIG_SIGNATURE_REFERENCE_PKG).setCertificate(CERT_CONFIG_OK), USER); installNewPackage(target(TARGET), USER); installNewPackage(overlay(OVERLAY, TARGET).setCertificate(CERT_CONFIG_NOK), USER); @@ -262,7 +260,7 @@ public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTes } @Test - public void testConfigSignaturePolicyNoRefPkg() { + public void testConfigSignaturePolicyNoRefPkg() throws Exception { installNewPackage(target(TARGET), USER); installNewPackage(overlay(OVERLAY, TARGET).setCertificate(CERT_CONFIG_NOK), USER); @@ -276,7 +274,7 @@ public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTes } @Test - public void testConfigSignaturePolicyRefPkgNotSystem() { + public void testConfigSignaturePolicyRefPkgNotSystem() throws Exception { setConfigSignaturePackageName(CONFIG_SIGNATURE_REFERENCE_PKG); reinitializeImpl(); diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java index 006dda0f80e3..2c477c897b30 100644 --- a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java +++ b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java @@ -16,6 +16,8 @@ package com.android.server.om; +import static com.android.server.om.OverlayManagerServiceImpl.OperationFailedException; + import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; @@ -30,6 +32,7 @@ import android.content.pm.PackageInfo; import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; +import android.util.Pair; import androidx.annotation.Nullable; @@ -43,13 +46,13 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.stream.Collectors; /** Base class for creating {@link OverlayManagerServiceImplTests} tests. */ class OverlayManagerServiceImplTestsBase { private OverlayManagerServiceImpl mImpl; private FakeDeviceState mState; - private FakeListener mListener; private FakePackageManagerHelper mPackageManager; private FakeIdmapDaemon mIdmapDaemon; private OverlayConfig mOverlayConfig; @@ -58,7 +61,6 @@ class OverlayManagerServiceImplTestsBase { @Before public void setUp() { mState = new FakeDeviceState(); - mListener = new FakeListener(); mPackageManager = new FakePackageManagerHelper(mState); mIdmapDaemon = new FakeIdmapDaemon(mState); mOverlayConfig = mock(OverlayConfig.class); @@ -73,18 +75,13 @@ class OverlayManagerServiceImplTestsBase { new IdmapManager(mIdmapDaemon, mPackageManager), new OverlayManagerSettings(), mOverlayConfig, - new String[0], - mListener); + new String[0]); } OverlayManagerServiceImpl getImpl() { return mImpl; } - FakeListener getListener() { - return mListener; - } - FakeIdmapDaemon getIdmapd() { return mIdmapDaemon; } @@ -155,7 +152,8 @@ class OverlayManagerServiceImplTestsBase { * * @throws IllegalStateException if the package is currently installed */ - void installNewPackage(FakeDeviceState.PackageBuilder pkg, int userId) { + void installNewPackage(FakeDeviceState.PackageBuilder pkg, int userId) + throws OperationFailedException { if (mState.select(pkg.packageName, userId) != null) { throw new IllegalStateException("package " + pkg.packageName + " already installed"); } @@ -176,23 +174,30 @@ class OverlayManagerServiceImplTestsBase { * {@link android.content.Intent#ACTION_PACKAGE_ADDED} broadcast with the * {@link android.content.Intent#EXTRA_REPLACING} extra. * + * @return the two Optional<PackageAndUser> objects from starting and finishing the upgrade + * * @throws IllegalStateException if the package is not currently installed */ - void upgradePackage(FakeDeviceState.PackageBuilder pkg, int userId) { + Pair<Optional<PackageAndUser>, Optional<PackageAndUser>> upgradePackage( + FakeDeviceState.PackageBuilder pkg, int userId) throws OperationFailedException { final FakeDeviceState.Package replacedPackage = mState.select(pkg.packageName, userId); if (replacedPackage == null) { throw new IllegalStateException("package " + pkg.packageName + " not installed"); } + Optional<PackageAndUser> opt1 = Optional.empty(); if (replacedPackage.targetPackageName != null) { - mImpl.onOverlayPackageReplacing(pkg.packageName, userId); + opt1 = mImpl.onOverlayPackageReplacing(pkg.packageName, userId); } mState.add(pkg, userId); + Optional<PackageAndUser> opt2; if (pkg.targetPackage == null) { - mImpl.onTargetPackageReplaced(pkg.packageName, userId); + opt2 = mImpl.onTargetPackageReplaced(pkg.packageName, userId); } else { - mImpl.onOverlayPackageReplaced(pkg.packageName, userId); + opt2 = mImpl.onOverlayPackageReplaced(pkg.packageName, userId); } + + return Pair.create(opt1, opt2); } /** @@ -203,7 +208,7 @@ class OverlayManagerServiceImplTestsBase { * * @throws IllegalStateException if the package is not currently installed */ - void uninstallPackage(String packageName, int userId) { + void uninstallPackage(String packageName, int userId) throws OperationFailedException { final FakeDeviceState.Package pkg = mState.select(packageName, userId); if (pkg == null) { throw new IllegalStateException("package " + packageName+ " not installed"); @@ -485,12 +490,4 @@ class OverlayManagerServiceImplTestsBase { } } } - - static class FakeListener implements OverlayManagerServiceImpl.OverlayChangeListener { - public int count; - - public void onOverlaysChanged(@NonNull String targetPackage, int userId) { - count++; - } - } } diff --git a/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTest.java b/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTest.java index b07b8fa059d1..9b8a2a82c6df 100644 --- a/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTest.java @@ -35,6 +35,7 @@ import static org.mockito.Mockito.when; import android.content.Context; import android.content.IntentSender; import android.content.pm.PackageManager; +import android.hardware.boot.V1_2.IBootControl; import android.os.Handler; import android.os.IPowerManager; import android.os.IRecoverySystemProgressListener; @@ -68,12 +69,13 @@ public class RecoverySystemServiceTest { private IThermalService mIThermalService; private FileWriter mUncryptUpdateFileWriter; private LockSettingsInternal mLockSettingsInternal; + private IBootControl mIBootControl; private static final String FAKE_OTA_PACKAGE_NAME = "fake.ota.package"; private static final String FAKE_OTHER_PACKAGE_NAME = "fake.other.package"; @Before - public void setup() { + public void setup() throws Exception { mContext = mock(Context.class); mSystemProperties = new RecoverySystemServiceTestable.FakeSystemProperties(); mUncryptSocket = mock(RecoverySystemService.UncryptSocket.class); @@ -88,8 +90,13 @@ public class RecoverySystemServiceTest { PowerManager powerManager = new PowerManager(mock(Context.class), mIPowerManager, mIThermalService, new Handler(looper)); + mIBootControl = mock(IBootControl.class); + when(mIBootControl.getCurrentSlot()).thenReturn(0); + when(mIBootControl.getActiveBootSlot()).thenReturn(1); + mRecoverySystemService = new RecoverySystemServiceTestable(mContext, mSystemProperties, - powerManager, mUncryptUpdateFileWriter, mUncryptSocket, mLockSettingsInternal); + powerManager, mUncryptUpdateFileWriter, mUncryptSocket, mLockSettingsInternal, + mIBootControl); } @Test @@ -332,6 +339,15 @@ public class RecoverySystemServiceTest { verify(mIPowerManager).reboot(anyBoolean(), eq("ab-update"), anyBoolean()); } + + @Test + public void rebootWithLskf_slotMismatch_Failure() throws Exception { + assertThat(mRecoverySystemService.requestLskf(FAKE_OTA_PACKAGE_NAME, null), is(true)); + mRecoverySystemService.onPreparedForReboot(true); + assertThat(mRecoverySystemService.rebootWithLskf(FAKE_OTA_PACKAGE_NAME, "ab-update", false), + is(false)); + } + @Test public void rebootWithLskf_withoutPrepare_Failure() throws Exception { assertThat(mRecoverySystemService.rebootWithLskf(FAKE_OTA_PACKAGE_NAME, null, true), diff --git a/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTestable.java b/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTestable.java index 131e4f321a6c..0727e5adb9ca 100644 --- a/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTestable.java +++ b/services/tests/servicestests/src/com/android/server/recoverysystem/RecoverySystemServiceTestable.java @@ -17,6 +17,7 @@ package com.android.server.recoverysystem; import android.content.Context; +import android.hardware.boot.V1_2.IBootControl; import android.os.PowerManager; import com.android.internal.widget.LockSettingsInternal; @@ -30,16 +31,19 @@ public class RecoverySystemServiceTestable extends RecoverySystemService { private final FileWriter mUncryptPackageFileWriter; private final UncryptSocket mUncryptSocket; private final LockSettingsInternal mLockSettingsInternal; + private final IBootControl mIBootControl; MockInjector(Context context, FakeSystemProperties systemProperties, PowerManager powerManager, FileWriter uncryptPackageFileWriter, - UncryptSocket uncryptSocket, LockSettingsInternal lockSettingsInternal) { + UncryptSocket uncryptSocket, LockSettingsInternal lockSettingsInternal, + IBootControl bootControl) { super(context); mSystemProperties = systemProperties; mPowerManager = powerManager; mUncryptPackageFileWriter = uncryptPackageFileWriter; mUncryptSocket = uncryptSocket; mLockSettingsInternal = lockSettingsInternal; + mIBootControl = bootControl; } @Override @@ -85,13 +89,19 @@ public class RecoverySystemServiceTestable extends RecoverySystemService { public LockSettingsInternal getLockSettingsService() { return mLockSettingsInternal; } + + @Override + public IBootControl getBootControl() { + return mIBootControl; + } } RecoverySystemServiceTestable(Context context, FakeSystemProperties systemProperties, PowerManager powerManager, FileWriter uncryptPackageFileWriter, - UncryptSocket uncryptSocket, LockSettingsInternal lockSettingsInternal) { + UncryptSocket uncryptSocket, LockSettingsInternal lockSettingsInternal, + IBootControl bootControl) { super(new MockInjector(context, systemProperties, powerManager, uncryptPackageFileWriter, - uncryptSocket, lockSettingsInternal)); + uncryptSocket, lockSettingsInternal, bootControl)); } public static class FakeSystemProperties { @@ -102,6 +112,8 @@ public class RecoverySystemServiceTestable extends RecoverySystemService { || RecoverySystemService.INIT_SERVICE_SETUP_BCB.equals(key) || RecoverySystemService.INIT_SERVICE_CLEAR_BCB.equals(key)) { return null; + } else if (RecoverySystemService.AB_UPDATE.equals(key)) { + return "true"; } else { throw new IllegalArgumentException("unexpected test key: " + key); } diff --git a/services/tests/servicestests/src/com/android/server/textservices/OWNERS b/services/tests/servicestests/src/com/android/server/textservices/OWNERS new file mode 100644 index 000000000000..0471e29a25cd --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/textservices/OWNERS @@ -0,0 +1,3 @@ +# Bug component: 816455 + +include /services/core/java/com/android/server/textservices/OWNERS diff --git a/telephony/java/android/telephony/AccessNetworkConstants.java b/telephony/java/android/telephony/AccessNetworkConstants.java index d01297147fdb..f6d18fcd9ab3 100644 --- a/telephony/java/android/telephony/AccessNetworkConstants.java +++ b/telephony/java/android/telephony/AccessNetworkConstants.java @@ -18,10 +18,7 @@ package android.telephony; import android.annotation.IntDef; import android.annotation.SystemApi; -import android.hardware.radio.V1_1.GeranBands; import android.hardware.radio.V1_5.AccessNetwork; -import android.hardware.radio.V1_5.EutranBands; -import android.hardware.radio.V1_5.UtranBands; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -117,52 +114,120 @@ public final class AccessNetworkConstants { * http://www.etsi.org/deliver/etsi_ts/145000_145099/145005/14.00.00_60/ts_145005v140000p.pdf */ public static final class GeranBand { - public static final int BAND_T380 = GeranBands.BAND_T380; - public static final int BAND_T410 = GeranBands.BAND_T410; - public static final int BAND_450 = GeranBands.BAND_450; - public static final int BAND_480 = GeranBands.BAND_480; - public static final int BAND_710 = GeranBands.BAND_710; - public static final int BAND_750 = GeranBands.BAND_750; - public static final int BAND_T810 = GeranBands.BAND_T810; - public static final int BAND_850 = GeranBands.BAND_850; - public static final int BAND_P900 = GeranBands.BAND_P900; - public static final int BAND_E900 = GeranBands.BAND_E900; - public static final int BAND_R900 = GeranBands.BAND_R900; - public static final int BAND_DCS1800 = GeranBands.BAND_DCS1800; - public static final int BAND_PCS1900 = GeranBands.BAND_PCS1900; - public static final int BAND_ER900 = GeranBands.BAND_ER900; + public static final int BAND_T380 = android.hardware.radio.V1_1.GeranBands.BAND_T380; + public static final int BAND_T410 = android.hardware.radio.V1_1.GeranBands.BAND_T410; + public static final int BAND_450 = android.hardware.radio.V1_1.GeranBands.BAND_450; + public static final int BAND_480 = android.hardware.radio.V1_1.GeranBands.BAND_480; + public static final int BAND_710 = android.hardware.radio.V1_1.GeranBands.BAND_710; + public static final int BAND_750 = android.hardware.radio.V1_1.GeranBands.BAND_750; + public static final int BAND_T810 = android.hardware.radio.V1_1.GeranBands.BAND_T810; + public static final int BAND_850 = android.hardware.radio.V1_1.GeranBands.BAND_850; + public static final int BAND_P900 = android.hardware.radio.V1_1.GeranBands.BAND_P900; + public static final int BAND_E900 = android.hardware.radio.V1_1.GeranBands.BAND_E900; + public static final int BAND_R900 = android.hardware.radio.V1_1.GeranBands.BAND_R900; + public static final int BAND_DCS1800 = android.hardware.radio.V1_1.GeranBands.BAND_DCS1800; + public static final int BAND_PCS1900 = android.hardware.radio.V1_1.GeranBands.BAND_PCS1900; + public static final int BAND_ER900 = android.hardware.radio.V1_1.GeranBands.BAND_ER900; + + /** + * GeranBand + * + * @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = {"BAND_"}, + value = {BAND_T380, + BAND_T410, + BAND_450, + BAND_480, + BAND_710, + BAND_750, + BAND_T810, + BAND_850, + BAND_P900, + BAND_E900, + BAND_R900, + BAND_DCS1800, + BAND_PCS1900, + BAND_ER900}) + + public @interface GeranBands {} /** @hide */ private GeranBand() {} } /** + * 3GPP TS 45.005 Table 2-1 Dynamically mapped ARFCN. + * 3GPP TS 45.005 Table 2-2 Fixed designation of ARFCN. + * @hide + */ + enum GeranBandArfcnFrequency { + + // Dynamically mapped ARFCN +// GERAN_ARFCN_FREQUENCY_BAND_T380(GeranBand.BAND_T380, 380.2, 0), +// GERAN_ARFCN_FREQUENCY_BAND_T410(GeranBand.BAND_T410, 410.2, 0), +// GERAN_ARFCN_FREQUENCY_BAND_710(GeranBand.BAND_710, 698, 0), +// GERAN_ARFCN_FREQUENCY_BAND_750(GeranBand.BAND_750, 747, 438, 30), +// GERAN_ARFCN_FREQUENCY_BAND_T810(GeranBand.BAND_T810, 806, 350), + // Fixed designation of ARFCN + GERAN_ARFCN_FREQUENCY_BAND_450(GeranBand.BAND_450, 450600, 259, 259, 293, 10), + GERAN_ARFCN_FREQUENCY_BAND_480(GeranBand.BAND_480, 479000, 306, 306, 340, 10), + GERAN_ARFCN_FREQUENCY_BAND_850(GeranBand.BAND_850, 824200, 128, 128, 251, 45), + GERAN_ARFCN_FREQUENCY_BAND_DCS1800(GeranBand.BAND_DCS1800, 1710200, 512, 512, 885, 95), + GERAN_ARFCN_FREQUENCY_BAND_PCS1900(GeranBand.BAND_PCS1900, 1850200, 512, 512, 810, 80), + GERAN_ARFCN_FREQUENCY_BAND_E900_1(GeranBand.BAND_E900, 890000, 0, 0, 124, 45), + GERAN_ARFCN_FREQUENCY_BAND_E900_2(GeranBand.BAND_E900, 890000, 1024, 975, 1023, 45), + GERAN_ARFCN_FREQUENCY_BAND_R900_1(GeranBand.BAND_R900, 890000, 0, 0, 124, 45), + GERAN_ARFCN_FREQUENCY_BAND_R900_2(GeranBand.BAND_R900, 890000, 1024, 955, 1023, 45), + GERAN_ARFCN_FREQUENCY_BAND_P900(GeranBand.BAND_P900, 890000, 0, 1, 124, 45), + GERAN_ARFCN_FREQUENCY_BAND_ER900_1(GeranBand.BAND_ER900, 890000, 0, 0, 124, 45), + GERAN_ARFCN_FREQUENCY_BAND_ER900_2(GeranBand.BAND_ER900, 890000, 1024, 940, 1023, 1024); + + GeranBandArfcnFrequency(int band, int uplinkFrequencyFirstKhz, int arfcnOffset, + int arfcnRangeFirst, int arfcnRangeLast, int downlinkOffset) { + this.band = band; + this.uplinkFrequencyFirst = uplinkFrequencyFirstKhz; + this.arfcnOffset = arfcnOffset; + this.arfcnRangeFirst = arfcnRangeFirst; + this.arfcnRangeLast = arfcnRangeLast; + this.downlinkOffset = downlinkOffset; + } + + int band; + int uplinkFrequencyFirst; + int arfcnOffset; + int arfcnRangeFirst; + int arfcnRangeLast; + int downlinkOffset; + } + + /** * Frequency bands for UTRAN. * http://www.etsi.org/deliver/etsi_ts/125100_125199/125104/13.03.00_60/ts_125104v130p.pdf */ public static final class UtranBand { - public static final int BAND_1 = UtranBands.BAND_1; - public static final int BAND_2 = UtranBands.BAND_2; - public static final int BAND_3 = UtranBands.BAND_3; - public static final int BAND_4 = UtranBands.BAND_4; - public static final int BAND_5 = UtranBands.BAND_5; - public static final int BAND_6 = UtranBands.BAND_6; - public static final int BAND_7 = UtranBands.BAND_7; - public static final int BAND_8 = UtranBands.BAND_8; - public static final int BAND_9 = UtranBands.BAND_9; - public static final int BAND_10 = UtranBands.BAND_10; - public static final int BAND_11 = UtranBands.BAND_11; - public static final int BAND_12 = UtranBands.BAND_12; - public static final int BAND_13 = UtranBands.BAND_13; - public static final int BAND_14 = UtranBands.BAND_14; + public static final int BAND_1 = android.hardware.radio.V1_5.UtranBands.BAND_1; + public static final int BAND_2 = android.hardware.radio.V1_5.UtranBands.BAND_2; + public static final int BAND_3 = android.hardware.radio.V1_5.UtranBands.BAND_3; + public static final int BAND_4 = android.hardware.radio.V1_5.UtranBands.BAND_4; + public static final int BAND_5 = android.hardware.radio.V1_5.UtranBands.BAND_5; + public static final int BAND_6 = android.hardware.radio.V1_5.UtranBands.BAND_6; + public static final int BAND_7 = android.hardware.radio.V1_5.UtranBands.BAND_7; + public static final int BAND_8 = android.hardware.radio.V1_5.UtranBands.BAND_8; + public static final int BAND_9 = android.hardware.radio.V1_5.UtranBands.BAND_9; + public static final int BAND_10 = android.hardware.radio.V1_5.UtranBands.BAND_10; + public static final int BAND_11 = android.hardware.radio.V1_5.UtranBands.BAND_11; + public static final int BAND_12 = android.hardware.radio.V1_5.UtranBands.BAND_12; + public static final int BAND_13 = android.hardware.radio.V1_5.UtranBands.BAND_13; + public static final int BAND_14 = android.hardware.radio.V1_5.UtranBands.BAND_14; // band 15, 16, 17, 18 are reserved - public static final int BAND_19 = UtranBands.BAND_19; - public static final int BAND_20 = UtranBands.BAND_20; - public static final int BAND_21 = UtranBands.BAND_21; - public static final int BAND_22 = UtranBands.BAND_22; + public static final int BAND_19 = android.hardware.radio.V1_5.UtranBands.BAND_19; + public static final int BAND_20 = android.hardware.radio.V1_5.UtranBands.BAND_20; + public static final int BAND_21 = android.hardware.radio.V1_5.UtranBands.BAND_21; + public static final int BAND_22 = android.hardware.radio.V1_5.UtranBands.BAND_22; // band 23, 24 are reserved - public static final int BAND_25 = UtranBands.BAND_25; - public static final int BAND_26 = UtranBands.BAND_26; + public static final int BAND_25 = android.hardware.radio.V1_5.UtranBands.BAND_25; + public static final int BAND_26 = android.hardware.radio.V1_5.UtranBands.BAND_26; // Frequency bands for TD-SCDMA. Defined in 3GPP TS 25.102, Table 5.2. @@ -171,115 +236,423 @@ public final class AccessNetworkConstants { * 1900 - 1920 MHz: Uplink and downlink transmission * 2010 - 2025 MHz: Uplink and downlink transmission */ - public static final int BAND_A = UtranBands.BAND_A; + public static final int BAND_A = android.hardware.radio.V1_5.UtranBands.BAND_A; /** * Band B * 1850 - 1910 MHz: Uplink and downlink transmission * 1930 - 1990 MHz: Uplink and downlink transmission */ - public static final int BAND_B = UtranBands.BAND_B; + public static final int BAND_B = android.hardware.radio.V1_5.UtranBands.BAND_B; /** * Band C * 1910 - 1930 MHz: Uplink and downlink transmission */ - public static final int BAND_C = UtranBands.BAND_C; + public static final int BAND_C = android.hardware.radio.V1_5.UtranBands.BAND_C; /** * Band D * 2570 - 2620 MHz: Uplink and downlink transmission */ - public static final int BAND_D = UtranBands.BAND_D; + public static final int BAND_D = android.hardware.radio.V1_5.UtranBands.BAND_D; /** * Band E * 2300—2400 MHz: Uplink and downlink transmission */ - public static final int BAND_E = UtranBands.BAND_E; + public static final int BAND_E = android.hardware.radio.V1_5.UtranBands.BAND_E; /** * Band F * 1880 - 1920 MHz: Uplink and downlink transmission */ - public static final int BAND_F = UtranBands.BAND_F; + public static final int BAND_F = android.hardware.radio.V1_5.UtranBands.BAND_F; + + /** + * UtranBand + * + * @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = {"BAND_"}, + value = {BAND_1, + BAND_2, + BAND_3, + BAND_4, + BAND_5, + BAND_6, + BAND_7, + BAND_8, + BAND_9, + BAND_10, + BAND_11, + BAND_12, + BAND_13, + BAND_14, + BAND_19, + BAND_20, + BAND_21, + BAND_22, + BAND_25, + BAND_26, + BAND_A, + BAND_B, + BAND_C, + BAND_D, + BAND_E, + BAND_F}) + + public @interface UtranBands {} /** @hide */ private UtranBand() {} } /** + * 3GPP TS 25.101, Table 5.1 UARFCN definition (general) + * 3GPP TS 25.102, Table 5.2 UTRA Absolute Radio Frequency Channel Number 1.28 Mcps TDD Option. + * + * @hide + */ + enum UtranBandArfcnFrequency { + + UTRAN_ARFCN_FREQUENCY_BAND_1(UtranBand.BAND_1, 0, 10562, 10838, 0, 9612, 9888), + UTRAN_ARFCN_FREQUENCY_BAND_2(UtranBand.BAND_2, 0, 9662, 9938, 0, 9262, 9538), + UTRAN_ARFCN_FREQUENCY_BAND_3(UtranBand.BAND_3, 1575000, 1162, 1513, 1525000, 937, 1288), + UTRAN_ARFCN_FREQUENCY_BAND_4(UtranBand.BAND_4, 1805000, 1537, 1738, 1450000, 1312, 1513), + UTRAN_ARFCN_FREQUENCY_BAND_5(UtranBand.BAND_5, 0, 4357, 4458, 0, 4132, 4233), + UTRAN_ARFCN_FREQUENCY_BAND_6(UtranBand.BAND_6, 0, 4387, 4413, 0, 4162, 4188), + UTRAN_ARFCN_FREQUENCY_BAND_7(UtranBand.BAND_7, 2175000, 2237, 2563, 2100000, 2012, 2338), + UTRAN_ARFCN_FREQUENCY_BAND_8(UtranBand.BAND_8, 340000, 2937, 3088, 340000, 2712, 2863), + UTRAN_ARFCN_FREQUENCY_BAND_9(UtranBand.BAND_9, 0, 9327, 9837, 0, 8762, 8912), + UTRAN_ARFCN_FREQUENCY_BAND_10(UtranBand.BAND_10, 1490000, 3112, 3388, 1135000, 2887, 3163), + UTRAN_ARFCN_FREQUENCY_BAND_11(UtranBand.BAND_11, 736000, 3712, 3787, 733000, 3487, 3562), + UTRAN_ARFCN_FREQUENCY_BAND_12(UtranBand.BAND_12, -37000, 3842, 3903, -22000, 3617, 3678), + UTRAN_ARFCN_FREQUENCY_BAND_13(UtranBand.BAND_13, -55000, 4017, 4043, 21000, 3792, 3818), + UTRAN_ARFCN_FREQUENCY_BAND_14(UtranBand.BAND_14, -63000, 4117, 4143, 12000, 3892, 3918), + UTRAN_ARFCN_FREQUENCY_BAND_19(UtranBand.BAND_19, 735000, 712, 763, 770000, 312, 363), + UTRAN_ARFCN_FREQUENCY_BAND_20(UtranBand.BAND_20, -109000, 4512, 4638, -23000, 4287, 4413), + UTRAN_ARFCN_FREQUENCY_BAND_21(UtranBand.BAND_21, 1326000, 862, 912, 1358000, 462, 512), + UTRAN_ARFCN_FREQUENCY_BAND_22(UtranBand.BAND_22, 2580000, 4662, 5038, 2525000, 4437, 4813), + UTRAN_ARFCN_FREQUENCY_BAND_25(UtranBand.BAND_25, 910000, 5112, 5413, 875000, 4887, 5188), + UTRAN_ARFCN_FREQUENCY_BAND_A(UtranBand.BAND_A, 0, 10054, 10121, 0, 9504, 9596), + UTRAN_ARFCN_FREQUENCY_BAND_B(UtranBand.BAND_B, 0, 9654, 9946, 0, 9254, 9546), + UTRAN_ARFCN_FREQUENCY_BAND_C(UtranBand.BAND_C, 0, 0, 0, 0, 9554, 9646), + UTRAN_ARFCN_FREQUENCY_BAND_D(UtranBand.BAND_D, 0, 0, 0, 0, 12854, 13096), + UTRAN_ARFCN_FREQUENCY_BAND_E(UtranBand.BAND_E, 0, 0, 0, 0, 11504, 11996), + UTRAN_ARFCN_FREQUENCY_BAND_F(UtranBand.BAND_F, 0, 0, 0, 0, 9404, 9596); + + UtranBandArfcnFrequency(int band, int downlinkOffsetKhz, int downlinkRangeFirst, + int downlinkRangeLast, int uplinkOffsetKhz, int uplinkRangeFirst, + int uplinkRangeLast) { + this.band = band; + this.downlinkOffset = downlinkOffsetKhz; + this.downlinkRangeFirst = downlinkRangeFirst; + this.downlinkRangeLast = downlinkRangeLast; + this.uplinkOffset = uplinkOffsetKhz; + this.uplinkRangeFirst = uplinkRangeFirst; + this.uplinkRangeLast = uplinkRangeLast; + } + + int band; + int downlinkOffset; + int downlinkRangeFirst; + int downlinkRangeLast; + int uplinkOffset; + int uplinkRangeFirst; + int uplinkRangeLast; + } + + /** * Frequency bands for EUTRAN. * 3GPP TS 36.101, Version 16.4.0, Table 5.5: Operating bands * https://www.etsi.org/deliver/etsi_ts/136100_136199/136101/15.09.00_60/ts_136101v150900p.pdf */ public static final class EutranBand { - public static final int BAND_1 = EutranBands.BAND_1; - public static final int BAND_2 = EutranBands.BAND_2; - public static final int BAND_3 = EutranBands.BAND_3; - public static final int BAND_4 = EutranBands.BAND_4; - public static final int BAND_5 = EutranBands.BAND_5; - public static final int BAND_6 = EutranBands.BAND_6; - public static final int BAND_7 = EutranBands.BAND_7; - public static final int BAND_8 = EutranBands.BAND_8; - public static final int BAND_9 = EutranBands.BAND_9; - public static final int BAND_10 = EutranBands.BAND_10; - public static final int BAND_11 = EutranBands.BAND_11; - public static final int BAND_12 = EutranBands.BAND_12; - public static final int BAND_13 = EutranBands.BAND_13; - public static final int BAND_14 = EutranBands.BAND_14; - public static final int BAND_17 = EutranBands.BAND_17; - public static final int BAND_18 = EutranBands.BAND_18; - public static final int BAND_19 = EutranBands.BAND_19; - public static final int BAND_20 = EutranBands.BAND_20; - public static final int BAND_21 = EutranBands.BAND_21; - public static final int BAND_22 = EutranBands.BAND_22; - public static final int BAND_23 = EutranBands.BAND_23; - public static final int BAND_24 = EutranBands.BAND_24; - public static final int BAND_25 = EutranBands.BAND_25; - public static final int BAND_26 = EutranBands.BAND_26; - public static final int BAND_27 = EutranBands.BAND_27; - public static final int BAND_28 = EutranBands.BAND_28; - public static final int BAND_30 = EutranBands.BAND_30; - public static final int BAND_31 = EutranBands.BAND_31; - public static final int BAND_33 = EutranBands.BAND_33; - public static final int BAND_34 = EutranBands.BAND_34; - public static final int BAND_35 = EutranBands.BAND_35; - public static final int BAND_36 = EutranBands.BAND_36; - public static final int BAND_37 = EutranBands.BAND_37; - public static final int BAND_38 = EutranBands.BAND_38; - public static final int BAND_39 = EutranBands.BAND_39; - public static final int BAND_40 = EutranBands.BAND_40; - public static final int BAND_41 = EutranBands.BAND_41; - public static final int BAND_42 = EutranBands.BAND_42; - public static final int BAND_43 = EutranBands.BAND_43; - public static final int BAND_44 = EutranBands.BAND_44; - public static final int BAND_45 = EutranBands.BAND_45; - public static final int BAND_46 = EutranBands.BAND_46; - public static final int BAND_47 = EutranBands.BAND_47; - public static final int BAND_48 = EutranBands.BAND_48; - public static final int BAND_49 = EutranBands.BAND_49; - public static final int BAND_50 = EutranBands.BAND_50; - public static final int BAND_51 = EutranBands.BAND_51; - public static final int BAND_52 = EutranBands.BAND_52; - public static final int BAND_53 = EutranBands.BAND_53; - public static final int BAND_65 = EutranBands.BAND_65; - public static final int BAND_66 = EutranBands.BAND_66; - public static final int BAND_68 = EutranBands.BAND_68; - public static final int BAND_70 = EutranBands.BAND_70; - public static final int BAND_71 = EutranBands.BAND_71; - public static final int BAND_72 = EutranBands.BAND_72; - public static final int BAND_73 = EutranBands.BAND_73; - public static final int BAND_74 = EutranBands.BAND_74; - public static final int BAND_85 = EutranBands.BAND_85; - public static final int BAND_87 = EutranBands.BAND_87; - public static final int BAND_88 = EutranBands.BAND_88; + public static final int BAND_1 = android.hardware.radio.V1_5.EutranBands.BAND_1; + public static final int BAND_2 = android.hardware.radio.V1_5.EutranBands.BAND_2; + public static final int BAND_3 = android.hardware.radio.V1_5.EutranBands.BAND_3; + public static final int BAND_4 = android.hardware.radio.V1_5.EutranBands.BAND_4; + public static final int BAND_5 = android.hardware.radio.V1_5.EutranBands.BAND_5; + public static final int BAND_6 = android.hardware.radio.V1_5.EutranBands.BAND_6; + public static final int BAND_7 = android.hardware.radio.V1_5.EutranBands.BAND_7; + public static final int BAND_8 = android.hardware.radio.V1_5.EutranBands.BAND_8; + public static final int BAND_9 = android.hardware.radio.V1_5.EutranBands.BAND_9; + public static final int BAND_10 = android.hardware.radio.V1_5.EutranBands.BAND_10; + public static final int BAND_11 = android.hardware.radio.V1_5.EutranBands.BAND_11; + public static final int BAND_12 = android.hardware.radio.V1_5.EutranBands.BAND_12; + public static final int BAND_13 = android.hardware.radio.V1_5.EutranBands.BAND_13; + public static final int BAND_14 = android.hardware.radio.V1_5.EutranBands.BAND_14; + public static final int BAND_17 = android.hardware.radio.V1_5.EutranBands.BAND_17; + public static final int BAND_18 = android.hardware.radio.V1_5.EutranBands.BAND_18; + public static final int BAND_19 = android.hardware.radio.V1_5.EutranBands.BAND_19; + public static final int BAND_20 = android.hardware.radio.V1_5.EutranBands.BAND_20; + public static final int BAND_21 = android.hardware.radio.V1_5.EutranBands.BAND_21; + public static final int BAND_22 = android.hardware.radio.V1_5.EutranBands.BAND_22; + public static final int BAND_23 = android.hardware.radio.V1_5.EutranBands.BAND_23; + public static final int BAND_24 = android.hardware.radio.V1_5.EutranBands.BAND_24; + public static final int BAND_25 = android.hardware.radio.V1_5.EutranBands.BAND_25; + public static final int BAND_26 = android.hardware.radio.V1_5.EutranBands.BAND_26; + public static final int BAND_27 = android.hardware.radio.V1_5.EutranBands.BAND_27; + public static final int BAND_28 = android.hardware.radio.V1_5.EutranBands.BAND_28; + public static final int BAND_30 = android.hardware.radio.V1_5.EutranBands.BAND_30; + public static final int BAND_31 = android.hardware.radio.V1_5.EutranBands.BAND_31; + public static final int BAND_33 = android.hardware.radio.V1_5.EutranBands.BAND_33; + public static final int BAND_34 = android.hardware.radio.V1_5.EutranBands.BAND_34; + public static final int BAND_35 = android.hardware.radio.V1_5.EutranBands.BAND_35; + public static final int BAND_36 = android.hardware.radio.V1_5.EutranBands.BAND_36; + public static final int BAND_37 = android.hardware.radio.V1_5.EutranBands.BAND_37; + public static final int BAND_38 = android.hardware.radio.V1_5.EutranBands.BAND_38; + public static final int BAND_39 = android.hardware.radio.V1_5.EutranBands.BAND_39; + public static final int BAND_40 = android.hardware.radio.V1_5.EutranBands.BAND_40; + public static final int BAND_41 = android.hardware.radio.V1_5.EutranBands.BAND_41; + public static final int BAND_42 = android.hardware.radio.V1_5.EutranBands.BAND_42; + public static final int BAND_43 = android.hardware.radio.V1_5.EutranBands.BAND_43; + public static final int BAND_44 = android.hardware.radio.V1_5.EutranBands.BAND_44; + public static final int BAND_45 = android.hardware.radio.V1_5.EutranBands.BAND_45; + public static final int BAND_46 = android.hardware.radio.V1_5.EutranBands.BAND_46; + public static final int BAND_47 = android.hardware.radio.V1_5.EutranBands.BAND_47; + public static final int BAND_48 = android.hardware.radio.V1_5.EutranBands.BAND_48; + public static final int BAND_49 = android.hardware.radio.V1_5.EutranBands.BAND_49; + public static final int BAND_50 = android.hardware.radio.V1_5.EutranBands.BAND_50; + public static final int BAND_51 = android.hardware.radio.V1_5.EutranBands.BAND_51; + public static final int BAND_52 = android.hardware.radio.V1_5.EutranBands.BAND_52; + public static final int BAND_53 = android.hardware.radio.V1_5.EutranBands.BAND_53; + public static final int BAND_65 = android.hardware.radio.V1_5.EutranBands.BAND_65; + public static final int BAND_66 = android.hardware.radio.V1_5.EutranBands.BAND_66; + public static final int BAND_68 = android.hardware.radio.V1_5.EutranBands.BAND_68; + public static final int BAND_70 = android.hardware.radio.V1_5.EutranBands.BAND_70; + public static final int BAND_71 = android.hardware.radio.V1_5.EutranBands.BAND_71; + public static final int BAND_72 = android.hardware.radio.V1_5.EutranBands.BAND_72; + public static final int BAND_73 = android.hardware.radio.V1_5.EutranBands.BAND_73; + public static final int BAND_74 = android.hardware.radio.V1_5.EutranBands.BAND_74; + public static final int BAND_85 = android.hardware.radio.V1_5.EutranBands.BAND_85; + public static final int BAND_87 = android.hardware.radio.V1_5.EutranBands.BAND_87; + public static final int BAND_88 = android.hardware.radio.V1_5.EutranBands.BAND_88; + + /** + * EutranBands + * + * @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = {"BAND_"}, + value = {BAND_1, + BAND_2, + BAND_3, + BAND_4, + BAND_5, + BAND_6, + BAND_7, + BAND_8, + BAND_9, + BAND_10, + BAND_11, + BAND_12, + BAND_13, + BAND_14, + BAND_17, + BAND_18, + BAND_19, + BAND_20, + BAND_21, + BAND_22, + BAND_23, + BAND_24, + BAND_25, + BAND_26, + BAND_27, + BAND_28, + BAND_30, + BAND_31, + BAND_33, + BAND_34, + BAND_35, + BAND_36, + BAND_37, + BAND_38, + BAND_39, + BAND_40, + BAND_41, + BAND_42, + BAND_43, + BAND_44, + BAND_45, + BAND_46, + BAND_47, + BAND_48, + BAND_49, + BAND_50, + BAND_51, + BAND_52, + BAND_53, + BAND_65, + BAND_66, + BAND_68, + BAND_70, + BAND_71, + BAND_72, + BAND_73, + BAND_74, + BAND_85, + BAND_87, + BAND_88}) + + public @interface EutranBands {} /** @hide */ private EutranBand() {}; } /** + * 3GPP TS 36.101 Table 5.7.3-1 E-UTRA channel numbers. + * + * @hide + */ + enum EutranBandArfcnFrequency { + + EUTRAN_ARFCN_FREQUENCY_BAND_1( + EutranBand.BAND_1, 2110000, 0, 599, 1920000, 18800, 18599), + EUTRAN_ARFCN_FREQUENCY_BAND_2( + EutranBand.BAND_2, 1930000, 600, 1199, 1850000, 18600, 19199), + EUTRAN_ARFCN_FREQUENCY_BAND_3( + EutranBand.BAND_3, 1805000, 1200, 1949, 1710000, 19200, 19949), + EUTRAN_ARFCN_FREQUENCY_BAND_4( + EutranBand.BAND_4, 2110000, 1950, 2399, 1710000, 19950, 20399), + EUTRAN_ARFCN_FREQUENCY_BAND_5( + EutranBand.BAND_5, 869000, 2400, 2649, 824000, 20400, 20649), + EUTRAN_ARFCN_FREQUENCY_BAND_6( + EutranBand.BAND_6, 875000, 2650, 2749, 830000, 20650, 20749), + EUTRAN_ARFCN_FREQUENCY_BAND_7( + EutranBand.BAND_7, 2620000, 2750, 3449, 2500000, 20750, 21449), + EUTRAN_ARFCN_FREQUENCY_BAND_8( + EutranBand.BAND_8, 925000, 3450, 3799, 880000, 21450, 21799), + EUTRAN_ARFCN_FREQUENCY_BAND_9( + EutranBand.BAND_9, 1844900, 3800, 4149, 1749900, 21800, 22149), + EUTRAN_ARFCN_FREQUENCY_BAND_10( + EutranBand.BAND_10, 2110000, 4150, 4749, 1710000, 22150, 22749), + EUTRAN_ARFCN_FREQUENCY_BAND_11( + EutranBand.BAND_11, 1475900, 4750, 4949, 1427900, 22750, 22949), + EUTRAN_ARFCN_FREQUENCY_BAND_12( + EutranBand.BAND_12, 729000, 5010, 5179, 699000, 23010, 23179), + EUTRAN_ARFCN_FREQUENCY_BAND_13( + EutranBand.BAND_13, 746000, 5180, 5279, 777000, 23180, 23279), + EUTRAN_ARFCN_FREQUENCY_BAND_14( + EutranBand.BAND_14, 758000, 5280, 5379, 788000, 23230, 23379), + EUTRAN_ARFCN_FREQUENCY_BAND_17( + EutranBand.BAND_17, 734000, 5730, 5849, 704000, 23730, 23849), + EUTRAN_ARFCN_FREQUENCY_BAND_18( + EutranBand.BAND_18, 860000, 5850, 5999, 815000, 23850, 23999), + EUTRAN_ARFCN_FREQUENCY_BAND_19( + EutranBand.BAND_19, 875000, 6000, 6149, 830000, 24000, 24149), + EUTRAN_ARFCN_FREQUENCY_BAND_20( + EutranBand.BAND_20, 791000, 6150, 6449, 832000, 24150, 24449), + EUTRAN_ARFCN_FREQUENCY_BAND_21( + EutranBand.BAND_21, 1495900, 6450, 6599, 1447900, 24450, 24599), + EUTRAN_ARFCN_FREQUENCY_BAND_22( + EutranBand.BAND_22, 3510000, 6600, 7399, 3410000, 24600, 25399), + EUTRAN_ARFCN_FREQUENCY_BAND_23( + EutranBand.BAND_23, 2180000, 7500, 7699, 2000000, 25500, 25699), + EUTRAN_ARFCN_FREQUENCY_BAND_24( + EutranBand.BAND_24, 1525000, 7700, 8039, 1626500, 25700, 26039), + EUTRAN_ARFCN_FREQUENCY_BAND_25( + EutranBand.BAND_25, 1930000, 8040, 8689, 1850000, 26040, 26689), + EUTRAN_ARFCN_FREQUENCY_BAND_26( + EutranBand.BAND_26, 859000, 8690, 9039, 814000, 26690, 27039), + EUTRAN_ARFCN_FREQUENCY_BAND_27( + EutranBand.BAND_27, 852000, 9040, 9209, 807000, 27040, 27209), + EUTRAN_ARFCN_FREQUENCY_BAND_28( + EutranBand.BAND_28, 758000, 9210, 9659, 703000, 27210, 27659), + EUTRAN_ARFCN_FREQUENCY_BAND_30( + EutranBand.BAND_30, 2350000, 9770, 9869, 2305000, 27660, 27759), + EUTRAN_ARFCN_FREQUENCY_BAND_31( + EutranBand.BAND_31, 462500, 9870, 9919, 452500, 27760, 27809), + EUTRAN_ARFCN_FREQUENCY_BAND_33( + EutranBand.BAND_33, 1900000, 36000, 36199, 1900000, 36000, 36199), + EUTRAN_ARFCN_FREQUENCY_BAND_34( + EutranBand.BAND_34, 2010000, 36200, 36349, 2010000, 36200, 36349), + EUTRAN_ARFCN_FREQUENCY_BAND_35( + EutranBand.BAND_35, 1850000, 36350, 36949, 1850000, 36350, 36949), + EUTRAN_ARFCN_FREQUENCY_BAND_36( + EutranBand.BAND_36, 1930000, 36950, 37549, 1930000, 36950, 37549), + EUTRAN_ARFCN_FREQUENCY_BAND_37( + EutranBand.BAND_37, 1910000, 37550, 37749, 1910000, 37550, 37749), + EUTRAN_ARFCN_FREQUENCY_BAND_38( + EutranBand.BAND_38, 2570000, 37750, 38249, 2570000, 37750, 38249), + EUTRAN_ARFCN_FREQUENCY_BAND_39( + EutranBand.BAND_39, 1880000, 38250, 38649, 1880000, 38250, 38649), + EUTRAN_ARFCN_FREQUENCY_BAND_40( + EutranBand.BAND_40, 2300000, 38650, 39649, 2300000, 38650, 39649), + EUTRAN_ARFCN_FREQUENCY_BAND_41( + EutranBand.BAND_41, 2496000, 39650, 41589, 2496000, 39650, 41589), + EUTRAN_ARFCN_FREQUENCY_BAND_42( + EutranBand.BAND_42, 3400000, 41950, 43589, 3400000, 41950, 43589), + EUTRAN_ARFCN_FREQUENCY_BAND_43( + EutranBand.BAND_43, 3600000, 43950, 45589, 3600000, 43950, 45589), + EUTRAN_ARFCN_FREQUENCY_BAND_44( + EutranBand.BAND_44, 703000, 45590, 46589, 703000, 45590, 46589), + EUTRAN_ARFCN_FREQUENCY_BAND_45( + EutranBand.BAND_45, 1447000, 46590, 46789, 1447000, 46590, 46789), + EUTRAN_ARFCN_FREQUENCY_BAND_46( + EutranBand.BAND_46, 5150000, 46790, 54539, 5150000, 46790, 54539), + EUTRAN_ARFCN_FREQUENCY_BAND_47( + EutranBand.BAND_47, 5855000, 54540, 55239, 5855000, 54540, 55239), + EUTRAN_ARFCN_FREQUENCY_BAND_48( + EutranBand.BAND_48, 3550000, 55240, 56739, 3550000, 55240, 56739), + EUTRAN_ARFCN_FREQUENCY_BAND_49( + EutranBand.BAND_49, 3550000, 56740, 58239, 3550000, 56740, 58239), + EUTRAN_ARFCN_FREQUENCY_BAND_50( + EutranBand.BAND_50, 1432000, 58240, 59089, 1432000, 58240, 59089), + EUTRAN_ARFCN_FREQUENCY_BAND_51( + EutranBand.BAND_51, 1427000, 59090, 59139, 1427000, 59090, 59139), + EUTRAN_ARFCN_FREQUENCY_BAND_52( + EutranBand.BAND_52, 3300000, 59140, 60139, 3300000, 59140, 60139), + EUTRAN_ARFCN_FREQUENCY_BAND_53( + EutranBand.BAND_53, 2483500, 60140, 60254, 2483500, 60140, 60254), + EUTRAN_ARFCN_FREQUENCY_BAND_65( + EutranBand.BAND_65, 2110000, 65536, 66435, 1920000, 131072, 131971), + EUTRAN_ARFCN_FREQUENCY_BAND_66( + EutranBand.BAND_66, 2110000, 66436, 67335, 1710000, 131972, 132671), + EUTRAN_ARFCN_FREQUENCY_BAND_68( + EutranBand.BAND_68, 753000, 67536, 67835, 698000, 132672, 132971), + EUTRAN_ARFCN_FREQUENCY_BAND_70( + EutranBand.BAND_70, 1995000, 68336, 68585, 1695000, 132972, 133121), + EUTRAN_ARFCN_FREQUENCY_BAND_71( + EutranBand.BAND_71, 617000, 68586, 68935, 663000, 133122, 133471), + EUTRAN_ARFCN_FREQUENCY_BAND_72( + EutranBand.BAND_72, 461000, 68936, 68985, 451000, 133472, 133521), + EUTRAN_ARFCN_FREQUENCY_BAND_73( + EutranBand.BAND_73, 460000, 68986, 69035, 450000, 133522, 133571), + EUTRAN_ARFCN_FREQUENCY_BAND_74( + EutranBand.BAND_74, 1475000, 69036, 69465, 1427000, 133572, 134001), + EUTRAN_ARFCN_FREQUENCY_BAND_85( + EutranBand.BAND_85, 728000, 70366, 70545, 698000, 134002, 134181), + EUTRAN_ARFCN_FREQUENCY_BAND_87( + EutranBand.BAND_87, 420000, 70546, 70595, 410000, 134182, 134231), + EUTRAN_ARFCN_FREQUENCY_BAND_88( + EutranBand.BAND_88, 422000, 70596, 70645, 412000, 134231, 134280); + + EutranBandArfcnFrequency(int band, int downlinkLowKhz, int downlinkOffset, + int downlinkRange, int uplinkLowKhz, int uplinkOffset, + int uplinkRange) { + this.band = band; + this.downlinkLowKhz = downlinkLowKhz; + this.downlinkOffset = downlinkOffset; + this.uplinkLowKhz = uplinkLowKhz; + this.uplinkOffset = uplinkOffset; + this.downlinkRange = downlinkRange; + this.uplinkRange = uplinkRange; + } + + int band; + int downlinkLowKhz; + int downlinkOffset; + int uplinkLowKhz; + int uplinkOffset; + int downlinkRange; + int uplinkRange; + } + + /** * Frequency bands for CDMA2000. * http://www.3gpp2.org/Public_html/Specs/C.S0057-E_v1.0_Bandclass_Specification.pdf * @hide @@ -320,7 +693,7 @@ public final class AccessNetworkConstants { * https://www.etsi.org/deliver/etsi_ts/138100_138199/13810102/15.08.00_60/ts_13810102v150800p.pdf */ public static final class NgranBands { - /** 3GPP TS 38.101-1, Version 16.2.0, Table 5.2-1: FR1 bands */ + /** 3GPP TS 38.101-1, Version 16.5.0, Table 5.2-1: FR1 bands */ public static final int BAND_1 = android.hardware.radio.V1_5.NgranBands.BAND_1; public static final int BAND_2 = android.hardware.radio.V1_5.NgranBands.BAND_2; public static final int BAND_3 = android.hardware.radio.V1_5.NgranBands.BAND_3; @@ -332,6 +705,7 @@ public final class AccessNetworkConstants { public static final int BAND_18 = android.hardware.radio.V1_5.NgranBands.BAND_18; public static final int BAND_20 = android.hardware.radio.V1_5.NgranBands.BAND_20; public static final int BAND_25 = android.hardware.radio.V1_5.NgranBands.BAND_25; + public static final int BAND_26 = android.hardware.radio.V1_6.NgranBands.BAND_26; public static final int BAND_28 = android.hardware.radio.V1_5.NgranBands.BAND_28; public static final int BAND_29 = android.hardware.radio.V1_5.NgranBands.BAND_29; public static final int BAND_30 = android.hardware.radio.V1_5.NgranBands.BAND_30; @@ -340,9 +714,11 @@ public final class AccessNetworkConstants { public static final int BAND_39 = android.hardware.radio.V1_5.NgranBands.BAND_39; public static final int BAND_40 = android.hardware.radio.V1_5.NgranBands.BAND_40; public static final int BAND_41 = android.hardware.radio.V1_5.NgranBands.BAND_41; + public static final int BAND_46 = android.hardware.radio.V1_6.NgranBands.BAND_46; public static final int BAND_48 = android.hardware.radio.V1_5.NgranBands.BAND_48; public static final int BAND_50 = android.hardware.radio.V1_5.NgranBands.BAND_50; public static final int BAND_51 = android.hardware.radio.V1_5.NgranBands.BAND_51; + public static final int BAND_53 = android.hardware.radio.V1_6.NgranBands.BAND_53; public static final int BAND_65 = android.hardware.radio.V1_5.NgranBands.BAND_65; public static final int BAND_66 = android.hardware.radio.V1_5.NgranBands.BAND_66; public static final int BAND_70 = android.hardware.radio.V1_5.NgranBands.BAND_70; @@ -366,6 +742,7 @@ public final class AccessNetworkConstants { public static final int BAND_93 = android.hardware.radio.V1_5.NgranBands.BAND_93; public static final int BAND_94 = android.hardware.radio.V1_5.NgranBands.BAND_94; public static final int BAND_95 = android.hardware.radio.V1_5.NgranBands.BAND_95; + public static final int BAND_96 = android.hardware.radio.V1_6.NgranBands.BAND_96; /** 3GPP TS 38.101-2, Version 16.2.0, Table 5.2-1: FR2 bands */ public static final int BAND_257 = android.hardware.radio.V1_5.NgranBands.BAND_257; @@ -390,6 +767,7 @@ public final class AccessNetworkConstants { BAND_18, BAND_20, BAND_25, + BAND_26, BAND_28, BAND_29, BAND_30, @@ -398,9 +776,11 @@ public final class AccessNetworkConstants { BAND_39, BAND_40, BAND_41, + BAND_46, BAND_48, BAND_50, BAND_51, + BAND_53, BAND_65, BAND_66, BAND_70, @@ -424,6 +804,7 @@ public final class AccessNetworkConstants { BAND_93, BAND_94, BAND_95, + BAND_96, BAND_257, BAND_258, BAND_260, @@ -464,7 +845,8 @@ public final class AccessNetworkConstants { value = { FREQUENCY_RANGE_GROUP_UNKNOWN, FREQUENCY_RANGE_GROUP_1, - FREQUENCY_RANGE_GROUP_2}) + FREQUENCY_RANGE_GROUP_2 + }) public @interface FrequencyRangeGroup {} /** @@ -489,6 +871,7 @@ public final class AccessNetworkConstants { case BAND_18: case BAND_20: case BAND_25: + case BAND_26: case BAND_28: case BAND_29: case BAND_30: @@ -497,9 +880,11 @@ public final class AccessNetworkConstants { case BAND_39: case BAND_40: case BAND_41: + case BAND_46: case BAND_48: case BAND_50: case BAND_51: + case BAND_53: case BAND_65: case BAND_66: case BAND_70: @@ -523,6 +908,7 @@ public final class AccessNetworkConstants { case BAND_93: case BAND_94: case BAND_95: + case BAND_96: return FREQUENCY_RANGE_GROUP_1; case BAND_257: case BAND_258: @@ -538,6 +924,33 @@ public final class AccessNetworkConstants { private NgranBands() {} } + /** + * 3GPP TS 38.104 Table 5.4.2.1-1 NR-ARFCN parameters for the global frequency raster. + * + * @hide + */ + enum NgranArfcnFrequency { + + NGRAN_ARFCN_FREQUENCY_RANGE_1(5, 0, 0, 0, 599999), + NGRAN_ARFCN_FREQUENCY_RANGE_2(15, 3000000, 600000, 600000, 2016666), + NGRAN_ARFCN_FREQUENCY_RANGE_3(60, 24250080, 2016667, 2016667, 3279165); + + NgranArfcnFrequency(int globalKhz, int rangeOffset, int arfcnOffset, + int rangeFirst, int rangeLast) { + this.globalKhz = globalKhz; + this.rangeOffset = rangeOffset; + this.arfcnOffset = arfcnOffset; + this.rangeFirst = rangeFirst; + this.rangeLast = rangeLast; + } + + int globalKhz; + int rangeOffset; + int arfcnOffset; + int rangeFirst; + int rangeLast; + } + /** @hide */ private AccessNetworkConstants() {}; } diff --git a/telephony/java/android/telephony/AccessNetworkUtils.java b/telephony/java/android/telephony/AccessNetworkUtils.java index 7661a32f6d5b..f29f3bd352be 100644 --- a/telephony/java/android/telephony/AccessNetworkUtils.java +++ b/telephony/java/android/telephony/AccessNetworkUtils.java @@ -4,12 +4,20 @@ import static android.telephony.ServiceState.DUPLEX_MODE_FDD; import static android.telephony.ServiceState.DUPLEX_MODE_TDD; import static android.telephony.ServiceState.DUPLEX_MODE_UNKNOWN; +import android.telephony.AccessNetworkConstants.EutranBandArfcnFrequency; import android.telephony.AccessNetworkConstants.EutranBand; import android.telephony.AccessNetworkConstants.GeranBand; +import android.telephony.AccessNetworkConstants.GeranBandArfcnFrequency; +import android.telephony.AccessNetworkConstants.NgranArfcnFrequency; +import android.telephony.AccessNetworkConstants.NgranBands; import android.telephony.AccessNetworkConstants.UtranBand; +import android.telephony.AccessNetworkConstants.UtranBandArfcnFrequency; import android.telephony.ServiceState.DuplexMode; +import android.util.Log; import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; /** * Utilities to map between radio constants. @@ -22,9 +30,27 @@ public class AccessNetworkUtils { private AccessNetworkUtils() {} public static final int INVALID_BAND = -1; + public static final int INVALID_FREQUENCY = -1; /** ISO country code of Japan. */ private static final String JAPAN_ISO_COUNTRY_CODE = "jp"; + private static final String TAG = "AccessNetworkUtils"; + + private static final int FREQUENCY_KHZ = 1000; + private static final int FREQUENCY_RANGE_LOW_KHZ = 1000000; + private static final int FREQUENCY_RANGE_MID_KHZ = 3000000; + private static final int FREQUENCY_RANGE_HIGH_KHZ = 6000000; + + private static final Set<Integer> UARFCN_NOT_GENERAL_BAND; + static { + UARFCN_NOT_GENERAL_BAND = new HashSet<Integer>(); + UARFCN_NOT_GENERAL_BAND.add(UtranBand.BAND_A); + UARFCN_NOT_GENERAL_BAND.add(UtranBand.BAND_B); + UARFCN_NOT_GENERAL_BAND.add(UtranBand.BAND_C); + UARFCN_NOT_GENERAL_BAND.add(UtranBand.BAND_D); + UARFCN_NOT_GENERAL_BAND.add(UtranBand.BAND_E); + UARFCN_NOT_GENERAL_BAND.add(UtranBand.BAND_F); + } /** * Gets the duplex mode for the given EUTRAN operating band. @@ -325,4 +351,403 @@ public class AccessNetworkUtils { } return INVALID_BAND; } + + /** + * Get geran bands from {@link PhysicalChannelConfig#getBand()} + */ + public static int getFrequencyRangeGroupFromGeranBand(@GeranBand.GeranBands int band) { + switch (band) { + case GeranBand.BAND_T380: + case GeranBand.BAND_T410: + case GeranBand.BAND_450: + case GeranBand.BAND_480: + case GeranBand.BAND_710: + case GeranBand.BAND_750: + case GeranBand.BAND_T810: + case GeranBand.BAND_850: + case GeranBand.BAND_P900: + case GeranBand.BAND_E900: + case GeranBand.BAND_R900: + case GeranBand.BAND_ER900: + return ServiceState.FREQUENCY_RANGE_LOW; + case GeranBand.BAND_DCS1800: + case GeranBand.BAND_PCS1900: + return ServiceState.FREQUENCY_RANGE_MID; + default: + return ServiceState.FREQUENCY_RANGE_UNKNOWN; + } + } + + /** + * Get utran bands from {@link PhysicalChannelConfig#getBand()} + */ + public static int getFrequencyRangeGroupFromUtranBand(@UtranBand.UtranBands int band) { + switch (band) { + case UtranBand.BAND_5: + case UtranBand.BAND_6: + case UtranBand.BAND_8: + case UtranBand.BAND_12: + case UtranBand.BAND_13: + case UtranBand.BAND_14: + case UtranBand.BAND_19: + case UtranBand.BAND_20: + case UtranBand.BAND_26: + return ServiceState.FREQUENCY_RANGE_LOW; + case UtranBand.BAND_1: + case UtranBand.BAND_2: + case UtranBand.BAND_3: + case UtranBand.BAND_4: + case UtranBand.BAND_7: + case UtranBand.BAND_9: + case UtranBand.BAND_10: + case UtranBand.BAND_11: + case UtranBand.BAND_21: + case UtranBand.BAND_25: + case UtranBand.BAND_A: + case UtranBand.BAND_B: + case UtranBand.BAND_C: + case UtranBand.BAND_D: + case UtranBand.BAND_E: + case UtranBand.BAND_F: + return ServiceState.FREQUENCY_RANGE_MID; + case UtranBand.BAND_22: + return ServiceState.FREQUENCY_RANGE_HIGH; + default: + return ServiceState.FREQUENCY_RANGE_UNKNOWN; + } + } + + /** + * Get eutran bands from {@link PhysicalChannelConfig#getBand()} + * 3GPP TS 36.101 Table 5.5 EUTRA operating bands + */ + public static int getFrequencyRangeGroupFromEutranBand(@EutranBand.EutranBands int band) { + switch (band) { + case EutranBand.BAND_5: + case EutranBand.BAND_6: + case EutranBand.BAND_8: + case EutranBand.BAND_12: + case EutranBand.BAND_13: + case EutranBand.BAND_14: + case EutranBand.BAND_17: + case EutranBand.BAND_18: + case EutranBand.BAND_19: + case EutranBand.BAND_20: + case EutranBand.BAND_26: + case EutranBand.BAND_27: + case EutranBand.BAND_28: + case EutranBand.BAND_31: + case EutranBand.BAND_44: + case EutranBand.BAND_50: + case EutranBand.BAND_51: + case EutranBand.BAND_68: + case EutranBand.BAND_71: + case EutranBand.BAND_72: + case EutranBand.BAND_73: + case EutranBand.BAND_85: + case EutranBand.BAND_87: + case EutranBand.BAND_88: + return ServiceState.FREQUENCY_RANGE_LOW; + case EutranBand.BAND_1: + case EutranBand.BAND_2: + case EutranBand.BAND_3: + case EutranBand.BAND_4: + case EutranBand.BAND_7: + case EutranBand.BAND_9: + case EutranBand.BAND_10: + case EutranBand.BAND_11: + case EutranBand.BAND_21: + case EutranBand.BAND_23: + case EutranBand.BAND_24: + case EutranBand.BAND_25: + case EutranBand.BAND_30: + case EutranBand.BAND_33: + case EutranBand.BAND_34: + case EutranBand.BAND_35: + case EutranBand.BAND_36: + case EutranBand.BAND_37: + case EutranBand.BAND_38: + case EutranBand.BAND_39: + case EutranBand.BAND_40: + case EutranBand.BAND_41: + case EutranBand.BAND_45: + case EutranBand.BAND_53: + case EutranBand.BAND_65: + case EutranBand.BAND_66: + case EutranBand.BAND_70: + case EutranBand.BAND_74: + return ServiceState.FREQUENCY_RANGE_MID; + case EutranBand.BAND_22: + case EutranBand.BAND_42: + case EutranBand.BAND_43: + case EutranBand.BAND_46: + case EutranBand.BAND_47: + case EutranBand.BAND_48: + case EutranBand.BAND_49: + case EutranBand.BAND_52: + return ServiceState.FREQUENCY_RANGE_HIGH; + default: + return ServiceState.FREQUENCY_RANGE_UNKNOWN; + } + } + + /** + * Get ngran band from {@link PhysicalChannelConfig#getBand()} + * 3GPP TS 38.104 Table 5.2-1 NR operating bands in FR1 + * 3GPP TS 38.104 Table 5.2-2 NR operating bands in FR2 + */ + public static int getFrequencyRangeGroupFromNrBand(@NgranBands.NgranBand int band) { + switch (band) { + case NgranBands.BAND_5: + case NgranBands.BAND_8: + case NgranBands.BAND_12: + case NgranBands.BAND_14: + case NgranBands.BAND_18: + case NgranBands.BAND_20: + case NgranBands.BAND_26: + case NgranBands.BAND_28: + case NgranBands.BAND_29: + case NgranBands.BAND_71: + case NgranBands.BAND_81: + case NgranBands.BAND_82: + case NgranBands.BAND_83: + case NgranBands.BAND_89: + return ServiceState.FREQUENCY_RANGE_LOW; + case NgranBands.BAND_1: + case NgranBands.BAND_2: + case NgranBands.BAND_3: + case NgranBands.BAND_7: + case NgranBands.BAND_25: + case NgranBands.BAND_30: + case NgranBands.BAND_34: + case NgranBands.BAND_38: + case NgranBands.BAND_39: + case NgranBands.BAND_40: + case NgranBands.BAND_41: + case NgranBands.BAND_50: + case NgranBands.BAND_51: + case NgranBands.BAND_53: + case NgranBands.BAND_65: + case NgranBands.BAND_66: + case NgranBands.BAND_70: + case NgranBands.BAND_74: + case NgranBands.BAND_75: + case NgranBands.BAND_76: + case NgranBands.BAND_80: + case NgranBands.BAND_84: + case NgranBands.BAND_86: + case NgranBands.BAND_90: + case NgranBands.BAND_91: + case NgranBands.BAND_92: + case NgranBands.BAND_93: + case NgranBands.BAND_94: + case NgranBands.BAND_95: + return ServiceState.FREQUENCY_RANGE_MID; + case NgranBands.BAND_46: + case NgranBands.BAND_48: + case NgranBands.BAND_77: + case NgranBands.BAND_78: + case NgranBands.BAND_79: + return ServiceState.FREQUENCY_RANGE_HIGH; + case NgranBands.BAND_96: + case NgranBands.BAND_257: + case NgranBands.BAND_258: + case NgranBands.BAND_260: + case NgranBands.BAND_261: + return ServiceState.FREQUENCY_RANGE_MMWAVE; + default: + return ServiceState.FREQUENCY_RANGE_UNKNOWN; + } + } + + /** + * 3GPP TS 38.104 Table 5.4.2.1-1 NR-ARFCN parameters for the global frequency raster. + * Formula of NR-ARFCN convert to actual frequency: + * Actual frequency(kHz) = (RANGE_OFFSET + GLOBAL_KHZ * (ARFCN - ARFCN_OFFSET)) + */ + public static int getFrequencyFromNrArfcn(int nrArfcn) { + + int globalKhz = 0; + int rangeOffset = 0; + int arfcnOffset = 0; + for (NgranArfcnFrequency nrArfcnFrequency : AccessNetworkConstants. + NgranArfcnFrequency.values()) { + if (nrArfcn >= nrArfcnFrequency.rangeFirst + && nrArfcn <= nrArfcnFrequency.rangeLast) { + globalKhz = nrArfcnFrequency.globalKhz; + rangeOffset = nrArfcnFrequency.rangeOffset; + arfcnOffset = nrArfcnFrequency.arfcnOffset; + break; + } + } + return rangeOffset + globalKhz * (nrArfcn - arfcnOffset); + } + + /** + * Get actual frequency from E-UTRA ARFCN. + */ + public static int getFrequencyFromEarfcn(int band, int earfcn, boolean isUplink) { + + int low = 0; + int offset = 0; + for (EutranBandArfcnFrequency earfcnFrequency : EutranBandArfcnFrequency.values()) { + if (band == earfcnFrequency.band) { + if (isInEarfcnRange(earfcn, earfcnFrequency, isUplink)) { + low = isUplink ? earfcnFrequency.uplinkLowKhz : earfcnFrequency.downlinkLowKhz; + offset = isUplink ? earfcnFrequency.uplinkOffset + : earfcnFrequency.downlinkOffset; + break; + } else { + Log.e(TAG, "Band and the range of EARFCN are not consistent."); + return INVALID_FREQUENCY; + } + } + } + return convertEarfcnToFrequency(low, earfcn, offset); + } + + /** + * 3GPP TS 36.101 Table 5.7.3-1 E-UTRA channel numbers. + * Formula of E-UTRA ARFCN convert to actual frequency: + * Actual frequency(kHz) = (DOWNLINK_LOW + 0.1 * (ARFCN - DOWNLINK_OFFSET)) * FREQUENCY_KHZ + * Actual frequency(kHz) = (UPLINK_LOW + 0.1 * (ARFCN - UPLINK_OFFSET)) * FREQUENCY_KHZ + */ + private static int convertEarfcnToFrequency(int low, int earfcn, int offset) { + return low + 100 * (earfcn - offset); + } + + private static boolean isInEarfcnRange(int earfcn, EutranBandArfcnFrequency earfcnFrequency, + boolean isUplink) { + if (isUplink) { + return earfcn >= earfcnFrequency.uplinkOffset && earfcn <= earfcnFrequency.uplinkRange; + } else { + return earfcn >= earfcnFrequency.downlinkOffset + && earfcn <= earfcnFrequency.downlinkRange; + } + } + + /** + * Get actual frequency from UTRA ARFCN. + */ + public static int getFrequencyFromUarfcn(int band, int uarfcn, boolean isUplink) { + + int offsetKhz = 0; + for (UtranBandArfcnFrequency uarfcnFrequency : AccessNetworkConstants. + UtranBandArfcnFrequency.values()) { + if (band == uarfcnFrequency.band) { + if (isInUarfcnRange(uarfcn, uarfcnFrequency, isUplink)) { + offsetKhz = isUplink ? uarfcnFrequency.uplinkOffset + : uarfcnFrequency.downlinkOffset; + break; + } else { + Log.e(TAG, "Band and the range of UARFCN are not consistent."); + return INVALID_FREQUENCY; + } + } + } + + if (!UARFCN_NOT_GENERAL_BAND.contains(band)) { + return convertUarfcnToFrequency(offsetKhz, uarfcn); + } else { + return convertUarfcnTddToFrequency(band, uarfcn); + } + } + + /** + * 3GPP TS 25.101, Table 5.1 UARFCN definition (general). + * Formula of UTRA ARFCN convert to actual frequency: + * For general bands: + * Downlink actual frequency(kHz) = (DOWNLINK_OFFSET + 0.2 * ARFCN) * FREQUENCY_KHZ + * Uplink actual frequency(kHz) = (UPLINK_OFFSET + 0.2 * ARFCN) * FREQUENCY_KHZ + */ + private static int convertUarfcnToFrequency(int offsetKhz, int uarfcn) { + return offsetKhz + (200 * uarfcn); + } + + /** + * 3GPP TS 25.102, Table 5.2 UTRA Absolute Radio Frequency Channel Number 1.28 Mcps TDD Option. + * For FDD bands A, B, C, E, F: + * Actual frequency(kHz) = 5 * ARFCN * FREQUENCY_KHZ + * For TDD bands D: + * Actual frequency(kHz) = (5 * (ARFCN - 2150.1MHz)) * FREQUENCY_KHZ + */ + private static int convertUarfcnTddToFrequency(int band, int uarfcn) { + if (band != UtranBand.BAND_D) { + return 5 * uarfcn * FREQUENCY_KHZ; + } else { + return 5 * ((FREQUENCY_KHZ * uarfcn) - 2150100); + } + } + + private static boolean isInUarfcnRange(int uarfcn, UtranBandArfcnFrequency uarfcnFrequency, + boolean isUplink) { + if (isUplink) { + return uarfcn >= uarfcnFrequency.uplinkRangeFirst + && uarfcn <= uarfcnFrequency.uplinkRangeLast; + } else { + if (uarfcnFrequency.downlinkRangeFirst != 0 && uarfcnFrequency.downlinkRangeLast != 0) { + return uarfcn >= uarfcnFrequency.downlinkRangeFirst + && uarfcn <= uarfcnFrequency.downlinkRangeLast; + } else { + // BAND_C, BAND_D, BAND_E and BAND_F do not have the downlink range. + return true; + } + } + } + + /** + * Get actual frequency from GERAN ARFCN. + */ + public static int getFrequencyFromArfcn(int band, int arfcn, boolean isUplink) { + + int uplinkFrequencyFirst = 0; + int arfcnOffset = 0; + int downlinkOffset = 0; + int frequency = 0; + for (GeranBandArfcnFrequency arfcnFrequency : AccessNetworkConstants. + GeranBandArfcnFrequency.values()) { + if (band == arfcnFrequency.band) { + if (arfcn >= arfcnFrequency.arfcnRangeFirst + && arfcn <= arfcnFrequency.arfcnRangeLast) { + uplinkFrequencyFirst = arfcnFrequency.uplinkFrequencyFirst; + downlinkOffset = arfcnFrequency.downlinkOffset; + arfcnOffset = arfcnFrequency.arfcnOffset; + frequency = convertArfcnToFrequency(arfcn, uplinkFrequencyFirst, + arfcnOffset); + break; + } else { + Log.e(TAG, "Band and the range of ARFCN are not consistent."); + return INVALID_FREQUENCY; + } + } + } + + return isUplink ? frequency : frequency + downlinkOffset; + } + + /** + * 3GPP TS 45.005 Table 2-1 Dynamically mapped ARFCN + * Formula of Geran ARFCN convert to actual frequency: + * Uplink actual frequency(kHz) = + * (UPLINK_FREQUENCY_FIRST + 0.2 * (ARFCN - ARFCN_RANGE_FIRST)) * FREQUENCY_KHZ + * Downlink actual frequency(kHz) = Uplink actual frequency + 10 + */ + private static int convertArfcnToFrequency(int arfcn, int uplinkFrequencyFirstKhz, + int arfcnOffset) { + return uplinkFrequencyFirstKhz + 200 * (arfcn - arfcnOffset); + } + + public static int getFrequencyRangeFromArfcn(int frequency) { + if (frequency < FREQUENCY_RANGE_LOW_KHZ) { + return ServiceState.FREQUENCY_RANGE_LOW; + } else if (frequency < FREQUENCY_RANGE_MID_KHZ + && frequency >= FREQUENCY_RANGE_LOW_KHZ) { + return ServiceState.FREQUENCY_RANGE_MID; + } else if (frequency < FREQUENCY_RANGE_HIGH_KHZ + && frequency >= FREQUENCY_RANGE_MID_KHZ) { + return ServiceState.FREQUENCY_RANGE_HIGH; + } else { + return ServiceState.FREQUENCY_RANGE_MMWAVE; + } + } } diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index 74b2aad5293e..e3eb0b582b1c 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -4077,6 +4077,18 @@ public class CarrierConfigManager { "use_lower_mtu_value_if_both_received"; /** + * Determines the default RTT mode. + * + * Upon first boot, when the user has not yet set a value for their preferred RTT mode, + * the value of this config will be sent to the IMS stack. Valid values are the same as for + * {@link Settings.Secure#RTT_CALLING_MODE}. + * + * @hide + */ + public static final String KEY_DEFAULT_RTT_MODE_INT = + "default_rtt_mode_int"; + + /** * Indicates if auto-configuration server is used for the RCS config * Reference: GSMA RCC.14 */ @@ -4628,6 +4640,7 @@ public class CarrierConfigManager { sDefaults.putString(KEY_CALL_COMPOSER_PICTURE_SERVER_URL_STRING, ""); sDefaults.putBoolean(KEY_USE_LOWER_MTU_VALUE_IF_BOTH_RECEIVED, false); sDefaults.putBoolean(KEY_USE_ACS_FOR_RCS_BOOL, false); + sDefaults.putInt(KEY_DEFAULT_RTT_MODE_INT, 0); } /** diff --git a/telephony/java/android/telephony/PhysicalChannelConfig.java b/telephony/java/android/telephony/PhysicalChannelConfig.java index 327d6313c4dc..9fb098ea8758 100644 --- a/telephony/java/android/telephony/PhysicalChannelConfig.java +++ b/telephony/java/android/telephony/PhysicalChannelConfig.java @@ -55,6 +55,18 @@ public final class PhysicalChannelConfig implements Parcelable { /** Physical Cell Id is unknown. */ public static final int PHYSICAL_CELL_ID_UNKNOWN = -1; + /** Physical Cell Id's maximum value is 1007. */ + public static final int PHYSICAL_CELL_ID_MAXIMUM_VALUE = 1007; + + /** Cell bandwidth is unknown. */ + public static final int CELL_BANDWIDTH_UNKNOWN = 0; + + /** The frequency is unknown. */ + public static final int FREQUENCY_UNKNOWN = -1; + + /** The band is unknown. */ + public static final int BAND_UNKNOWN = 0; + /** * Connection status of the cell. * @@ -64,15 +76,20 @@ public final class PhysicalChannelConfig implements Parcelable { private int mCellConnectionStatus; /** - * Cell bandwidth, in kHz. + * Downlink cell bandwidth, in kHz. */ private int mCellBandwidthDownlinkKhz; /** + * Uplink cell bandwidth, in kHz. + */ + private int mCellBandwidthUplinkKhz; + + /** * The radio technology for this physical channel. */ @NetworkType - private int mRat; + private int mNetworkType; /** * The rough frequency range for this physical channel. @@ -81,9 +98,24 @@ public final class PhysicalChannelConfig implements Parcelable { private int mFrequencyRange; /** - * The absolute radio frequency channel number, {@link #CHANNEL_NUMBER_UNKNOWN} if unknown. + * The frequency of Downlink. */ - private int mChannelNumber; + private int mDownlinkFrequency; + + /** + * The frequency of Uplink. + */ + private int mUplinkFrequency; + + /** + * Downlink Absolute Radio Frequency Channel Number + */ + private int mDownlinkChannelNumber; + + /** + * Uplink Absolute Radio Frequency Channel Number + */ + private int mUplinkChannelNumber; /** * A list of data calls mapped to this physical channel. An empty list means the physical @@ -96,6 +128,11 @@ public final class PhysicalChannelConfig implements Parcelable { */ private int mPhysicalCellId; + /** + * This is the band which is being used. + */ + private int mBand; + @Override public int describeContents() { return 0; @@ -105,27 +142,39 @@ public final class PhysicalChannelConfig implements Parcelable { public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeInt(mCellConnectionStatus); dest.writeInt(mCellBandwidthDownlinkKhz); - dest.writeInt(mRat); - dest.writeInt(mChannelNumber); + dest.writeInt(mCellBandwidthUplinkKhz); + dest.writeInt(mNetworkType); + dest.writeInt(mDownlinkChannelNumber); + dest.writeInt(mUplinkChannelNumber); dest.writeInt(mFrequencyRange); dest.writeIntArray(mContextIds); dest.writeInt(mPhysicalCellId); + dest.writeInt(mBand); } /** - * @return Cell bandwidth, in kHz + * @return Downlink cell bandwidth in kHz, {@link #CELL_BANDWIDTH_UNKNOWN} if unknown. */ - public int getCellBandwidthDownlink() { + @IntRange(from = 1) + public int getCellBandwidthDownlinkKhz() { return mCellBandwidthDownlinkKhz; } /** + * @return Uplink cell bandwidth in kHz, {@link #CELL_BANDWIDTH_UNKNOWN} if unknown. + */ + @IntRange(from = 1) + public int getCellBandwidthUplinkKhz() { + return mCellBandwidthUplinkKhz; + } + + /** * Get the list of data call ids mapped to this physical channel. This list is sorted into * ascending numerical order. Each id in this list must match the id in * {@link com.android.internal.telephony.dataconnection.DataConnection}. An empty list means the * physical channel has no data call mapped to it. * - * @return an integer list indicates the data call ids. + * @return an integer list indicates the data call ids, * @hide */ public int[] getContextIds() { @@ -133,7 +182,18 @@ public final class PhysicalChannelConfig implements Parcelable { } /** - * @return the rough frequency range for this physical channel. + * @return the absolute radio frequency channel number for this physical channel, + * {@link #CHANNEL_NUMBER_UNKNOWN} if unknown. + * @deprecated Use {@link #getDownlinkChannelNumber()} to get the channel number. + */ + @Deprecated + public int getChannelNumber() { + return getDownlinkChannelNumber(); + } + + /** + * @return the rough frequency range for this physical channel, + * {@link ServiceState#FREQUENCY_RANGE_UNKNOWN} if unknown. * @see {@link ServiceState#FREQUENCY_RANGE_LOW} * @see {@link ServiceState#FREQUENCY_RANGE_MID} * @see {@link ServiceState#FREQUENCY_RANGE_HIGH} @@ -146,11 +206,48 @@ public final class PhysicalChannelConfig implements Parcelable { } /** - * @return the absolute radio frequency channel number for this physical channel, + * @return Downlink Absolute Radio Frequency Channel Number, * {@link #CHANNEL_NUMBER_UNKNOWN} if unknown. */ - public int getChannelNumber() { - return mChannelNumber; + @IntRange(from = 0) + public int getDownlinkChannelNumber() { + return mDownlinkChannelNumber; + } + + /** + * @return Uplink Absolute Radio Frequency Channel Number, + * {@link #CHANNEL_NUMBER_UNKNOWN} if unknown. + */ + @IntRange(from = 0) + public int getUplinkChannelNumber() { + return mUplinkChannelNumber; + } + + /** + * The valid bands are {@link AccessNetworkConstants.GeranBand}, + * {@link AccessNetworkConstants.UtranBand}, {@link AccessNetworkConstants.EutranBand} and + * {@link AccessNetworkConstants.NgranBands}. + * + * @return the frequency band, {@link #BAND_UNKNOWN} if unknown. */ + @IntRange(from = 1, to = 261) + public int getBand() { + return mBand; + } + + /** + * @return The downlink frequency in kHz, {@link #FREQUENCY_UNKNOWN} if unknown. + */ + @IntRange(from = 0) + public int getDownlinkFrequencyKhz() { + return mDownlinkFrequency; + } + + /** + * @return The uplink frequency in kHz, {@link #FREQUENCY_UNKNOWN} if unknown. + */ + @IntRange(from = 0) + public int getUplinkFrequencyKhz() { + return mUplinkFrequency; } /** @@ -171,10 +268,13 @@ public final class PhysicalChannelConfig implements Parcelable { return mPhysicalCellId; } - /**The radio technology for this physical channel. */ + /** + * @return The network type for this physical channel, + * {@link TelephonyManager#NETWORK_TYPE_UNKNOWN} if unknown. + */ @NetworkType public int getNetworkType() { - return mRat; + return mNetworkType; } /** @@ -184,7 +284,7 @@ public final class PhysicalChannelConfig implements Parcelable { * @see #CONNECTION_SECONDARY_SERVING * @see #CONNECTION_UNKNOWN * - * @return Connection status of the cell + * @return Connection status of the cell, {@link #CONNECTION_UNKNOWN} if unknown. */ @ConnectionStatus public int getConnectionStatus() { @@ -208,6 +308,97 @@ public final class PhysicalChannelConfig implements Parcelable { } } + private void setDownlinkFrequency() { + switch (mNetworkType) { + case TelephonyManager.NETWORK_TYPE_NR: + mDownlinkFrequency = AccessNetworkUtils.getFrequencyFromNrArfcn( + mDownlinkChannelNumber); + break; + case TelephonyManager.NETWORK_TYPE_LTE: + mDownlinkFrequency = AccessNetworkUtils.getFrequencyFromEarfcn( + mBand, mDownlinkChannelNumber, false); + break; + case TelephonyManager.NETWORK_TYPE_HSPAP: + case TelephonyManager.NETWORK_TYPE_TD_SCDMA: + case TelephonyManager.NETWORK_TYPE_UMTS: + case TelephonyManager.NETWORK_TYPE_HSDPA: + case TelephonyManager.NETWORK_TYPE_HSUPA: + case TelephonyManager.NETWORK_TYPE_HSPA: + mDownlinkFrequency = AccessNetworkUtils.getFrequencyFromUarfcn( + mBand, mDownlinkChannelNumber, false); + break; + case TelephonyManager.NETWORK_TYPE_GPRS: + case TelephonyManager.NETWORK_TYPE_EDGE: + case TelephonyManager.NETWORK_TYPE_GSM: + mDownlinkFrequency = AccessNetworkUtils.getFrequencyFromArfcn( + mBand, mDownlinkChannelNumber, false); + break; + } + } + + private void setUplinkFrequency() { + switch (mNetworkType){ + case TelephonyManager.NETWORK_TYPE_NR: + mUplinkFrequency = mDownlinkFrequency; + break; + case TelephonyManager.NETWORK_TYPE_LTE: + mUplinkFrequency = AccessNetworkUtils.getFrequencyFromEarfcn( + mBand, mUplinkChannelNumber, true); + break; + case TelephonyManager.NETWORK_TYPE_HSPAP: + case TelephonyManager.NETWORK_TYPE_TD_SCDMA: + case TelephonyManager.NETWORK_TYPE_UMTS: + case TelephonyManager.NETWORK_TYPE_HSDPA: + case TelephonyManager.NETWORK_TYPE_HSUPA: + case TelephonyManager.NETWORK_TYPE_HSPA: + mUplinkFrequency = AccessNetworkUtils.getFrequencyFromUarfcn( + mBand, mUplinkChannelNumber, true); + break; + case TelephonyManager.NETWORK_TYPE_GPRS: + case TelephonyManager.NETWORK_TYPE_EDGE: + case TelephonyManager.NETWORK_TYPE_GSM: + mUplinkFrequency = AccessNetworkUtils.getFrequencyFromArfcn( + mBand, mUplinkChannelNumber, true); + break; + } + } + + private void setFrequencyRange() { + if (mFrequencyRange != ServiceState.FREQUENCY_RANGE_UNKNOWN) { + return; + } + + switch (mNetworkType) { + case TelephonyManager.NETWORK_TYPE_NR: + mFrequencyRange = AccessNetworkUtils.getFrequencyRangeGroupFromNrBand(mBand); + break; + case TelephonyManager.NETWORK_TYPE_LTE: + mFrequencyRange = AccessNetworkUtils.getFrequencyRangeGroupFromEutranBand(mBand); + break; + case TelephonyManager.NETWORK_TYPE_HSPAP: + case TelephonyManager.NETWORK_TYPE_TD_SCDMA: + case TelephonyManager.NETWORK_TYPE_UMTS: + case TelephonyManager.NETWORK_TYPE_HSDPA: + case TelephonyManager.NETWORK_TYPE_HSUPA: + case TelephonyManager.NETWORK_TYPE_HSPA: + mFrequencyRange = AccessNetworkUtils.getFrequencyRangeGroupFromUtranBand(mBand); + break; + case TelephonyManager.NETWORK_TYPE_GPRS: + case TelephonyManager.NETWORK_TYPE_EDGE: + case TelephonyManager.NETWORK_TYPE_GSM: + mFrequencyRange = AccessNetworkUtils.getFrequencyRangeGroupFromGeranBand(mBand); + break; + default: + mFrequencyRange = ServiceState.FREQUENCY_RANGE_UNKNOWN; + break; + } + + if (mFrequencyRange == ServiceState.FREQUENCY_RANGE_UNKNOWN) { + mFrequencyRange = AccessNetworkUtils.getFrequencyRangeFromArfcn( + mDownlinkFrequency); + } + } + @Override public boolean equals(Object o) { if (this == o) { @@ -221,30 +412,37 @@ public final class PhysicalChannelConfig implements Parcelable { PhysicalChannelConfig config = (PhysicalChannelConfig) o; return mCellConnectionStatus == config.mCellConnectionStatus && mCellBandwidthDownlinkKhz == config.mCellBandwidthDownlinkKhz - && mRat == config.mRat + && mCellBandwidthUplinkKhz == config.mCellBandwidthUplinkKhz + && mNetworkType == config.mNetworkType && mFrequencyRange == config.mFrequencyRange - && mChannelNumber == config.mChannelNumber + && mDownlinkChannelNumber == config.mDownlinkChannelNumber + && mUplinkChannelNumber == config.mUplinkChannelNumber && mPhysicalCellId == config.mPhysicalCellId - && Arrays.equals(mContextIds, config.mContextIds); + && Arrays.equals(mContextIds, config.mContextIds) + && mBand == config.mBand + && mDownlinkFrequency == config.mDownlinkFrequency + && mUplinkFrequency == config.mUplinkFrequency; } @Override public int hashCode() { return Objects.hash( - mCellConnectionStatus, mCellBandwidthDownlinkKhz, mRat, mFrequencyRange, - mChannelNumber, mPhysicalCellId, mContextIds); + mCellConnectionStatus, mCellBandwidthDownlinkKhz, mCellBandwidthUplinkKhz, + mNetworkType, mFrequencyRange, mDownlinkChannelNumber, mUplinkChannelNumber, + mContextIds, mPhysicalCellId, mBand, mDownlinkFrequency, mUplinkFrequency); } - public static final @android.annotation.NonNull Parcelable.Creator<PhysicalChannelConfig> CREATOR = - new Parcelable.Creator<PhysicalChannelConfig>() { - public PhysicalChannelConfig createFromParcel(Parcel in) { - return new PhysicalChannelConfig(in); - } + public static final + @android.annotation.NonNull Parcelable.Creator<PhysicalChannelConfig> CREATOR = + new Parcelable.Creator<PhysicalChannelConfig>() { + public PhysicalChannelConfig createFromParcel(Parcel in) { + return new PhysicalChannelConfig(in); + } - public PhysicalChannelConfig[] newArray(int size) { - return new PhysicalChannelConfig[size]; - } - }; + public PhysicalChannelConfig[] newArray(int size) { + return new PhysicalChannelConfig[size]; + } + }; @Override public String toString() { @@ -253,16 +451,26 @@ public final class PhysicalChannelConfig implements Parcelable { .append(getConnectionStatusString()) .append(",mCellBandwidthDownlinkKhz=") .append(mCellBandwidthDownlinkKhz) - .append(",mRat=") - .append(TelephonyManager.getNetworkTypeName(mRat)) + .append(",mCellBandwidthUplinkKhz=") + .append(mCellBandwidthUplinkKhz) + .append(",mNetworkType=") + .append(TelephonyManager.getNetworkTypeName(mNetworkType)) .append(",mFrequencyRange=") .append(ServiceState.frequencyRangeToString(mFrequencyRange)) - .append(",mChannelNumber=") - .append(mChannelNumber) + .append(",mDownlinkChannelNumber=") + .append(mDownlinkChannelNumber) + .append(",mUplinkChannelNumber=") + .append(mUplinkChannelNumber) .append(",mContextIds=") .append(Arrays.toString(mContextIds)) .append(",mPhysicalCellId=") .append(mPhysicalCellId) + .append(",mBand=") + .append(mBand) + .append(",mDownlinkFrequency=") + .append(mDownlinkFrequency) + .append(",mUplinkFrequency=") + .append(mUplinkFrequency) .append("}") .toString(); } @@ -270,21 +478,37 @@ public final class PhysicalChannelConfig implements Parcelable { private PhysicalChannelConfig(Parcel in) { mCellConnectionStatus = in.readInt(); mCellBandwidthDownlinkKhz = in.readInt(); - mRat = in.readInt(); - mChannelNumber = in.readInt(); + mCellBandwidthUplinkKhz = in.readInt(); + mNetworkType = in.readInt(); + mDownlinkChannelNumber = in.readInt(); + mUplinkChannelNumber = in.readInt(); mFrequencyRange = in.readInt(); mContextIds = in.createIntArray(); mPhysicalCellId = in.readInt(); + mBand = in.readInt(); + if (mBand > BAND_UNKNOWN) { + setDownlinkFrequency(); + setUplinkFrequency(); + setFrequencyRange(); + } } private PhysicalChannelConfig(Builder builder) { mCellConnectionStatus = builder.mCellConnectionStatus; mCellBandwidthDownlinkKhz = builder.mCellBandwidthDownlinkKhz; - mRat = builder.mRat; - mChannelNumber = builder.mChannelNumber; + mCellBandwidthUplinkKhz = builder.mCellBandwidthUplinkKhz; + mNetworkType = builder.mNetworkType; + mDownlinkChannelNumber = builder.mDownlinkChannelNumber; + mUplinkChannelNumber = builder.mUplinkChannelNumber; mFrequencyRange = builder.mFrequencyRange; mContextIds = builder.mContextIds; mPhysicalCellId = builder.mPhysicalCellId; + mBand = builder.mBand; + if (mBand > BAND_UNKNOWN) { + setDownlinkFrequency(); + setUplinkFrequency(); + setFrequencyRange(); + } } /** @@ -292,61 +516,105 @@ public final class PhysicalChannelConfig implements Parcelable { * @hide */ public static final class Builder { - private int mRat; + private int mNetworkType; private int mFrequencyRange; - private int mChannelNumber; + private int mDownlinkChannelNumber; + private int mUplinkChannelNumber; private int mCellBandwidthDownlinkKhz; + private int mCellBandwidthUplinkKhz; private int mCellConnectionStatus; private int[] mContextIds; private int mPhysicalCellId; + private int mBand; public Builder() { - mRat = ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN; + mNetworkType = TelephonyManager.NETWORK_TYPE_UNKNOWN; mFrequencyRange = ServiceState.FREQUENCY_RANGE_UNKNOWN; - mChannelNumber = CHANNEL_NUMBER_UNKNOWN; - mCellBandwidthDownlinkKhz = 0; + mDownlinkChannelNumber = CHANNEL_NUMBER_UNKNOWN; + mUplinkChannelNumber = CHANNEL_NUMBER_UNKNOWN; + mCellBandwidthDownlinkKhz = CELL_BANDWIDTH_UNKNOWN; + mCellBandwidthUplinkKhz = CELL_BANDWIDTH_UNKNOWN; mCellConnectionStatus = CONNECTION_UNKNOWN; mContextIds = new int[0]; mPhysicalCellId = PHYSICAL_CELL_ID_UNKNOWN; + mBand = BAND_UNKNOWN; } public PhysicalChannelConfig build() { return new PhysicalChannelConfig(this); } - public Builder setRat(int rat) { - this.mRat = rat; + public @NonNull Builder setNetworkType(@NetworkType int networkType) { + if (!TelephonyManager.isNetworkTypeValid(networkType)) { + throw new IllegalArgumentException("Network type: " + networkType + " is invalid."); + } + mNetworkType = networkType; return this; } - public Builder setFrequencyRange(int frequencyRange) { - this.mFrequencyRange = frequencyRange; + public @NonNull Builder setFrequencyRange(int frequencyRange) { + if (!ServiceState.isFrequencyRangeValid(frequencyRange)) { + throw new IllegalArgumentException("Frequency range: " + frequencyRange + + " is invalid."); + } + mFrequencyRange = frequencyRange; return this; } - public Builder setChannelNumber(int channelNumber) { - this.mChannelNumber = channelNumber; + public @NonNull Builder setDownlinkChannelNumber(int downlinkChannelNumber) { + mDownlinkChannelNumber = downlinkChannelNumber; return this; } - public Builder setCellBandwidthDownlinkKhz(int cellBandwidthDownlinkKhz) { - this.mCellBandwidthDownlinkKhz = cellBandwidthDownlinkKhz; + public @NonNull Builder setUplinkChannelNumber(int uplinkChannelNumber) { + mUplinkChannelNumber = uplinkChannelNumber; return this; } - public Builder setCellConnectionStatus(int connectionStatus) { - this.mCellConnectionStatus = connectionStatus; + public @NonNull Builder setCellBandwidthDownlinkKhz(int cellBandwidthDownlinkKhz) { + if (cellBandwidthDownlinkKhz < CELL_BANDWIDTH_UNKNOWN) { + throw new IllegalArgumentException("Cell downlink bandwidth(kHz): " + + cellBandwidthDownlinkKhz + " is invalid."); + } + mCellBandwidthDownlinkKhz = cellBandwidthDownlinkKhz; return this; } - public Builder setContextIds(int[] contextIds) { + public @NonNull Builder setCellBandwidthUplinkKhz(int cellBandwidthUplinkKhz) { + if (cellBandwidthUplinkKhz < CELL_BANDWIDTH_UNKNOWN) { + throw new IllegalArgumentException("Cell uplink bandwidth(kHz): "+ + cellBandwidthUplinkKhz +" is invalid."); + } + mCellBandwidthUplinkKhz = cellBandwidthUplinkKhz; + return this; + } + + public @NonNull Builder setCellConnectionStatus(int connectionStatus) { + mCellConnectionStatus = connectionStatus; + return this; + } + + public @NonNull Builder setContextIds(int[] contextIds) { if (contextIds != null) Arrays.sort(contextIds); - this.mContextIds = contextIds; + mContextIds = contextIds; return this; } - public Builder setPhysicalCellId(int physicalCellId) { - this.mPhysicalCellId = physicalCellId; + public @NonNull Builder setPhysicalCellId(int physicalCellId) { + if (physicalCellId > PHYSICAL_CELL_ID_MAXIMUM_VALUE) { + throw new IllegalArgumentException("Physical cell Id: " + physicalCellId + + " is over limit."); + } + mPhysicalCellId = physicalCellId; + return this; + } + + public @NonNull Builder setBand(int band) { + if (band <= BAND_UNKNOWN) { + throw new IllegalArgumentException("Band: " + band + + " is invalid."); + } + mBand = band; return this; } } diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java index dedb1afa2495..f110daecd952 100644 --- a/telephony/java/android/telephony/ServiceState.java +++ b/telephony/java/android/telephony/ServiceState.java @@ -2111,4 +2111,23 @@ public class ServiceState implements Parcelable { } return false; } + + /** + * The frequency range is valid or not. + * + * @param frequencyRange The frequency range {@link FrequencyRange}. + * @return {@code true} if valid, {@code false} otherwise. + * + * @hide + */ + public static boolean isFrequencyRangeValid(int frequencyRange) { + if (frequencyRange == FREQUENCY_RANGE_LOW + || frequencyRange == FREQUENCY_RANGE_MID + || frequencyRange == FREQUENCY_RANGE_HIGH + || frequencyRange == FREQUENCY_RANGE_MMWAVE) { + return true; + } else { + return false; + } + } } diff --git a/telephony/java/android/telephony/SignalStrengthUpdateRequest.aidl b/telephony/java/android/telephony/SignalStrengthUpdateRequest.aidl new file mode 100644 index 000000000000..a45de2e58dd1 --- /dev/null +++ b/telephony/java/android/telephony/SignalStrengthUpdateRequest.aidl @@ -0,0 +1,20 @@ +/* +** +** 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.telephony; + +parcelable SignalStrengthUpdateRequest; diff --git a/telephony/java/android/telephony/SignalStrengthUpdateRequest.java b/telephony/java/android/telephony/SignalStrengthUpdateRequest.java new file mode 100644 index 000000000000..af67ed279fab --- /dev/null +++ b/telephony/java/android/telephony/SignalStrengthUpdateRequest.java @@ -0,0 +1,272 @@ +/* + * 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.telephony; + +import android.annotation.NonNull; +import android.os.Binder; +import android.os.IBinder; +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashSet; +import java.util.List; +import java.util.Objects; +import java.util.Set; + +/** + * Request used to register {@link SignalThresholdInfo} to be notified when the signal strength + * breach the specified thresholds. + */ +public final class SignalStrengthUpdateRequest implements Parcelable { + /** + * List of SignalThresholdInfo for the request. + */ + private final List<SignalThresholdInfo> mSignalThresholdInfos; + + /** + * Whether the reporting is required for thresholds in the request while device is idle. + */ + private final boolean mIsReportingRequestedWhileIdle; + + /** + * Whether the reporting requested for system thresholds while device is idle. + * + * System signal thresholds are loaded from carrier config items and mainly used for UI + * displaying. By default, they are ignored when device is idle. When setting the value to true, + * modem will continue reporting signal strength changes over the system signal thresholds even + * device is idle. + * + * This should only set to true by the system caller. + */ + private final boolean mIsSystemThresholdReportingRequestedWhileIdle; + + /** + * A IBinder object as a token for server side to check if the request client is still living. + */ + private final IBinder mLiveToken; + + private SignalStrengthUpdateRequest( + @NonNull List<SignalThresholdInfo> signalThresholdInfos, + boolean isReportingRequestedWhileIdle, + boolean isSystemThresholdReportingRequestedWhileIdle) { + validate(signalThresholdInfos); + + mSignalThresholdInfos = signalThresholdInfos; + mIsReportingRequestedWhileIdle = isReportingRequestedWhileIdle; + mIsSystemThresholdReportingRequestedWhileIdle = + isSystemThresholdReportingRequestedWhileIdle; + mLiveToken = new Binder(); + } + + /** + * Builder class to create {@link SignalStrengthUpdateRequest} object. + */ + public static final class Builder { + private List<SignalThresholdInfo> mSignalThresholdInfos = null; + private boolean mIsReportingRequestedWhileIdle = false; + private boolean mIsSystemThresholdReportingRequestedWhileIdle = false; + + /** + * Set the collection of SignalThresholdInfo for the builder object + * + * @param signalThresholdInfos the collection of SignalThresholdInfo + * + * @return the builder to facilitate the chaining + */ + public @NonNull Builder setSignalThresholdInfos( + @NonNull Collection<SignalThresholdInfo> signalThresholdInfos) { + Objects.requireNonNull(signalThresholdInfos, + "SignalThresholdInfo collection must not be null"); + for (SignalThresholdInfo info : signalThresholdInfos) { + Objects.requireNonNull(info, + "SignalThresholdInfo in the collection must not be null"); + } + + mSignalThresholdInfos = new ArrayList<>(signalThresholdInfos); + // Sort the collection with RAN ascending order, make the ordering not matter for equals + mSignalThresholdInfos.sort( + Comparator.comparingInt(SignalThresholdInfo::getRadioAccessNetworkType)); + return this; + } + + /** + * Set the builder object if require reporting on thresholds in this request when device is + * idle. + * + * @param isReportingRequestedWhileIdle true if request reporting when device is idle + * + * @return the builder to facilitate the chaining + */ + public @NonNull Builder setReportingRequestedWhileIdle( + boolean isReportingRequestedWhileIdle) { + mIsReportingRequestedWhileIdle = isReportingRequestedWhileIdle; + return this; + } + + /** + * Set the builder object if require reporting on the system thresholds when device is idle. + * + * This can only used by the system caller. + * + * @param isSystemThresholdReportingRequestedWhileIdle true if request reporting on the + * system thresholds when device is idle + * @return the builder to facilitate the chaining + * @hide + */ + public @NonNull Builder setSystemThresholdReportingRequestedWhileIdle( + boolean isSystemThresholdReportingRequestedWhileIdle) { + mIsSystemThresholdReportingRequestedWhileIdle = + isSystemThresholdReportingRequestedWhileIdle; + return this; + } + + /** + * Build a {@link SignalStrengthUpdateRequest} object. + * + * @return the SignalStrengthUpdateRequest object + * + * @throws IllegalArgumentException if the SignalThresholdInfo collection is empty size, the + * radio access network type in the collection is not unique + */ + public @NonNull SignalStrengthUpdateRequest build() { + return new SignalStrengthUpdateRequest(mSignalThresholdInfos, + mIsReportingRequestedWhileIdle, mIsSystemThresholdReportingRequestedWhileIdle); + } + } + + private SignalStrengthUpdateRequest(Parcel in) { + mSignalThresholdInfos = in.createTypedArrayList(SignalThresholdInfo.CREATOR); + mIsReportingRequestedWhileIdle = in.readBoolean(); + mIsSystemThresholdReportingRequestedWhileIdle = in.readBoolean(); + mLiveToken = in.readStrongBinder(); + } + + /** + * Get the collection of SignalThresholdInfo in the request. + * + * @return the collection of SignalThresholdInfo + */ + @NonNull + public Collection<SignalThresholdInfo> getSignalThresholdInfos() { + return Collections.unmodifiableList(mSignalThresholdInfos); + } + + /** + * Get whether reporting is requested for the threshold in the request while device is idle. + * + * @return true if reporting requested while device is idle + */ + public boolean isReportingRequestedWhileIdle() { + return mIsReportingRequestedWhileIdle; + } + + /** + * @return true if reporting requested for system thresholds while device is idle + * + * @hide + */ + public boolean isSystemThresholdReportingRequestedWhileIdle() { + return mIsSystemThresholdReportingRequestedWhileIdle; + } + + /* + * @return the live token of the request + * + * @hide + */ + public @NonNull IBinder getLiveToken() { + return mLiveToken; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeTypedList(mSignalThresholdInfos); + dest.writeBoolean(mIsReportingRequestedWhileIdle); + dest.writeBoolean(mIsSystemThresholdReportingRequestedWhileIdle); + dest.writeStrongBinder(mLiveToken); + } + + @Override + public boolean equals(Object other) { + if (this == other) return true; + + if (!(other instanceof SignalStrengthUpdateRequest)) { + return false; + } + + SignalStrengthUpdateRequest request = (SignalStrengthUpdateRequest) other; + return mSignalThresholdInfos.equals(request.mSignalThresholdInfos) + && mIsReportingRequestedWhileIdle == request.mIsReportingRequestedWhileIdle + && mIsSystemThresholdReportingRequestedWhileIdle + == request.mIsSystemThresholdReportingRequestedWhileIdle; + } + + @Override + public int hashCode() { + return Objects.hash(mSignalThresholdInfos, mIsReportingRequestedWhileIdle, + mIsSystemThresholdReportingRequestedWhileIdle); + } + + public static final @NonNull Parcelable.Creator<SignalStrengthUpdateRequest> CREATOR = + new Parcelable.Creator<SignalStrengthUpdateRequest>() { + @Override + public SignalStrengthUpdateRequest createFromParcel(Parcel source) { + return new SignalStrengthUpdateRequest(source); + } + + @Override + public SignalStrengthUpdateRequest[] newArray(int size) { + return new SignalStrengthUpdateRequest[size]; + } + }; + + @Override + public String toString() { + return new StringBuilder("SignalStrengthUpdateRequest{") + .append("mSignalThresholdInfos=") + .append(mSignalThresholdInfos) + .append(" mIsReportingRequestedWhileIdle=") + .append(mIsReportingRequestedWhileIdle) + .append(" mIsSystemThresholdReportingRequestedWhileIdle=") + .append(mIsSystemThresholdReportingRequestedWhileIdle) + .append(" mLiveToken") + .append(mLiveToken) + .append("}").toString(); + } + + /** + * Throw IAE when the RAN in the collection is not unique. + */ + private static void validate(Collection<SignalThresholdInfo> infos) { + Set<Integer> uniqueRan = new HashSet<>(infos.size()); + for (SignalThresholdInfo info : infos) { + final int ran = info.getRadioAccessNetworkType(); + if (!uniqueRan.add(ran)) { + throw new IllegalArgumentException("RAN: " + ran + " is not unique"); + } + } + } +} diff --git a/telephony/java/android/telephony/SignalThresholdInfo.java b/telephony/java/android/telephony/SignalThresholdInfo.java index bb9c0da3f8d4..0059ad6c2426 100644 --- a/telephony/java/android/telephony/SignalThresholdInfo.java +++ b/telephony/java/android/telephony/SignalThresholdInfo.java @@ -280,6 +280,20 @@ public final class SignalThresholdInfo implements Parcelable { public static final int SIGNAL_SSSINR_MAX_VALUE = 40; /** + * The minimum number of thresholds allowed in each SignalThresholdInfo. + * + * @hide + */ + public static final int MINIMUM_NUMBER_OF_THRESHOLDS_ALLOWED = 1; + + /** + * The maximum number of thresholds allowed in each SignalThresholdInfo. + * + * @hide + */ + public static final int MAXIMUM_NUMBER_OF_THRESHOLDS_ALLOWED = 4; + + /** * Constructor * * @param ran Radio Access Network type @@ -368,7 +382,11 @@ public final class SignalThresholdInfo implements Parcelable { /** * Set the signal strength thresholds of the corresponding signal measurement type. * - * The range and unit must reference specific SignalMeasurementType. + * The range and unit must reference specific SignalMeasurementType. The length of the + * thresholds should between the numbers return from + * {@link #getMinimumNumberOfThresholdsAllowed()} and + * {@link #getMaximumNumberOfThresholdsAllowed()}. An IllegalArgumentException will throw + * otherwise. * * @param thresholds array of integer as the signal threshold values * @return the builder to facilitate the chaining @@ -385,11 +403,34 @@ public final class SignalThresholdInfo implements Parcelable { */ public @NonNull Builder setThresholds(@NonNull int[] thresholds) { Objects.requireNonNull(thresholds, "thresholds must not be null"); + if (thresholds.length < MINIMUM_NUMBER_OF_THRESHOLDS_ALLOWED + || thresholds.length > MAXIMUM_NUMBER_OF_THRESHOLDS_ALLOWED) { + throw new IllegalArgumentException( + "thresholds length must between " + MINIMUM_NUMBER_OF_THRESHOLDS_ALLOWED + + " and " + MAXIMUM_NUMBER_OF_THRESHOLDS_ALLOWED); + } + mThresholds = thresholds.clone(); + Arrays.sort(mThresholds); + return this; + } + + /** + * Set the signal strength thresholds for the corresponding signal measurement type without + * the length limitation. + * + * @param thresholds array of integer as the signal threshold values + * @return the builder to facilitate the chaining + * + * @hide + */ + public @NonNull Builder setThresholdsUnlimited(@NonNull int[] thresholds) { + Objects.requireNonNull(thresholds, "thresholds must not be null"); mThresholds = thresholds.clone(); Arrays.sort(mThresholds); return this; } + /** * Set if the modem should trigger the report based on the criteria. * @@ -474,6 +515,24 @@ public final class SignalThresholdInfo implements Parcelable { return mThresholds.clone(); } + /** + * Get the minimum number of thresholds allowed in each SignalThresholdInfo. + * + * @return the minimum number of thresholds allowed + */ + public static int getMinimumNumberOfThresholdsAllowed() { + return MINIMUM_NUMBER_OF_THRESHOLDS_ALLOWED; + } + + /** + * Get the maximum number of threshold allowed in each SignalThresholdInfo. + * + * @return the maximum number of thresholds allowed + */ + public static int getMaximumNumberOfThresholdsAllowed() { + return MAXIMUM_NUMBER_OF_THRESHOLDS_ALLOWED; + } + @Override public int describeContents() { return 0; diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java index bcc2c67bd8e7..b958bff6d00b 100644 --- a/telephony/java/android/telephony/SmsManager.java +++ b/telephony/java/android/telephony/SmsManager.java @@ -345,7 +345,6 @@ public final class SmsManager { * where this operation may fail. * </p> * - * * @param destinationAddress the address to send the message to * @param scAddress is the service center address or null to use * the current default SMSC @@ -358,7 +357,6 @@ public final class SmsManager { * <code>RESULT_ERROR_RADIO_OFF</code><br> * <code>RESULT_ERROR_NULL_PDU</code><br> * <code>RESULT_ERROR_NO_SERVICE</code><br> - * <code>RESULT_ERROR_NO_SERVICE</code><br> * <code>RESULT_ERROR_LIMIT_EXCEEDED</code><br> * <code>RESULT_ERROR_FDN_CHECK_FAILURE</code><br> * <code>RESULT_ERROR_SHORT_CODE_NOT_ALLOWED</code><br> @@ -473,7 +471,6 @@ public final class SmsManager { * <code>RESULT_ERROR_RADIO_OFF</code><br> * <code>RESULT_ERROR_NULL_PDU</code><br> * <code>RESULT_ERROR_NO_SERVICE</code><br> - * <code>RESULT_ERROR_NO_SERVICE</code><br> * <code>RESULT_ERROR_LIMIT_EXCEEDED</code><br> * <code>RESULT_ERROR_FDN_CHECK_FAILURE</code><br> * <code>RESULT_ERROR_SHORT_CODE_NOT_ALLOWED</code><br> @@ -862,22 +859,20 @@ public final class SmsManager { * where this operation may fail. * </p> * - * * @param destinationAddress the address to send the message to * @param scAddress is the service center address or null to use - * the current default SMSC + * the current default SMSC * @param parts an <code>ArrayList</code> of strings that, in order, - * comprise the original message + * comprise the original message * @param sentIntents if not null, an <code>ArrayList</code> of - * <code>PendingIntent</code>s (one for each message part) that is - * broadcast when the corresponding message part has been sent. - * The result code will be <code>Activity.RESULT_OK</code> for success, - * or one of these errors:<br> + * <code>PendingIntent</code>s (one for each message part) that is + * broadcast when the corresponding message part has been sent. + * The result code will be <code>Activity.RESULT_OK</code> for success, + * or one of these errors:<br> * <code>RESULT_ERROR_GENERIC_FAILURE</code><br> * <code>RESULT_ERROR_RADIO_OFF</code><br> * <code>RESULT_ERROR_NULL_PDU</code><br> * <code>RESULT_ERROR_NO_SERVICE</code><br> - * <code>RESULT_ERROR_NO_SERVICE</code><br> * <code>RESULT_ERROR_LIMIT_EXCEEDED</code><br> * <code>RESULT_ERROR_FDN_CHECK_FAILURE</code><br> * <code>RESULT_ERROR_SHORT_CODE_NOT_ALLOWED</code><br> @@ -933,14 +928,14 @@ public final class SmsManager { * For <code>RESULT_ERROR_GENERIC_FAILURE</code> or any of the RESULT_RIL errors, * the sentIntent may include the extra "errorCode" containing a radio technology specific * value, generally only useful for troubleshooting.<br> - * The per-application based SMS control checks sentIntent. If sentIntent - * is NULL the caller will be checked against all unknown applications, - * which cause smaller number of SMS to be sent in checking period. + * The per-application based SMS control checks sentIntent. If sentIntent + * is NULL the caller will be checked against all unknown applications, + * which cause smaller number of SMS to be sent in checking period. * @param deliveryIntents if not null, an <code>ArrayList</code> of - * <code>PendingIntent</code>s (one for each message part) that is - * broadcast when the corresponding message part has been delivered - * to the recipient. The raw pdu of the status report is in the - * extended data ("pdu"). + * <code>PendingIntent</code>s (one for each message part) that is + * broadcast when the corresponding message part has been delivered + * to the recipient. The raw pdu of the status report is in the + * extended data ("pdu"). * * @throws IllegalArgumentException if destinationAddress or data are empty */ @@ -1123,22 +1118,21 @@ public final class SmsManager { * boolean value {@code true}. See {@link #getDefault()} for more information on the conditions * where this operation may fail. * </p> - + * * @param destinationAddress the address to send the message to * @param scAddress is the service center address or null to use - * the current default SMSC + * the current default SMSC * @param parts an <code>ArrayList</code> of strings that, in order, - * comprise the original message + * comprise the original message * @param sentIntents if not null, an <code>ArrayList</code> of - * <code>PendingIntent</code>s (one for each message part) that is - * broadcast when the corresponding message part has been sent. - * The result code will be <code>Activity.RESULT_OK</code> for success, - * or one of these errors:<br> + * <code>PendingIntent</code>s (one for each message part) that is + * broadcast when the corresponding message part has been sent. + * The result code will be <code>Activity.RESULT_OK</code> for success, + * or one of these errors:<br> * <code>RESULT_ERROR_GENERIC_FAILURE</code><br> * <code>RESULT_ERROR_RADIO_OFF</code><br> * <code>RESULT_ERROR_NULL_PDU</code><br> * <code>RESULT_ERROR_NO_SERVICE</code><br> - * <code>RESULT_ERROR_NO_SERVICE</code><br> * <code>RESULT_ERROR_LIMIT_EXCEEDED</code><br> * <code>RESULT_ERROR_FDN_CHECK_FAILURE</code><br> * <code>RESULT_ERROR_SHORT_CODE_NOT_ALLOWED</code><br> @@ -1194,14 +1188,14 @@ public final class SmsManager { * For <code>RESULT_ERROR_GENERIC_FAILURE</code> or any of the RESULT_RIL errors, * the sentIntent may include the extra "errorCode" containing a radio technology specific * value, generally only useful for troubleshooting.<br> - * The per-application based SMS control checks sentIntent. If sentIntent - * is NULL the caller will be checked against all unknown applications, - * which cause smaller number of SMS to be sent in checking period. + * The per-application based SMS control checks sentIntent. If sentIntent + * is NULL the caller will be checked against all unknown applications, + * which cause smaller number of SMS to be sent in checking period. * @param deliveryIntents if not null, an <code>ArrayList</code> of - * <code>PendingIntent</code>s (one for each message part) that is - * broadcast when the corresponding message part has been delivered - * to the recipient. The raw pdu of the status report is in the - * extended data ("pdu"). + * <code>PendingIntent</code>s (one for each message part) that is + * broadcast when the corresponding message part has been delivered + * to the recipient. The raw pdu of the status report is in the + * extended data ("pdu"). * @param priority Priority level of the message * Refer specification See 3GPP2 C.S0015-B, v2.0, table 4.5.9-1 * --------------------------------- @@ -1340,7 +1334,6 @@ public final class SmsManager { * <code>RESULT_ERROR_RADIO_OFF</code><br> * <code>RESULT_ERROR_NULL_PDU</code><br> * <code>RESULT_ERROR_NO_SERVICE</code><br> - * <code>RESULT_ERROR_NO_SERVICE</code><br> * <code>RESULT_ERROR_LIMIT_EXCEEDED</code><br> * <code>RESULT_ERROR_FDN_CHECK_FAILURE</code><br> * <code>RESULT_ERROR_SHORT_CODE_NOT_ALLOWED</code><br> diff --git a/telephony/java/android/telephony/TelephonyDisplayInfo.java b/telephony/java/android/telephony/TelephonyDisplayInfo.java index 3d5c6aad1042..1fcb504e7895 100644 --- a/telephony/java/android/telephony/TelephonyDisplayInfo.java +++ b/telephony/java/android/telephony/TelephonyDisplayInfo.java @@ -29,6 +29,10 @@ import java.util.Objects; * information is provided in accordance with carrier policy and branding preferences; it is not * necessarily a precise or accurate representation of the current state and should be treated * accordingly. + * To be notified of changes in TelephonyDisplayInfo, use + * {@link TelephonyManager#registerPhoneStateListener} with a {@link PhoneStateListener} + * that implements {@link PhoneStateListener.DisplayInfoChangedListener}. + * Override the onDisplayInfoChanged() method to handle the broadcast. */ public final class TelephonyDisplayInfo implements Parcelable { /** diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index f39ee095758c..f018f2fffc3a 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -120,6 +120,7 @@ import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Map; @@ -7456,18 +7457,23 @@ public class TelephonyManager { } /** - * Set IMS registration state + * Set IMS registration state on all active subscriptions. + * <p/> + * Use {@link android.telephony.ims.stub.ImsRegistrationImplBase#onRegistered} and + * {@link android.telephony.ims.stub.ImsRegistrationImplBase#onDeregistered} to set Ims + * registration state instead. + * + * @param registered whether ims is registered * - * @param Registration state * @hide */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public void setImsRegistrationState(boolean registered) { + public void setImsRegistrationState(final boolean registered) { try { - ITelephony telephony = getITelephony(); + final ITelephony telephony = getITelephony(); if (telephony != null) telephony.setImsRegistrationState(registered); - } catch (RemoteException e) { + } catch (final RemoteException e) { } } @@ -9456,9 +9462,16 @@ public class TelephonyManager { * @return true if mobile data is enabled. */ @RequiresPermission(anyOf = {android.Manifest.permission.ACCESS_NETWORK_STATE, - android.Manifest.permission.MODIFY_PHONE_STATE}) + android.Manifest.permission.MODIFY_PHONE_STATE, + android.Manifest.permission.READ_PHONE_STATE}) public boolean isDataEnabled() { - return getDataEnabled(getSubId(SubscriptionManager.getDefaultDataSubscriptionId())); + try { + return isDataEnabledForReason(DATA_ENABLED_REASON_USER); + } catch (IllegalStateException ise) { + // TODO(b/176163590): Remove this catch once TelephonyManager is booting safely. + Log.e(TAG, "Error calling #isDataEnabled, returning default (false).", ise); + return false; + } } /** @@ -9703,7 +9716,7 @@ public class TelephonyManager { @SystemApi public boolean getDataEnabled(int subId) { try { - return isDataEnabledForReason(DATA_ENABLED_REASON_USER); + return isDataEnabledForReason(subId, DATA_ENABLED_REASON_USER); } catch (RuntimeException e) { Log.e(TAG, "Error calling isDataEnabledForReason e:" + e); } @@ -14668,4 +14681,98 @@ public class TelephonyManager { throw new IllegalStateException("telephony service is null."); } } + + /** + * The network type is valid or not. + * + * @param networkType The network type {@link NetworkType}. + * @return {@code true} if valid, {@code false} otherwise. + * + * @hide + */ + public static boolean isNetworkTypeValid(@NetworkType int networkType) { + return networkType >= TelephonyManager.NETWORK_TYPE_UNKNOWN && + networkType <= TelephonyManager.NETWORK_TYPE_NR; + } + + /** + * Set a {@link SignalStrengthUpdateRequest} to receive notification when signal quality + * measurements breach the specified thresholds. + * + * To be notified, set the signal strength update request and then register + * {@link TelephonyManager#listen(PhoneStateListener, int)} with + * {@link PhoneStateListener#LISTEN_SIGNAL_STRENGTHS}. The notification will arrive through + * {@link PhoneStateListener#onSignalStrengthsChanged(SignalStrength)}. + * + * To stop receiving the notification over the specified thresholds, pass the same + * {@link SignalStrengthUpdateRequest} object to + * {@link #clearSignalStrengthUpdateRequest(SignalStrengthUpdateRequest)}. + * + * System will clean up the {@link SignalStrengthUpdateRequest} if the caller process died + * without calling {@link #clearSignalStrengthUpdateRequest(SignalStrengthUpdateRequest)}. + * + * If this TelephonyManager object has been created with {@link #createForSubscriptionId}, + * applies to the given subId. Otherwise, applies to + * {@link SubscriptionManager#getDefaultSubscriptionId()}. To request for multiple subIds, + * pass a request object to each TelephonyManager object created with + * {@link #createForSubscriptionId}. + * + * <p>Requires Permission: + * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} + * or that the calling app has carrier privileges (see + * {@link TelephonyManager#hasCarrierPrivileges}). + * + * Note that the thresholds in the request will be used on a best-effort basis; the system may + * modify requests to multiplex various request sources or to optimize power consumption. The + * caller should not expect to be notified with the exactly the same thresholds. + * + * @see #clearSignalStrengthUpdateRequest(SignalStrengthUpdateRequest) + * + * @param request the SignalStrengthUpdateRequest to be set into the System + * + * @throws IllegalStateException if a new request is set with same subId from the same caller + */ + @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges + @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + public void setSignalStrengthUpdateRequest(@NonNull SignalStrengthUpdateRequest request) { + Objects.requireNonNull(request, "request must not be null"); + + try { + ITelephony service = getITelephony(); + if (service != null) { + service.setSignalStrengthUpdateRequest(getSubId(), request, getOpPackageName()); + } + } catch (RemoteException e) { + Log.e(TAG, "Error calling ITelephony#setSignalStrengthUpdateRequest", e); + } + } + + /** + * Clear a {@link SignalStrengthUpdateRequest} from the system. + * + * <p>Requires Permission: + * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} + * or that the calling app has carrier privileges (see + * {@link TelephonyManager#hasCarrierPrivileges}). + * + * <p>If the given request was not set before, this operation is a no-op. + * + * @see #setSignalStrengthUpdateRequest(SignalStrengthUpdateRequest) + * + * @param request the SignalStrengthUpdateRequest to be cleared from the System + */ + @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges + @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + public void clearSignalStrengthUpdateRequest(@NonNull SignalStrengthUpdateRequest request) { + Objects.requireNonNull(request, "request must not be null"); + + try { + ITelephony service = getITelephony(); + if (service != null) { + service.clearSignalStrengthUpdateRequest(getSubId(), request, getOpPackageName()); + } + } catch (RemoteException e) { + Log.e(TAG, "Error calling ITelephony#clearSignalStrengthUpdateRequest", e); + } + } } diff --git a/telephony/java/android/telephony/ims/RegistrationManager.java b/telephony/java/android/telephony/ims/RegistrationManager.java index e085dec10546..2c75368b86bf 100644 --- a/telephony/java/android/telephony/ims/RegistrationManager.java +++ b/telephony/java/android/telephony/ims/RegistrationManager.java @@ -25,6 +25,7 @@ import android.annotation.RequiresPermission; import android.net.Uri; import android.os.Binder; import android.telephony.AccessNetworkConstants; +import android.telephony.NetworkRegistrationInfo; import android.telephony.ims.aidl.IImsRegistrationCallback; import android.telephony.ims.feature.ImsFeature; import android.telephony.ims.stub.ImsRegistrationImplBase; @@ -85,6 +86,22 @@ public interface RegistrationManager { AccessNetworkConstants.TRANSPORT_TYPE_WLAN); }}; + /** @hide */ + @NonNull + static String registrationStateToString( + final @NetworkRegistrationInfo.RegistrationState int value) { + switch (value) { + case REGISTRATION_STATE_NOT_REGISTERED: + return "REGISTRATION_STATE_NOT_REGISTERED"; + case REGISTRATION_STATE_REGISTERING: + return "REGISTRATION_STATE_REGISTERING"; + case REGISTRATION_STATE_REGISTERED: + return "REGISTRATION_STATE_REGISTERED"; + default: + return Integer.toString(value); + } + } + /** * Callback class for receiving IMS network Registration callback events. * @see #registerImsRegistrationCallback(Executor, RegistrationCallback) diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index 541ec040d4dd..f5662692d84b 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -49,6 +49,7 @@ import android.telephony.RadioAccessFamily; import android.telephony.RadioAccessSpecifier; import android.telephony.ServiceState; import android.telephony.SignalStrength; +import android.telephony.SignalStrengthUpdateRequest; import android.telephony.TelephonyHistogram; import android.telephony.VisualVoicemailSmsFilterSettings; import android.telephony.emergency.EmergencyNumber; @@ -2367,4 +2368,17 @@ interface ITelephony { * their mobile plan. */ String getMobileProvisioningUrl(); + + /** + * Set a SignalStrengthUpdateRequest to receive notification when Signal Strength breach the + * specified thresholds. + */ + void setSignalStrengthUpdateRequest(int subId, in SignalStrengthUpdateRequest request, + String callingPackage); + + /** + * Clear a SignalStrengthUpdateRequest from system. + */ + void clearSignalStrengthUpdateRequest(int subId, in SignalStrengthUpdateRequest request, + String callingPackage); } diff --git a/test-mock/api/current.txt b/test-mock/api/current.txt index 1110790c373f..d1a68d4e9cb2 100644 --- a/test-mock/api/current.txt +++ b/test-mock/api/current.txt @@ -117,6 +117,7 @@ package android.test.mock { method public void sendOrderedBroadcast(android.content.Intent, String, android.content.BroadcastReceiver, android.os.Handler, int, String, android.os.Bundle); method public void sendOrderedBroadcastAsUser(android.content.Intent, android.os.UserHandle, String, android.content.BroadcastReceiver, android.os.Handler, int, String, android.os.Bundle); method public void sendStickyBroadcast(android.content.Intent); + method public void sendStickyBroadcast(android.content.Intent, android.os.Bundle); method public void sendStickyBroadcastAsUser(android.content.Intent, android.os.UserHandle); method public void sendStickyOrderedBroadcast(android.content.Intent, android.content.BroadcastReceiver, android.os.Handler, int, String, android.os.Bundle); method public void sendStickyOrderedBroadcastAsUser(android.content.Intent, android.os.UserHandle, android.content.BroadcastReceiver, android.os.Handler, int, String, android.os.Bundle); diff --git a/test-mock/src/android/test/mock/MockContext.java b/test-mock/src/android/test/mock/MockContext.java index cf3b03cae72e..6046d78240b6 100644 --- a/test-mock/src/android/test/mock/MockContext.java +++ b/test-mock/src/android/test/mock/MockContext.java @@ -493,6 +493,11 @@ public class MockContext extends Context { } @Override + public void sendStickyBroadcast(Intent intent, Bundle options) { + throw new UnsupportedOperationException(); + } + + @Override public void sendStickyOrderedBroadcast(Intent intent, BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData, Bundle initialExtras) { diff --git a/tests/net/common/java/android/net/CaptivePortalDataTest.kt b/tests/net/common/java/android/net/CaptivePortalDataTest.kt index 2cb16d3372d7..b2bcfeb9019d 100644 --- a/tests/net/common/java/android/net/CaptivePortalDataTest.kt +++ b/tests/net/common/java/android/net/CaptivePortalDataTest.kt @@ -58,7 +58,8 @@ class CaptivePortalDataTest { @Test fun testParcelUnparcel() { - assertParcelSane(data, fieldCount = 8) + val fieldCount = if (SdkLevel.isAtLeastS()) 8 else 7 + assertParcelSane(data, fieldCount) assertParcelingIsLossless(makeBuilder().setUserPortalUrl(null).build()) assertParcelingIsLossless(makeBuilder().setVenueInfoUrl(null).build()) diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index abf16f2a39ad..37307a46b8ac 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -21,6 +21,7 @@ import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS; import static android.app.PendingIntent.FLAG_IMMUTABLE; import static android.content.Intent.ACTION_USER_ADDED; import static android.content.Intent.ACTION_USER_REMOVED; +import static android.content.Intent.ACTION_USER_UNLOCKED; import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED; import static android.content.pm.PackageManager.GET_PERMISSIONS; import static android.content.pm.PackageManager.MATCH_ANY_USER; @@ -221,6 +222,7 @@ import android.os.SystemClock; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; +import android.security.Credentials; import android.security.KeyStore; import android.system.Os; import android.telephony.TelephonyManager; @@ -237,6 +239,7 @@ import androidx.test.runner.AndroidJUnit4; import com.android.internal.app.IBatteryStats; import com.android.internal.net.VpnConfig; import com.android.internal.net.VpnInfo; +import com.android.internal.net.VpnProfile; import com.android.internal.util.ArrayUtils; import com.android.internal.util.WakeupMessage; import com.android.internal.util.test.BroadcastInterceptingContext; @@ -279,6 +282,7 @@ import java.net.Inet6Address; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.Socket; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -384,6 +388,7 @@ public class ConnectivityServiceTest { @Mock MockableSystemProperties mSystemProperties; @Mock EthernetManager mEthernetManager; @Mock NetworkPolicyManager mNetworkPolicyManager; + @Mock KeyStore mKeyStore; private ArgumentCaptor<ResolverParamsParcel> mResolverParamsParcelCaptor = ArgumentCaptor.forClass(ResolverParamsParcel.class); @@ -1062,6 +1067,15 @@ public class ConnectivityServiceTest { private int mVpnType = VpnManager.TYPE_VPN_SERVICE; private VpnInfo mVpnInfo; + // These ConditionVariables allow tests to wait for LegacyVpnRunner to be stopped/started. + // TODO: this scheme is ad-hoc and error-prone because it does not fail if, for example, the + // test expects two starts in a row, or even if the production code calls start twice in a + // row. find a better solution. Simply putting a method to create a LegacyVpnRunner into + // Vpn.Dependencies doesn't work because LegacyVpnRunner is not a static class and has + // extensive access into the internals of Vpn. + private ConditionVariable mStartLegacyVpnCv = new ConditionVariable(); + private ConditionVariable mStopVpnRunnerCv = new ConditionVariable(); + public MockVpn(int userId) { super(startHandlerThreadAndReturnLooper(), mServiceContext, new Dependencies() { @@ -1075,7 +1089,7 @@ public class ConnectivityServiceTest { return mDeviceIdleInternal; } }, - mNetworkManagementService, mMockNetd, userId, mock(KeyStore.class)); + mNetworkManagementService, mMockNetd, userId, mKeyStore); } public void setUids(Set<UidRange> uids) { @@ -1187,10 +1201,44 @@ public class ConnectivityServiceTest { } mAgentRegistered = false; setUids(null); + // Remove NET_CAPABILITY_INTERNET or MockNetworkAgent will refuse to connect later on. + mNetworkCapabilities.removeCapability(NET_CAPABILITY_INTERNET); mInterface = null; } @Override + public void startLegacyVpnRunner() { + mStartLegacyVpnCv.open(); + } + + public void expectStartLegacyVpnRunner() { + assertTrue("startLegacyVpnRunner not called after " + TIMEOUT_MS + " ms", + mStartLegacyVpnCv.block(TIMEOUT_MS)); + + // startLegacyVpn calls stopVpnRunnerPrivileged, which will open mStopVpnRunnerCv, just + // before calling startLegacyVpnRunner. Restore mStopVpnRunnerCv, so the test can expect + // that the VpnRunner is stopped and immediately restarted by calling + // expectStartLegacyVpnRunner() and expectStopVpnRunnerPrivileged() back-to-back. + mStopVpnRunnerCv = new ConditionVariable(); + } + + @Override + public void stopVpnRunnerPrivileged() { + if (mVpnRunner != null) { + super.stopVpnRunnerPrivileged(); + disconnect(); + mStartLegacyVpnCv = new ConditionVariable(); + } + mVpnRunner = null; + mStopVpnRunnerCv.open(); + } + + public void expectStopVpnRunnerPrivileged() { + assertTrue("stopVpnRunnerPrivileged not called after " + TIMEOUT_MS + " ms", + mStopVpnRunnerCv.block(TIMEOUT_MS)); + } + + @Override public synchronized VpnInfo getVpnInfo() { if (mVpnInfo != null) return mVpnInfo; @@ -1271,10 +1319,19 @@ public class ConnectivityServiceTest { } } - private static final int VPN_USER = 0; - private static final int APP1_UID = UserHandle.getUid(VPN_USER, 10100); - private static final int APP2_UID = UserHandle.getUid(VPN_USER, 10101); - private static final int VPN_UID = UserHandle.getUid(VPN_USER, 10043); + private static final int PRIMARY_USER = 0; + private static final int APP1_UID = UserHandle.getUid(PRIMARY_USER, 10100); + private static final int APP2_UID = UserHandle.getUid(PRIMARY_USER, 10101); + private static final int VPN_UID = UserHandle.getUid(PRIMARY_USER, 10043); + private static final UserInfo PRIMARY_USER_INFO = new UserInfo(PRIMARY_USER, "", + UserInfo.FLAG_PRIMARY); + + private static final int RESTRICTED_USER = 1; + private static final UserInfo RESTRICTED_USER_INFO = new UserInfo(RESTRICTED_USER, "", + UserInfo.FLAG_RESTRICTED); + static { + RESTRICTED_USER_INFO.restrictedProfileParentId = PRIMARY_USER; + } @Before public void setUp() throws Exception { @@ -1284,10 +1341,13 @@ public class ConnectivityServiceTest { MockitoAnnotations.initMocks(this); - when(mUserManager.getAliveUsers()).thenReturn( - Arrays.asList(new UserInfo[] { - new UserInfo(VPN_USER, "", 0), - })); + when(mUserManager.getAliveUsers()).thenReturn(Arrays.asList(PRIMARY_USER_INFO)); + when(mUserManager.getUserInfo(PRIMARY_USER)).thenReturn(PRIMARY_USER_INFO); + // canHaveRestrictedProfile does not take a userId. It applies to the userId of the context + // it was started from, i.e., PRIMARY_USER. + when(mUserManager.canHaveRestrictedProfile()).thenReturn(true); + when(mUserManager.getUserInfo(RESTRICTED_USER)).thenReturn(RESTRICTED_USER_INFO); + final ApplicationInfo applicationInfo = new ApplicationInfo(); applicationInfo.targetSdkVersion = Build.VERSION_CODES.Q; when(mPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), any())) @@ -1359,6 +1419,7 @@ public class ConnectivityServiceTest { doReturn(mock(ProxyTracker.class)).when(deps).makeProxyTracker(any(), any()); doReturn(true).when(deps).queryUserAccess(anyInt(), anyInt()); doReturn(mBatteryStatsService).when(deps).getBatteryStatsService(); + doReturn(mKeyStore).when(deps).getKeyStore(); doAnswer(inv -> { mPolicyTracker = new WrappedMultinetworkPolicyTracker( inv.getArgument(0), inv.getArgument(1), inv.getArgument(2)); @@ -1527,7 +1588,7 @@ public class ConnectivityServiceTest { waitForIdle(); try { final Intent intent = get(timeoutMs, TimeUnit.MILLISECONDS); - fail("Unexpected broadcast: " + intent.getAction()); + fail("Unexpected broadcast: " + intent.getAction() + " " + intent.getExtras()); } catch (TimeoutException expected) { } finally { mServiceContext.unregisterReceiver(mReceiver); @@ -5831,6 +5892,131 @@ public class ConnectivityServiceTest { mCm.unregisterNetworkCallback(callback); } + private void assertGetNetworkInfoOfGetActiveNetworkIsConnected(boolean expectedConnectivity) { + // What Chromium used to do before https://chromium-review.googlesource.com/2605304 + assertEquals("Unexpected result for getActiveNetworkInfo(getActiveNetwork())", + expectedConnectivity, mCm.getNetworkInfo(mCm.getActiveNetwork()).isConnected()); + } + + @Test + public void testVpnUnderlyingNetworkSuspended() throws Exception { + final TestNetworkCallback callback = new TestNetworkCallback(); + mCm.registerDefaultNetworkCallback(callback); + + // Connect a VPN. + mMockVpn.establishForMyUid(false /* validated */, true /* hasInternet */, + false /* isStrictMode */); + callback.expectAvailableCallbacksUnvalidated(mMockVpn); + + // Connect cellular data. + mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR); + mCellNetworkAgent.connect(false /* validated */); + callback.expectCapabilitiesThat(mMockVpn, + nc -> nc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED) + && nc.hasTransport(TRANSPORT_CELLULAR)); + callback.assertNoCallback(); + + assertTrue(mCm.getNetworkCapabilities(mMockVpn.getNetwork()) + .hasCapability(NET_CAPABILITY_NOT_SUSPENDED)); + assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED); + assertNetworkInfo(TYPE_WIFI, DetailedState.DISCONNECTED); + assertNetworkInfo(TYPE_VPN, DetailedState.CONNECTED); + assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED); + assertGetNetworkInfoOfGetActiveNetworkIsConnected(true); + + // Suspend the cellular network and expect the VPN to be suspended. + mCellNetworkAgent.suspend(); + callback.expectCapabilitiesThat(mMockVpn, + nc -> !nc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED) + && nc.hasTransport(TRANSPORT_CELLULAR)); + callback.expectCallback(CallbackEntry.SUSPENDED, mMockVpn); + callback.assertNoCallback(); + + assertFalse(mCm.getNetworkCapabilities(mMockVpn.getNetwork()) + .hasCapability(NET_CAPABILITY_NOT_SUSPENDED)); + assertNetworkInfo(TYPE_MOBILE, DetailedState.SUSPENDED); + assertNetworkInfo(TYPE_WIFI, DetailedState.DISCONNECTED); + assertNetworkInfo(TYPE_VPN, DetailedState.SUSPENDED); + assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.SUSPENDED); + // VPN's main underlying network is suspended, so no connectivity. + assertGetNetworkInfoOfGetActiveNetworkIsConnected(false); + + // Switch to another network. The VPN should no longer be suspended. + mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiNetworkAgent.connect(false /* validated */); + callback.expectCapabilitiesThat(mMockVpn, + nc -> nc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED) + && nc.hasTransport(TRANSPORT_WIFI)); + + // BUG: the VPN is no longer suspended, so a RESUMED callback should have been sent. + // callback.expectCallback(CallbackEntry.RESUMED, mMockVpn); + callback.assertNoCallback(); + + assertTrue(mCm.getNetworkCapabilities(mMockVpn.getNetwork()) + .hasCapability(NET_CAPABILITY_NOT_SUSPENDED)); + assertNetworkInfo(TYPE_MOBILE, DetailedState.DISCONNECTED); + assertNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED); + assertNetworkInfo(TYPE_VPN, DetailedState.SUSPENDED); // BUG: VPN caps have NOT_SUSPENDED. + assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED); + // BUG: the device has connectivity, so this should return true. + assertGetNetworkInfoOfGetActiveNetworkIsConnected(false); + + // Unsuspend cellular and then switch back to it. + // The same bug happens in the opposite direction: the VPN's capabilities correctly have + // NOT_SUSPENDED, but the VPN's NetworkInfo is in state SUSPENDED. + mCellNetworkAgent.resume(); + callback.assertNoCallback(); + mWiFiNetworkAgent.disconnect(); + callback.expectCapabilitiesThat(mMockVpn, + nc -> nc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED) + && nc.hasTransport(TRANSPORT_CELLULAR)); + // Spurious double callback? + callback.expectCapabilitiesThat(mMockVpn, + nc -> nc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED) + && nc.hasTransport(TRANSPORT_CELLULAR)); + callback.assertNoCallback(); + + assertTrue(mCm.getNetworkCapabilities(mMockVpn.getNetwork()) + .hasCapability(NET_CAPABILITY_NOT_SUSPENDED)); + assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED); + assertNetworkInfo(TYPE_WIFI, DetailedState.DISCONNECTED); + assertNetworkInfo(TYPE_VPN, DetailedState.SUSPENDED); // BUG: VPN caps have NOT_SUSPENDED. + assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED); + // BUG: the device has connectivity, so this should return true. + assertGetNetworkInfoOfGetActiveNetworkIsConnected(false); + + // Re-suspending the current network fixes the problem. + mCellNetworkAgent.suspend(); + callback.expectCapabilitiesThat(mMockVpn, + nc -> !nc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED) + && nc.hasTransport(TRANSPORT_CELLULAR)); + callback.expectCallback(CallbackEntry.SUSPENDED, mMockVpn); + callback.assertNoCallback(); + + assertFalse(mCm.getNetworkCapabilities(mMockVpn.getNetwork()) + .hasCapability(NET_CAPABILITY_NOT_SUSPENDED)); + assertNetworkInfo(TYPE_MOBILE, DetailedState.SUSPENDED); + assertNetworkInfo(TYPE_WIFI, DetailedState.DISCONNECTED); + assertNetworkInfo(TYPE_VPN, DetailedState.SUSPENDED); + assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.SUSPENDED); + assertGetNetworkInfoOfGetActiveNetworkIsConnected(false); + + mCellNetworkAgent.resume(); + callback.expectCapabilitiesThat(mMockVpn, + nc -> nc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED) + && nc.hasTransport(TRANSPORT_CELLULAR)); + callback.expectCallback(CallbackEntry.RESUMED, mMockVpn); + callback.assertNoCallback(); + + assertTrue(mCm.getNetworkCapabilities(mMockVpn.getNetwork()) + .hasCapability(NET_CAPABILITY_NOT_SUSPENDED)); + assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED); + assertNetworkInfo(TYPE_WIFI, DetailedState.DISCONNECTED); + assertNetworkInfo(TYPE_VPN, DetailedState.CONNECTED); + assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED); + assertGetNetworkInfoOfGetActiveNetworkIsConnected(true); + } + @Test public void testVpnNetworkActive() throws Exception { final int uid = Process.myUid(); @@ -6309,7 +6495,7 @@ public class ConnectivityServiceTest { } @Test - public void testVpnRestrictedUsers() throws Exception { + public void testRestrictedProfileAffectsVpnUidRanges() throws Exception { // NETWORK_SETTINGS is necessary to see the UID ranges in NetworkCapabilities. mServiceContext.setPermission(Manifest.permission.NETWORK_SETTINGS, PERMISSION_GRANTED); @@ -6341,19 +6527,11 @@ public class ConnectivityServiceTest { callback.expectCapabilitiesThat(mWiFiNetworkAgent, (caps) -> caps.hasCapability(NET_CAPABILITY_VALIDATED)); - // Create a fake restricted profile whose parent is our user ID. - final int userId = UserHandle.getUserId(uid); - when(mUserManager.canHaveRestrictedProfile()).thenReturn(true); - final int restrictedUserId = userId + 1; - final UserInfo info = new UserInfo(restrictedUserId, "user", UserInfo.FLAG_RESTRICTED); - info.restrictedProfileParentId = userId; - assertTrue(info.isRestricted()); - when(mUserManager.getUserInfo(restrictedUserId)).thenReturn(info); - when(mPackageManager.getPackageUidAsUser(ALWAYS_ON_PACKAGE, restrictedUserId)) - .thenReturn(UserHandle.getUid(restrictedUserId, VPN_UID)); + when(mPackageManager.getPackageUidAsUser(ALWAYS_ON_PACKAGE, RESTRICTED_USER)) + .thenReturn(UserHandle.getUid(RESTRICTED_USER, VPN_UID)); final Intent addedIntent = new Intent(ACTION_USER_ADDED); - addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, restrictedUserId); + addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, RESTRICTED_USER); // Send a USER_ADDED broadcast for it. // The BroadcastReceiver for this broadcast checks that is being run on the handler thread. @@ -6365,7 +6543,7 @@ public class ConnectivityServiceTest { callback.expectCapabilitiesThat(mMockVpn, (caps) -> caps.getUids().size() == 2 && caps.getUids().contains(new UidRange(uid, uid)) - && caps.getUids().contains(UidRange.createForUser(restrictedUserId)) + && caps.getUids().contains(UidRange.createForUser(RESTRICTED_USER)) && caps.hasTransport(TRANSPORT_VPN) && caps.hasTransport(TRANSPORT_WIFI)); @@ -6375,13 +6553,13 @@ public class ConnectivityServiceTest { callback.expectCapabilitiesThat(mMockVpn, (caps) -> caps.getUids().size() == 2 && caps.getUids().contains(new UidRange(uid, uid)) - && caps.getUids().contains(UidRange.createForUser(restrictedUserId)) + && caps.getUids().contains(UidRange.createForUser(RESTRICTED_USER)) && caps.hasTransport(TRANSPORT_VPN) && !caps.hasTransport(TRANSPORT_WIFI)); // Send a USER_REMOVED broadcast and expect to lose the UID range for the restricted user. final Intent removedIntent = new Intent(ACTION_USER_REMOVED); - removedIntent.putExtra(Intent.EXTRA_USER_HANDLE, restrictedUserId); + removedIntent.putExtra(Intent.EXTRA_USER_HANDLE, RESTRICTED_USER); handler.post(() -> mServiceContext.sendBroadcast(removedIntent)); // Expect that the VPN gains the UID range for the restricted user, and that the capability @@ -6391,53 +6569,72 @@ public class ConnectivityServiceTest { && caps.getUids().contains(new UidRange(uid, uid)) && caps.hasTransport(TRANSPORT_VPN) && !caps.hasTransport(TRANSPORT_WIFI)); + } - // Test lockdown with restricted profiles. + @Test + public void testLockdownVpnWithRestrictedProfiles() throws Exception { + // For ConnectivityService#setAlwaysOnVpnPackage. mServiceContext.setPermission( Manifest.permission.CONTROL_ALWAYS_ON_VPN, PERMISSION_GRANTED); + // For call Vpn#setAlwaysOnPackage. mServiceContext.setPermission( Manifest.permission.CONTROL_VPN, PERMISSION_GRANTED); + // Necessary to see the UID ranges in NetworkCapabilities. mServiceContext.setPermission( Manifest.permission.NETWORK_SETTINGS, PERMISSION_GRANTED); + final NetworkRequest request = new NetworkRequest.Builder() + .removeCapability(NET_CAPABILITY_NOT_VPN) + .build(); + final TestNetworkCallback callback = new TestNetworkCallback(); + mCm.registerNetworkCallback(request, callback); + + final int uid = Process.myUid(); + // Connect wifi and check that UIDs in the main and restricted profiles have network access. - mMockVpn.disconnect(); mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); mWiFiNetworkAgent.connect(true /* validated */); - final int restrictedUid = UserHandle.getUid(restrictedUserId, 42 /* appId */); + final int restrictedUid = UserHandle.getUid(RESTRICTED_USER, 42 /* appId */); assertNotNull(mCm.getActiveNetworkForUid(uid)); assertNotNull(mCm.getActiveNetworkForUid(restrictedUid)); // Enable always-on VPN lockdown. The main user loses network access because no VPN is up. final ArrayList<String> allowList = new ArrayList<>(); - mService.setAlwaysOnVpnPackage(userId, ALWAYS_ON_PACKAGE, true /* lockdown */, allowList); + mService.setAlwaysOnVpnPackage(PRIMARY_USER, ALWAYS_ON_PACKAGE, true /* lockdown */, + allowList); waitForIdle(); assertNull(mCm.getActiveNetworkForUid(uid)); + // This is arguably overspecified: a UID that is not running doesn't have an active network. + // But it's useful to check that non-default users do not lose network access, and to prove + // that the loss of connectivity below is indeed due to the restricted profile coming up. assertNotNull(mCm.getActiveNetworkForUid(restrictedUid)); // Start the restricted profile, and check that the UID within it loses network access. - when(mUserManager.getAliveUsers()).thenReturn( - Arrays.asList(new UserInfo[] { - new UserInfo(userId, "", 0), - info - })); + when(mPackageManager.getPackageUidAsUser(ALWAYS_ON_PACKAGE, RESTRICTED_USER)) + .thenReturn(UserHandle.getUid(RESTRICTED_USER, VPN_UID)); + when(mUserManager.getAliveUsers()).thenReturn(Arrays.asList(PRIMARY_USER_INFO, + RESTRICTED_USER_INFO)); // TODO: check that VPN app within restricted profile still has access, etc. + final Intent addedIntent = new Intent(ACTION_USER_ADDED); + addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, RESTRICTED_USER); + final Handler handler = new Handler(mCsHandlerThread.getLooper()); handler.post(() -> mServiceContext.sendBroadcast(addedIntent)); waitForIdle(); assertNull(mCm.getActiveNetworkForUid(uid)); assertNull(mCm.getActiveNetworkForUid(restrictedUid)); // Stop the restricted profile, and check that the UID within it has network access again. - when(mUserManager.getAliveUsers()).thenReturn( - Arrays.asList(new UserInfo[] { - new UserInfo(userId, "", 0), - })); + when(mUserManager.getAliveUsers()).thenReturn(Arrays.asList(PRIMARY_USER_INFO)); + + // Send a USER_REMOVED broadcast and expect to lose the UID range for the restricted user. + final Intent removedIntent = new Intent(ACTION_USER_REMOVED); + removedIntent.putExtra(Intent.EXTRA_USER_HANDLE, RESTRICTED_USER); handler.post(() -> mServiceContext.sendBroadcast(removedIntent)); waitForIdle(); assertNull(mCm.getActiveNetworkForUid(uid)); assertNotNull(mCm.getActiveNetworkForUid(restrictedUid)); - mService.setAlwaysOnVpnPackage(userId, null, false /* lockdown */, allowList); + mService.setAlwaysOnVpnPackage(PRIMARY_USER, null, false /* lockdown */, allowList); waitForIdle(); } @@ -6778,6 +6975,7 @@ public class ConnectivityServiceTest { final int userId = UserHandle.getUserId(uid); final ArrayList<String> allowList = new ArrayList<>(); mService.setAlwaysOnVpnPackage(userId, ALWAYS_ON_PACKAGE, true /* lockdown */, allowList); + waitForIdle(); UidRangeParcel firstHalf = new UidRangeParcel(1, VPN_UID - 1); UidRangeParcel secondHalf = new UidRangeParcel(VPN_UID + 1, 99999); @@ -6799,10 +6997,10 @@ public class ConnectivityServiceTest { // Disable lockdown, expect to see the network unblocked. mService.setAlwaysOnVpnPackage(userId, null, false /* lockdown */, allowList); - expectNetworkRejectNonSecureVpn(inOrder, false, firstHalf, secondHalf); callback.expectBlockedStatusCallback(false, mWiFiNetworkAgent); defaultCallback.expectBlockedStatusCallback(false, mWiFiNetworkAgent); vpnUidCallback.assertNoCallback(); + expectNetworkRejectNonSecureVpn(inOrder, false, firstHalf, secondHalf); assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID)); assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork()); assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED); @@ -6845,9 +7043,11 @@ public class ConnectivityServiceTest { // Disable lockdown, remove our UID from the allowlist, and re-enable lockdown. // Everything should now be blocked. mService.setAlwaysOnVpnPackage(userId, null, false /* lockdown */, allowList); + waitForIdle(); expectNetworkRejectNonSecureVpn(inOrder, false, piece1, piece2, piece3); allowList.clear(); mService.setAlwaysOnVpnPackage(userId, ALWAYS_ON_PACKAGE, true /* lockdown */, allowList); + waitForIdle(); expectNetworkRejectNonSecureVpn(inOrder, true, firstHalf, secondHalf); defaultCallback.expectBlockedStatusCallback(true, mWiFiNetworkAgent); assertBlockedCallbackInAnyOrder(callback, true, mWiFiNetworkAgent, mCellNetworkAgent); @@ -6925,6 +7125,200 @@ public class ConnectivityServiceTest { mCm.unregisterNetworkCallback(vpnUidCallback); } + private void setupLegacyLockdownVpn() { + final String profileName = "testVpnProfile"; + final byte[] profileTag = profileName.getBytes(StandardCharsets.UTF_8); + when(mKeyStore.contains(Credentials.LOCKDOWN_VPN)).thenReturn(true); + when(mKeyStore.get(Credentials.LOCKDOWN_VPN)).thenReturn(profileTag); + + final VpnProfile profile = new VpnProfile(profileName); + profile.name = "My VPN"; + profile.server = "192.0.2.1"; + profile.dnsServers = "8.8.8.8"; + profile.type = VpnProfile.TYPE_IPSEC_XAUTH_PSK; + final byte[] encodedProfile = profile.encode(); + when(mKeyStore.get(Credentials.VPN + profileName)).thenReturn(encodedProfile); + } + + @Test + public void testLegacyLockdownVpn() throws Exception { + mServiceContext.setPermission( + Manifest.permission.CONTROL_VPN, PERMISSION_GRANTED); + + final NetworkRequest request = new NetworkRequest.Builder().clearCapabilities().build(); + final TestNetworkCallback callback = new TestNetworkCallback(); + mCm.registerNetworkCallback(request, callback); + + final TestNetworkCallback defaultCallback = new TestNetworkCallback(); + mCm.registerDefaultNetworkCallback(defaultCallback); + + // Pretend lockdown VPN was configured. + setupLegacyLockdownVpn(); + + // LockdownVpnTracker disables the Vpn teardown code and enables lockdown. + // Check the VPN's state before it does so. + assertTrue(mMockVpn.getEnableTeardown()); + assertFalse(mMockVpn.getLockdown()); + + // Send a USER_UNLOCKED broadcast so CS starts LockdownVpnTracker. + final int userId = UserHandle.getUserId(Process.myUid()); + final Intent addedIntent = new Intent(ACTION_USER_UNLOCKED); + addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId); + final Handler handler = new Handler(mCsHandlerThread.getLooper()); + handler.post(() -> mServiceContext.sendBroadcast(addedIntent)); + waitForIdle(); + + // Lockdown VPN disables teardown and enables lockdown. + assertFalse(mMockVpn.getEnableTeardown()); + assertTrue(mMockVpn.getLockdown()); + + // Bring up a network. + // Expect nothing to happen because the network does not have an IPv4 default route: legacy + // VPN only supports IPv4. + final LinkProperties cellLp = new LinkProperties(); + cellLp.setInterfaceName("rmnet0"); + cellLp.addLinkAddress(new LinkAddress("2001:db8::1/64")); + cellLp.addRoute(new RouteInfo(new IpPrefix("::/0"), null, "rmnet0")); + mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp); + mCellNetworkAgent.connect(false /* validated */); + callback.expectAvailableCallbacksUnvalidatedAndBlocked(mCellNetworkAgent); + defaultCallback.expectAvailableCallbacksUnvalidatedAndBlocked(mCellNetworkAgent); + waitForIdle(); + assertNull(mMockVpn.getAgent()); + + // Add an IPv4 address. Ideally the VPN should start, but it doesn't because nothing calls + // LockdownVpnTracker#handleStateChangedLocked. This is a bug. + // TODO: consider fixing this. + cellLp.addLinkAddress(new LinkAddress("192.0.2.2/25")); + cellLp.addRoute(new RouteInfo(new IpPrefix("0.0.0.0/0"), null, "rmnet0")); + mCellNetworkAgent.sendLinkProperties(cellLp); + callback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent); + defaultCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent); + waitForIdle(); + assertNull(mMockVpn.getAgent()); + + // Disconnect, then try again with a network that supports IPv4 at connection time. + // Expect lockdown VPN to come up. + ExpectedBroadcast b1 = expectConnectivityAction(TYPE_MOBILE, DetailedState.DISCONNECTED); + mCellNetworkAgent.disconnect(); + callback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent); + defaultCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent); + b1.expectBroadcast(); + + // When lockdown VPN is active, the NetworkInfo state in CONNECTIVITY_ACTION is overwritten + // with the state of the VPN network. So expect a CONNECTING broadcast. + b1 = expectConnectivityAction(TYPE_MOBILE, DetailedState.CONNECTING); + mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, cellLp); + mCellNetworkAgent.connect(false /* validated */); + callback.expectAvailableCallbacksUnvalidatedAndBlocked(mCellNetworkAgent); + defaultCallback.expectAvailableCallbacksUnvalidatedAndBlocked(mCellNetworkAgent); + b1.expectBroadcast(); + assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED); + assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED); + assertNetworkInfo(TYPE_WIFI, DetailedState.BLOCKED); + assertNetworkInfo(TYPE_VPN, DetailedState.BLOCKED); + + // TODO: it would be nice if we could simply rely on the production code here, and have + // LockdownVpnTracker start the VPN, have the VPN code register its NetworkAgent with + // ConnectivityService, etc. That would require duplicating a fair bit of code from the + // Vpn tests around how to mock out LegacyVpnRunner. But even if we did that, this does not + // work for at least two reasons: + // 1. In this test, calling registerNetworkAgent does not actually result in an agent being + // registered. This is because nothing calls onNetworkMonitorCreated, which is what + // actually ends up causing handleRegisterNetworkAgent to be called. Code in this test + // that wants to register an agent must use TestNetworkAgentWrapper. + // 2. Even if we exposed Vpn#agentConnect to the test, and made MockVpn#agentConnect call + // the TestNetworkAgentWrapper code, this would deadlock because the + // TestNetworkAgentWrapper code cannot be called on the handler thread since it calls + // waitForIdle(). + mMockVpn.expectStartLegacyVpnRunner(); + b1 = expectConnectivityAction(TYPE_VPN, DetailedState.CONNECTED); + ExpectedBroadcast b2 = expectConnectivityAction(TYPE_MOBILE, DetailedState.CONNECTED); + mMockVpn.establishForMyUid(); + callback.expectAvailableThenValidatedCallbacks(mMockVpn); + defaultCallback.expectAvailableThenValidatedCallbacks(mMockVpn); + b1.expectBroadcast(); + b2.expectBroadcast(); + assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED); + assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED); + assertNetworkInfo(TYPE_WIFI, DetailedState.DISCONNECTED); + assertNetworkInfo(TYPE_VPN, DetailedState.CONNECTED); + + // Switch default network from cell to wifi. Expect VPN to disconnect and reconnect. + final LinkProperties wifiLp = new LinkProperties(); + wifiLp.setInterfaceName("wlan0"); + wifiLp.addLinkAddress(new LinkAddress("192.0.2.163/25")); + wifiLp.addRoute(new RouteInfo(new IpPrefix("0.0.0.0/0"), null, "wlan0")); + mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, wifiLp); + + b1 = expectConnectivityAction(TYPE_MOBILE, DetailedState.DISCONNECTED); + // Wifi is CONNECTING because the VPN isn't up yet. + b2 = expectConnectivityAction(TYPE_WIFI, DetailedState.CONNECTING); + ExpectedBroadcast b3 = expectConnectivityAction(TYPE_VPN, DetailedState.DISCONNECTED); + mWiFiNetworkAgent.connect(false /* validated */); + b1.expectBroadcast(); + b2.expectBroadcast(); + b3.expectBroadcast(); + mMockVpn.expectStopVpnRunnerPrivileged(); + mMockVpn.expectStartLegacyVpnRunner(); + + // TODO: why is wifi not blocked? Is it because when this callback is sent, the VPN is still + // connected, so the network is not considered blocked by the lockdown UID ranges? But the + // fact that a VPN is connected should only result in the VPN itself being unblocked, not + // any other network. Bug in isUidBlockedByVpn? + callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); + callback.expectCapabilitiesThat(mMockVpn, nc -> nc.hasTransport(TRANSPORT_WIFI)); + callback.expectCallback(CallbackEntry.LOST, mMockVpn); + defaultCallback.expectCapabilitiesThat(mMockVpn, nc -> nc.hasTransport(TRANSPORT_WIFI)); + defaultCallback.expectCallback(CallbackEntry.LOST, mMockVpn); + defaultCallback.expectAvailableCallbacksUnvalidatedAndBlocked(mWiFiNetworkAgent); + + // While the VPN is reconnecting on the new network, everything is blocked. + assertActiveNetworkInfo(TYPE_WIFI, DetailedState.BLOCKED); + assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED); + assertNetworkInfo(TYPE_WIFI, DetailedState.BLOCKED); + assertNetworkInfo(TYPE_VPN, DetailedState.BLOCKED); + + // The VPN comes up again on wifi. + b1 = expectConnectivityAction(TYPE_VPN, DetailedState.CONNECTED); + b2 = expectConnectivityAction(TYPE_WIFI, DetailedState.CONNECTED); + mMockVpn.establishForMyUid(); + callback.expectAvailableThenValidatedCallbacks(mMockVpn); + defaultCallback.expectAvailableThenValidatedCallbacks(mMockVpn); + b1.expectBroadcast(); + b2.expectBroadcast(); + + assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED); + assertNetworkInfo(TYPE_MOBILE, DetailedState.DISCONNECTED); + assertNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED); + assertNetworkInfo(TYPE_VPN, DetailedState.CONNECTED); + + // Disconnect cell. Nothing much happens since it's not the default network. + // Whenever LockdownVpnTracker is connected, it will send a connected broadcast any time any + // NetworkInfo is updated. This is probably a bug. + // TODO: consider fixing this. + b1 = expectConnectivityAction(TYPE_WIFI, DetailedState.CONNECTED); + mCellNetworkAgent.disconnect(); + b1.expectBroadcast(); + callback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent); + defaultCallback.assertNoCallback(); + + assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED); + assertNetworkInfo(TYPE_MOBILE, DetailedState.DISCONNECTED); + assertNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED); + assertNetworkInfo(TYPE_VPN, DetailedState.CONNECTED); + + b1 = expectConnectivityAction(TYPE_WIFI, DetailedState.DISCONNECTED); + mWiFiNetworkAgent.disconnect(); + callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent); + b1.expectBroadcast(); + callback.expectCapabilitiesThat(mMockVpn, nc -> !nc.hasTransport(TRANSPORT_WIFI)); + b2 = expectConnectivityAction(TYPE_VPN, DetailedState.DISCONNECTED); + mMockVpn.expectStopVpnRunnerPrivileged(); + callback.expectCallback(CallbackEntry.LOST, mMockVpn); + b2.expectBroadcast(); + } + @Test public final void testLoseTrusted() throws Exception { final NetworkRequest trustedRequest = new NetworkRequest.Builder() @@ -7599,7 +7993,7 @@ public class ConnectivityServiceTest { lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null)); lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), RTN_UNREACHABLE)); // The uid range needs to cover the test app so the network is visible to it. - final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(VPN_USER)); + final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(PRIMARY_USER)); mMockVpn.establish(lp, VPN_UID, vpnRange); assertVpnUidRangesUpdated(true, vpnRange, VPN_UID); @@ -7627,7 +8021,7 @@ public class ConnectivityServiceTest { lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null)); lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null)); // The uid range needs to cover the test app so the network is visible to it. - final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(VPN_USER)); + final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(PRIMARY_USER)); mMockVpn.establish(lp, Process.SYSTEM_UID, vpnRange); assertVpnUidRangesUpdated(true, vpnRange, Process.SYSTEM_UID); @@ -7643,7 +8037,7 @@ public class ConnectivityServiceTest { lp.addRoute(new RouteInfo(new IpPrefix("192.0.2.0/24"), null, "tun0")); lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), RTN_UNREACHABLE)); // The uid range needs to cover the test app so the network is visible to it. - final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(VPN_USER)); + final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(PRIMARY_USER)); mMockVpn.establish(lp, Process.SYSTEM_UID, vpnRange); assertVpnUidRangesUpdated(true, vpnRange, Process.SYSTEM_UID); @@ -7658,7 +8052,7 @@ public class ConnectivityServiceTest { lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null)); lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null)); // The uid range needs to cover the test app so the network is visible to it. - final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(VPN_USER)); + final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(PRIMARY_USER)); mMockVpn.establish(lp, VPN_UID, vpnRange); assertVpnUidRangesUpdated(true, vpnRange, VPN_UID); @@ -7710,7 +8104,7 @@ public class ConnectivityServiceTest { lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), RTN_UNREACHABLE)); lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null)); // The uid range needs to cover the test app so the network is visible to it. - final UidRange vpnRange = UidRange.createForUser(VPN_USER); + final UidRange vpnRange = UidRange.createForUser(PRIMARY_USER); final Set<UidRange> vpnRanges = Collections.singleton(vpnRange); mMockVpn.establish(lp, VPN_UID, vpnRanges); assertVpnUidRangesUpdated(true, vpnRanges, VPN_UID); @@ -7908,7 +8302,7 @@ public class ConnectivityServiceTest { private void setupConnectionOwnerUid(int vpnOwnerUid, @VpnManager.VpnType int vpnType) throws Exception { - final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(VPN_USER)); + final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(PRIMARY_USER)); mMockVpn.establish(new LinkProperties(), vpnOwnerUid, vpnRange); assertVpnUidRangesUpdated(true, vpnRange, vpnOwnerUid); mMockVpn.setVpnType(vpnType); @@ -8112,11 +8506,18 @@ public class ConnectivityServiceTest { assertTrue(mService.mConnectivityDiagnosticsCallbacks.containsKey(mIBinder)); } + public NetworkAgentInfo fakeMobileNai(NetworkCapabilities nc) { + final NetworkInfo info = new NetworkInfo(TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_LTE, + ConnectivityManager.getNetworkTypeName(TYPE_MOBILE), + TelephonyManager.getNetworkTypeName(TelephonyManager.NETWORK_TYPE_LTE)); + return new NetworkAgentInfo(null, new Network(NET_ID), info, new LinkProperties(), + nc, 0, mServiceContext, null, new NetworkAgentConfig(), mService, null, null, null, + 0, INVALID_UID); + } + @Test public void testCheckConnectivityDiagnosticsPermissionsNetworkStack() throws Exception { - final NetworkAgentInfo naiWithoutUid = - new NetworkAgentInfo(null, null, null, null, new NetworkCapabilities(), 0, - mServiceContext, null, null, mService, null, null, null, 0, INVALID_UID); + final NetworkAgentInfo naiWithoutUid = fakeMobileNai(new NetworkCapabilities()); mServiceContext.setPermission( android.Manifest.permission.NETWORK_STACK, PERMISSION_GRANTED); @@ -8129,9 +8530,7 @@ public class ConnectivityServiceTest { @Test public void testCheckConnectivityDiagnosticsPermissionsWrongUidPackageName() throws Exception { - final NetworkAgentInfo naiWithoutUid = - new NetworkAgentInfo(null, null, null, null, new NetworkCapabilities(), 0, - mServiceContext, null, null, mService, null, null, null, 0, INVALID_UID); + final NetworkAgentInfo naiWithoutUid = fakeMobileNai(new NetworkCapabilities()); mServiceContext.setPermission(android.Manifest.permission.NETWORK_STACK, PERMISSION_DENIED); @@ -8144,9 +8543,7 @@ public class ConnectivityServiceTest { @Test public void testCheckConnectivityDiagnosticsPermissionsNoLocationPermission() throws Exception { - final NetworkAgentInfo naiWithoutUid = - new NetworkAgentInfo(null, null, null, null, new NetworkCapabilities(), 0, - mServiceContext, null, null, mService, null, null, null, 0, INVALID_UID); + final NetworkAgentInfo naiWithoutUid = fakeMobileNai(new NetworkCapabilities()); mServiceContext.setPermission(android.Manifest.permission.NETWORK_STACK, PERMISSION_DENIED); @@ -8159,10 +8556,7 @@ public class ConnectivityServiceTest { @Test public void testCheckConnectivityDiagnosticsPermissionsActiveVpn() throws Exception { - final Network network = new Network(NET_ID); - final NetworkAgentInfo naiWithoutUid = - new NetworkAgentInfo(null, network, null, null, new NetworkCapabilities(), 0, - mServiceContext, null, null, mService, null, null, null, 0, INVALID_UID); + final NetworkAgentInfo naiWithoutUid = fakeMobileNai(new NetworkCapabilities()); mMockVpn.establishForMyUid(); assertUidRangesUpdatedForMyUid(true); @@ -8172,7 +8566,7 @@ public class ConnectivityServiceTest { setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION); - assertTrue(mService.setUnderlyingNetworksForVpn(new Network[] {network})); + assertTrue(mService.setUnderlyingNetworksForVpn(new Network[] {naiWithoutUid.network})); waitForIdle(); assertTrue( "Active VPN permission not applied", @@ -8193,9 +8587,7 @@ public class ConnectivityServiceTest { public void testCheckConnectivityDiagnosticsPermissionsNetworkAdministrator() throws Exception { final NetworkCapabilities nc = new NetworkCapabilities(); nc.setAdministratorUids(new int[] {Process.myUid()}); - final NetworkAgentInfo naiWithUid = - new NetworkAgentInfo(null, null, null, null, nc, 0, mServiceContext, null, null, - mService, null, null, null, 0, INVALID_UID); + final NetworkAgentInfo naiWithUid = fakeMobileNai(nc); setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION); @@ -8212,9 +8604,7 @@ public class ConnectivityServiceTest { final NetworkCapabilities nc = new NetworkCapabilities(); nc.setOwnerUid(Process.myUid()); nc.setAdministratorUids(new int[] {Process.myUid()}); - final NetworkAgentInfo naiWithUid = - new NetworkAgentInfo(null, null, null, null, nc, 0, mServiceContext, null, null, - mService, null, null, null, 0, INVALID_UID); + final NetworkAgentInfo naiWithUid = fakeMobileNai(nc); setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION); @@ -8481,7 +8871,7 @@ public class ConnectivityServiceTest { lp.setInterfaceName("tun0"); lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null)); lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null)); - final UidRange vpnRange = UidRange.createForUser(VPN_USER); + final UidRange vpnRange = UidRange.createForUser(PRIMARY_USER); Set<UidRange> vpnRanges = Collections.singleton(vpnRange); mMockVpn.establish(lp, VPN_UID, vpnRanges); assertVpnUidRangesUpdated(true, vpnRanges, VPN_UID); diff --git a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java index 96c56e32f156..4d151afecd63 100644 --- a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java +++ b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java @@ -34,7 +34,9 @@ import android.content.res.Resources; import android.net.ConnectivityManager; import android.net.IDnsResolver; import android.net.INetd; +import android.net.LinkProperties; import android.net.Network; +import android.net.NetworkAgentConfig; import android.net.NetworkCapabilities; import android.net.NetworkInfo; import android.net.NetworkProvider; @@ -353,9 +355,10 @@ public class LingerMonitorTest { NetworkCapabilities caps = new NetworkCapabilities(); caps.addCapability(0); caps.addTransportType(transport); - NetworkAgentInfo nai = new NetworkAgentInfo(null, new Network(netId), info, null, - caps, 50, mCtx, null, null /* config */, mConnService, mNetd, mDnsResolver, mNMS, - NetworkProvider.ID_NONE, Binder.getCallingUid()); + NetworkAgentInfo nai = new NetworkAgentInfo(null, new Network(netId), info, + new LinkProperties(), caps, 50, mCtx, null, new NetworkAgentConfig() /* config */, + mConnService, mNetd, mDnsResolver, mNMS, NetworkProvider.ID_NONE, + Binder.getCallingUid()); nai.everValidated = true; return nai; } diff --git a/tests/utils/testutils/java/com/android/internal/util/test/BroadcastInterceptingContext.java b/tests/utils/testutils/java/com/android/internal/util/test/BroadcastInterceptingContext.java index 25bd7c06be49..1102624da031 100644 --- a/tests/utils/testutils/java/com/android/internal/util/test/BroadcastInterceptingContext.java +++ b/tests/utils/testutils/java/com/android/internal/util/test/BroadcastInterceptingContext.java @@ -29,7 +29,6 @@ import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; import java.util.concurrent.FutureTask; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; @@ -197,6 +196,11 @@ public class BroadcastInterceptingContext extends ContextWrapper { } @Override + public void sendStickyBroadcast(Intent intent, Bundle options) { + sendBroadcast(intent); + } + + @Override public void sendStickyBroadcastAsUser(Intent intent, UserHandle user) { sendBroadcast(intent); } diff --git a/tests/vcn/Android.bp b/tests/vcn/Android.bp index 3c08d347b19a..c04ddd78e69b 100644 --- a/tests/vcn/Android.bp +++ b/tests/vcn/Android.bp @@ -16,6 +16,7 @@ android_test { "frameworks-base-testutils", "framework-protos", "mockito-target-minus-junit4", + "net-tests-utils", "platform-test-annotations", "services.core", ], diff --git a/tests/vcn/java/android/net/vcn/VcnManagerTest.java b/tests/vcn/java/android/net/vcn/VcnManagerTest.java new file mode 100644 index 000000000000..9c6b7194af35 --- /dev/null +++ b/tests/vcn/java/android/net/vcn/VcnManagerTest.java @@ -0,0 +1,106 @@ +/* + * 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.vcn; + +import static androidx.test.InstrumentationRegistry.getContext; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; + +import android.content.Context; +import android.net.vcn.VcnManager.VcnUnderlyingNetworkPolicyListener; + +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; + +import java.util.concurrent.Executor; + +public class VcnManagerTest { + private static final Executor INLINE_EXECUTOR = Runnable::run; + + private IVcnManagementService mMockVcnManagementService; + private VcnUnderlyingNetworkPolicyListener mMockPolicyListener; + + private Context mContext; + private VcnManager mVcnManager; + + @Before + public void setUp() { + mMockVcnManagementService = mock(IVcnManagementService.class); + mMockPolicyListener = mock(VcnUnderlyingNetworkPolicyListener.class); + + mContext = getContext(); + mVcnManager = new VcnManager(mContext, mMockVcnManagementService); + } + + @Test + public void testAddVcnUnderlyingNetworkPolicyListener() throws Exception { + mVcnManager.addVcnUnderlyingNetworkPolicyListener(INLINE_EXECUTOR, mMockPolicyListener); + + ArgumentCaptor<IVcnUnderlyingNetworkPolicyListener> captor = + ArgumentCaptor.forClass(IVcnUnderlyingNetworkPolicyListener.class); + verify(mMockVcnManagementService).addVcnUnderlyingNetworkPolicyListener(captor.capture()); + + assertTrue(VcnManager.REGISTERED_POLICY_LISTENERS.containsKey(mMockPolicyListener)); + + IVcnUnderlyingNetworkPolicyListener listenerWrapper = captor.getValue(); + listenerWrapper.onPolicyChanged(); + verify(mMockPolicyListener).onPolicyChanged(); + } + + @Test + public void testRemoveVcnUnderlyingNetworkPolicyListener() throws Exception { + mVcnManager.addVcnUnderlyingNetworkPolicyListener(INLINE_EXECUTOR, mMockPolicyListener); + + mVcnManager.removeVcnUnderlyingNetworkPolicyListener(mMockPolicyListener); + + assertFalse(VcnManager.REGISTERED_POLICY_LISTENERS.containsKey(mMockPolicyListener)); + verify(mMockVcnManagementService) + .addVcnUnderlyingNetworkPolicyListener( + any(IVcnUnderlyingNetworkPolicyListener.class)); + } + + @Test + public void testRemoveVcnUnderlyingNetworkPolicyListenerUnknownListener() throws Exception { + mVcnManager.removeVcnUnderlyingNetworkPolicyListener(mMockPolicyListener); + + assertFalse(VcnManager.REGISTERED_POLICY_LISTENERS.containsKey(mMockPolicyListener)); + verify(mMockVcnManagementService, never()) + .addVcnUnderlyingNetworkPolicyListener( + any(IVcnUnderlyingNetworkPolicyListener.class)); + } + + @Test(expected = NullPointerException.class) + public void testAddVcnUnderlyingNetworkPolicyListenerNullExecutor() throws Exception { + mVcnManager.addVcnUnderlyingNetworkPolicyListener(null, mMockPolicyListener); + } + + @Test(expected = NullPointerException.class) + public void testAddVcnUnderlyingNetworkPolicyListenerNullListener() throws Exception { + mVcnManager.addVcnUnderlyingNetworkPolicyListener(INLINE_EXECUTOR, null); + } + + @Test(expected = NullPointerException.class) + public void testRemoveVcnUnderlyingNetworkPolicyListenerNullListener() { + mVcnManager.removeVcnUnderlyingNetworkPolicyListener(null); + } +} diff --git a/tests/vcn/java/android/net/vcn/VcnUnderlyingNetworkPolicyTest.java b/tests/vcn/java/android/net/vcn/VcnUnderlyingNetworkPolicyTest.java new file mode 100644 index 000000000000..3ba0a1f53a9f --- /dev/null +++ b/tests/vcn/java/android/net/vcn/VcnUnderlyingNetworkPolicyTest.java @@ -0,0 +1,51 @@ +/* + * 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.vcn; + +import static com.android.testutils.ParcelUtils.assertParcelSane; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; + +import android.net.NetworkCapabilities; + +import org.junit.Test; + +public class VcnUnderlyingNetworkPolicyTest { + private static final VcnUnderlyingNetworkPolicy DEFAULT_NETWORK_POLICY = + new VcnUnderlyingNetworkPolicy( + false /* isTearDownRequested */, new NetworkCapabilities()); + private static final VcnUnderlyingNetworkPolicy SAMPLE_NETWORK_POLICY = + new VcnUnderlyingNetworkPolicy( + true /* isTearDownRequested */, + new NetworkCapabilities.Builder() + .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) + .build()); + + @Test + public void testEquals() { + assertEquals(DEFAULT_NETWORK_POLICY, DEFAULT_NETWORK_POLICY); + assertEquals(SAMPLE_NETWORK_POLICY, SAMPLE_NETWORK_POLICY); + + assertNotEquals(DEFAULT_NETWORK_POLICY, SAMPLE_NETWORK_POLICY); + } + + @Test + public void testParcelUnparcel() { + assertParcelSane(SAMPLE_NETWORK_POLICY, 2); + } +} |