Merge "Create the ResumeOnRebootService."
diff --git a/Android.bp b/Android.bp
index 2316823..402cf1c 100644
--- a/Android.bp
+++ b/Android.bp
@@ -483,6 +483,7 @@
"android.hardware.vibrator-V1.2-java",
"android.hardware.vibrator-V1.3-java",
"android.security.apc-java",
+ "android.security.authorization-java",
"android.system.keystore2-java",
"android.system.suspend.control.internal-java",
"devicepolicyprotosnano",
diff --git a/StubLibraries.bp b/StubLibraries.bp
index ed8781e..64ee09c 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -120,6 +120,20 @@
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 @@
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 @@
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 @@
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 a060ad9..7e7feaf 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 97600135..bde2bec 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 9a157b8..fdfef4c 100644
--- a/api/Android.bp
+++ b/api/Android.bp
@@ -50,10 +50,7 @@
dest: "current.txt",
},
{
- targets: [
- "sdk",
- "win_sdk",
- ],
+ targets: ["sdk", "win_sdk"],
dir: "apistubs/android/public/api",
dest: "android.txt",
},
@@ -106,6 +103,11 @@
dir: "api",
dest: "removed.txt",
},
+ {
+ targets: ["sdk", "win_sdk"],
+ dir: "apistubs/android/public/api",
+ dest: "removed.txt",
+ },
],
}
@@ -131,10 +133,7 @@
dest: "system-current.txt",
},
{
- targets: [
- "sdk",
- "win_sdk",
- ],
+ targets: ["sdk", "win_sdk"],
dir: "apistubs/android/system/api",
dest: "android.txt",
},
@@ -163,6 +162,11 @@
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 @@
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 @@
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 bdb8380..846a34e 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 @@
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 @@
}
instrument.componentNameArg = nextArgRequired();
-
instrument.run();
}
}
diff --git a/cmds/app_process/Android.bp b/cmds/app_process/Android.bp
index 07221f9..14ebb71 100644
--- a/cmds/app_process/Android.bp
+++ b/cmds/app_process/Android.bp
@@ -62,4 +62,13 @@
// 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 405d6f6..dc2868a 100644
--- a/cmds/sm/src/com/android/commands/sm/Sm.java
+++ b/cmds/sm/src/com/android/commands/sm/Sm.java
@@ -20,6 +20,7 @@
import android.os.PersistableBundle;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.SystemProperties;
import android.os.storage.DiskInfo;
import android.os.storage.IStorageManager;
import android.os.storage.StorageManager;
@@ -30,6 +31,8 @@
public final class Sm {
private static final String TAG = "Sm";
+ private static final String ANDROID_VOLD_APP_DATA_ISOLATION_ENABLED_PROPERTY =
+ "persist.sys.vold_app_data_isolation_enabled";
IStorageManager mSm;
@@ -256,6 +259,10 @@
}
public void runDisableAppDataIsolation() throws RemoteException {
+ if (!SystemProperties.getBoolean(
+ ANDROID_VOLD_APP_DATA_ISOLATION_ENABLED_PROPERTY, false)) {
+ throw new IllegalStateException("Storage app data isolation is not enabled.");
+ }
final String pkgName = nextArg();
final int pid = Integer.parseInt(nextArg());
final int userId = Integer.parseInt(nextArg());
diff --git a/config/OWNERS b/config/OWNERS
index d59c6f2..001038d 100644
--- a/config/OWNERS
+++ b/config/OWNERS
@@ -4,5 +4,11 @@
per-file hiddenapi-* = andreionea@google.com, mathewi@google.com, satayev@google.com
+# art-team@ manages the boot image profiles
+per-file boot-* = calin@google.com, mathieuc@google.com, ngeoffray@google.com
+per-file dirty-image-objects = calin@google.com, mathieuc@google.com, ngeoffray@google.com
+per-file generate-preloaded-classes.sh = calin@google.com, mathieuc@google.com, ngeoffray@google.com
+per-file preloaded-classes* = calin@google.com, mathieuc@google.com, ngeoffray@google.com
+
# Escalations:
per-file hiddenapi-* = bdc@google.com, narayan@google.com
diff --git a/core/api/current.txt b/core/api/current.txt
index a7a82f9..c71ec3d 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -10145,6 +10145,7 @@
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 @@
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 @@
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 @@
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";
@@ -35868,6 +35889,9 @@
method @NonNull public String getVersion();
method public boolean isConnected();
method public void shutdown();
+ field public static final String ACTION_SECURE_ELEMENT_STATE_CHANGED = "android.se.omapi.action.SECURE_ELEMENT_STATE_CHANGED";
+ field public static final String EXTRA_READER_NAME = "android.se.omapi.extra.READER_NAME";
+ field public static final String EXTRA_READER_STATE = "android.se.omapi.extra.READER_STATE";
}
public static interface SEService.OnConnectedListener {
@@ -39226,6 +39250,7 @@
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
@@ -39237,10 +39262,12 @@
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
@@ -39266,6 +39293,7 @@
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 {
@@ -39553,6 +39581,7 @@
field public static final String KEY_RTT_DOWNGRADE_SUPPORTED_BOOL = "rtt_downgrade_supported_bool";
field public static final String KEY_RTT_SUPPORTED_BOOL = "rtt_supported_bool";
field public static final String KEY_RTT_SUPPORTED_FOR_VT_BOOL = "rtt_supported_for_vt_bool";
+ field public static final String KEY_RTT_SUPPORTED_WHILE_ROAMING_BOOL = "rtt_supported_while_roaming";
field public static final String KEY_RTT_UPGRADE_SUPPORTED_BOOL = "rtt_upgrade_supported_bool";
field public static final String KEY_SHOW_4G_FOR_3G_DATA_ICON_BOOL = "show_4g_for_3g_data_icon_bool";
field public static final String KEY_SHOW_4G_FOR_LTE_DATA_ICON_BOOL = "show_4g_for_lte_data_icon_bool";
@@ -40703,17 +40732,27 @@
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
}
@@ -40798,6 +40837,7 @@
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);
@@ -41175,6 +41215,7 @@
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();
@@ -41253,7 +41294,7 @@
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);
@@ -41287,6 +41328,7 @@
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 9349770..bc4a3ca 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -10,6 +10,14 @@
package android.net {
+ public class ConnectivityManager {
+ 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 final class NetworkCapabilities implements android.os.Parcelable {
+ field public static final int TRANSPORT_TEST = 7; // 0x7
+ }
+
public final class TcpRepairWindow {
ctor public TcpRepairWindow(int, int, int, int, int, int);
field public final int maxWindow;
@@ -20,6 +28,22 @@
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 {
@@ -28,6 +52,10 @@
method public final void markVintfStability();
}
+ public static class Build.VERSION {
+ field public static final int FIRST_SDK_INT;
+ }
+
public interface Parcelable {
method public default int getStability();
}
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 8552f44..e72a9b4 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -127,6 +127,7 @@
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";
@@ -1413,8 +1414,14 @@
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
@@ -1596,6 +1603,25 @@
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 {
@@ -1685,7 +1711,6 @@
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";
@@ -5995,6 +6020,7 @@
method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void getLatestTetheringEntitlementResult(int, boolean, @NonNull java.util.concurrent.Executor, @NonNull android.net.ConnectivityManager.OnTetheringEntitlementResultListener);
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public boolean isTetheringSupported();
method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_FACTORY}) public int registerNetworkProvider(@NonNull android.net.NetworkProvider);
+ method public void registerQosCallback(@NonNull android.net.QosSocketInfo, @NonNull android.net.QosCallback, @NonNull java.util.concurrent.Executor);
method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void registerTetheringEventCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.ConnectivityManager.OnTetheringEventCallback);
method @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public void requestNetwork(@NonNull android.net.NetworkRequest, int, int, @NonNull android.os.Handler, @NonNull android.net.ConnectivityManager.NetworkCallback);
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_AIRPLANE_MODE, android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void setAirplaneMode(boolean);
@@ -6004,6 +6030,7 @@
method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void startTethering(int, boolean, android.net.ConnectivityManager.OnStartTetheringCallback, android.os.Handler);
method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void stopTethering(int);
method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_FACTORY}) public void unregisterNetworkProvider(@NonNull android.net.NetworkProvider);
+ method public void unregisterQosCallback(@NonNull android.net.QosCallback);
method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void unregisterTetheringEventCallback(@NonNull android.net.ConnectivityManager.OnTetheringEventCallback);
field public static final String EXTRA_CAPTIVE_PORTAL_PROBE_SPEC = "android.net.extra.CAPTIVE_PORTAL_PROBE_SPEC";
field public static final String EXTRA_CAPTIVE_PORTAL_USER_AGENT = "android.net.extra.CAPTIVE_PORTAL_USER_AGENT";
@@ -6197,6 +6224,8 @@
method public void onAddKeepalivePacketFilter(int, @NonNull android.net.KeepalivePacketData);
method public void onAutomaticReconnectDisabled();
method public void onNetworkUnwanted();
+ method public void onQosCallbackRegistered(int, @NonNull android.net.QosFilter);
+ method public void onQosCallbackUnregistered(int);
method public void onRemoveKeepalivePacketFilter(int);
method public void onSaveAcceptUnvalidated(boolean);
method public void onSignalStrengthThresholdsUpdated(@NonNull int[]);
@@ -6207,6 +6236,9 @@
method public final void sendLinkProperties(@NonNull android.net.LinkProperties);
method public final void sendNetworkCapabilities(@NonNull android.net.NetworkCapabilities);
method public final void sendNetworkScore(@IntRange(from=0, to=99) int);
+ method public final void sendQosCallbackError(int, int);
+ method public final void sendQosSessionAvailable(int, int, @NonNull android.telephony.data.EpsBearerQosSessionAttributes);
+ method public final void sendQosSessionLost(int, int);
method public final void sendSocketKeepaliveEvent(int, int);
method public final void setUnderlyingNetworks(@Nullable java.util.List<android.net.Network>);
method public void unregister();
@@ -6293,6 +6325,9 @@
method public abstract void onRequestScores(android.net.NetworkKey[]);
}
+ public class NetworkReleasedException extends java.lang.Exception {
+ }
+
public class NetworkRequest implements android.os.Parcelable {
method @Nullable public String getRequestorPackageName();
method public int getRequestorUid();
@@ -6365,6 +6400,47 @@
ctor public NetworkStats.Entry(@Nullable String, int, int, int, int, int, int, long, long, long, long, long);
}
+ public abstract class QosCallback {
+ ctor public QosCallback();
+ method public void onError(@NonNull android.net.QosCallbackException);
+ method public void onQosSessionAvailable(@NonNull android.net.QosSession, @NonNull android.net.QosSessionAttributes);
+ method public void onQosSessionLost(@NonNull android.net.QosSession);
+ }
+
+ public static class QosCallback.QosCallbackRegistrationException extends java.lang.RuntimeException {
+ }
+
+ public final class QosCallbackException extends java.lang.Exception {
+ }
+
+ public abstract class QosFilter {
+ method @NonNull public abstract android.net.Network getNetwork();
+ method public abstract boolean matchesLocalAddress(@NonNull java.net.InetAddress, int, int);
+ }
+
+ public final class QosSession implements android.os.Parcelable {
+ ctor public QosSession(int, int);
+ method public int describeContents();
+ method public int getSessionId();
+ method public int getSessionType();
+ method public long getUniqueId();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.QosSession> CREATOR;
+ field public static final int TYPE_EPS_BEARER = 1; // 0x1
+ }
+
+ public interface QosSessionAttributes {
+ }
+
+ public final class QosSocketInfo implements android.os.Parcelable {
+ ctor public QosSocketInfo(@NonNull android.net.Network, @NonNull java.net.Socket) throws java.io.IOException;
+ method public int describeContents();
+ method @NonNull public java.net.InetSocketAddress getLocalSocketAddress();
+ method @NonNull public android.net.Network getNetwork();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.QosSocketInfo> CREATOR;
+ }
+
public final class RouteInfo implements android.os.Parcelable {
ctor public RouteInfo(@Nullable android.net.IpPrefix, @Nullable java.net.InetAddress, @Nullable String, int);
ctor public RouteInfo(@Nullable android.net.IpPrefix, @Nullable java.net.InetAddress, @Nullable String, int, int);
@@ -6410,6 +6486,12 @@
field public static final int SUCCESS = 0; // 0x0
}
+ public class SocketLocalAddressChangedException extends java.lang.Exception {
+ }
+
+ public class SocketNotBoundException extends java.lang.Exception {
+ }
+
public final class StaticIpConfiguration implements android.os.Parcelable {
ctor public StaticIpConfiguration();
ctor public StaticIpConfiguration(@Nullable android.net.StaticIpConfiguration);
@@ -6506,157 +6588,157 @@
package android.net.metrics {
- public final class ApfProgramEvent implements android.net.metrics.IpConnectivityLog.Event {
+ @Deprecated 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);
+ @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);
}
- public final class ApfStats implements android.net.metrics.IpConnectivityLog.Event {
+ @Deprecated 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);
+ @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);
}
- public final class DhcpClientEvent implements android.net.metrics.IpConnectivityLog.Event {
+ @Deprecated 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);
+ @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);
}
- 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
+ @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
}
- 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);
+ @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);
}
- public static interface IpConnectivityLog.Event extends android.os.Parcelable {
+ @Deprecated 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
+ @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
}
- 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
+ @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
}
- 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
+ @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
}
- public final class RaEvent implements android.net.metrics.IpConnectivityLog.Event {
+ @Deprecated 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);
+ @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);
}
- 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
+ @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
}
- 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 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);
}
}
@@ -6927,7 +7009,10 @@
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
}
@@ -7047,24 +7132,10 @@
}
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();
@@ -10763,6 +10834,19 @@
field public static final int RESULT_SUCCESS = 0; // 0x0
}
+ public final class EpsBearerQosSessionAttributes implements android.os.Parcelable android.net.QosSessionAttributes {
+ method @NonNull public static android.telephony.data.EpsBearerQosSessionAttributes create(@NonNull android.os.Parcel);
+ method public int describeContents();
+ method public long getGuaranteedDownlinkBitRate();
+ method public long getGuaranteedUplinkBitRate();
+ method public long getMaxDownlinkBitRate();
+ method public long getMaxUplinkBitRate();
+ method public int getQci();
+ method @NonNull public java.util.List<java.net.InetSocketAddress> getRemoteAddresses();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.telephony.data.EpsBearerQosSessionAttributes> CREATOR;
+ }
+
public abstract class QualifiedNetworksService extends android.app.Service {
ctor public QualifiedNetworksService();
method @NonNull public abstract android.telephony.data.QualifiedNetworksService.NetworkAvailabilityProvider onCreateNetworkAvailabilityProvider(int);
@@ -11809,6 +11893,7 @@
ctor public SipMessage(@NonNull String, @NonNull String, @NonNull byte[]);
method public int describeContents();
method @NonNull public byte[] getContent();
+ method @NonNull public byte[] getEncodedMessage();
method @NonNull public String getHeaderSection();
method @NonNull public String getStartLine();
method public void writeToParcel(@NonNull android.os.Parcel, int);
@@ -12246,6 +12331,164 @@
}
+package android.uwb {
+
+ public final class AngleMeasurement implements android.os.Parcelable {
+ method public int describeContents();
+ method @FloatRange(from=0.0, to=1.0) public double getConfidenceLevel();
+ method @FloatRange(from=0.0, to=3.141592653589793) public double getErrorRadians();
+ method @FloatRange(from=-3.141592653589793, to=3.141592653589793) public double getRadians();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.uwb.AngleMeasurement> CREATOR;
+ }
+
+ public static final class AngleMeasurement.Builder {
+ ctor public AngleMeasurement.Builder();
+ method @NonNull public android.uwb.AngleMeasurement build();
+ method @NonNull public android.uwb.AngleMeasurement.Builder setConfidenceLevel(double);
+ method @NonNull public android.uwb.AngleMeasurement.Builder setErrorRadians(double);
+ method @NonNull public android.uwb.AngleMeasurement.Builder setRadians(double);
+ }
+
+ public final class AngleOfArrivalMeasurement implements android.os.Parcelable {
+ method public int describeContents();
+ method @Nullable public android.uwb.AngleMeasurement getAltitude();
+ method @NonNull public android.uwb.AngleMeasurement getAzimuth();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.uwb.AngleOfArrivalMeasurement> CREATOR;
+ }
+
+ public static final class AngleOfArrivalMeasurement.Builder {
+ ctor public AngleOfArrivalMeasurement.Builder();
+ method @NonNull public android.uwb.AngleOfArrivalMeasurement build();
+ method @NonNull public android.uwb.AngleOfArrivalMeasurement.Builder setAltitude(@NonNull android.uwb.AngleMeasurement);
+ method @NonNull public android.uwb.AngleOfArrivalMeasurement.Builder setAzimuth(@NonNull android.uwb.AngleMeasurement);
+ }
+
+ public final class DistanceMeasurement implements android.os.Parcelable {
+ method public int describeContents();
+ method @FloatRange(from=0.0, to=1.0) public double getConfidenceLevel();
+ method public double getErrorMeters();
+ method public double getMeters();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.uwb.DistanceMeasurement> CREATOR;
+ }
+
+ public static final class DistanceMeasurement.Builder {
+ ctor public DistanceMeasurement.Builder();
+ method @NonNull public android.uwb.DistanceMeasurement build();
+ method @NonNull public android.uwb.DistanceMeasurement.Builder setConfidenceLevel(double);
+ method @NonNull public android.uwb.DistanceMeasurement.Builder setErrorMeters(double);
+ method @NonNull public android.uwb.DistanceMeasurement.Builder setMeters(double);
+ }
+
+ public final class RangingMeasurement implements android.os.Parcelable {
+ method public int describeContents();
+ method @Nullable public android.uwb.AngleOfArrivalMeasurement getAngleOfArrivalMeasurement();
+ method @Nullable public android.uwb.DistanceMeasurement getDistanceMeasurement();
+ method public long getElapsedRealtimeNanos();
+ method @NonNull public android.uwb.UwbAddress getRemoteDeviceAddress();
+ method public int getStatus();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.uwb.RangingMeasurement> CREATOR;
+ field public static final int RANGING_STATUS_FAILURE_OUT_OF_RANGE = 1; // 0x1
+ field public static final int RANGING_STATUS_FAILURE_UNKNOWN_ERROR = -1; // 0xffffffff
+ field public static final int RANGING_STATUS_SUCCESS = 0; // 0x0
+ }
+
+ public static final class RangingMeasurement.Builder {
+ ctor public RangingMeasurement.Builder();
+ method @NonNull public android.uwb.RangingMeasurement build();
+ method @NonNull public android.uwb.RangingMeasurement.Builder setAngleOfArrivalMeasurement(@NonNull android.uwb.AngleOfArrivalMeasurement);
+ method @NonNull public android.uwb.RangingMeasurement.Builder setDistanceMeasurement(@NonNull android.uwb.DistanceMeasurement);
+ method @NonNull public android.uwb.RangingMeasurement.Builder setElapsedRealtimeNanos(long);
+ method @NonNull public android.uwb.RangingMeasurement.Builder setRemoteDeviceAddress(@NonNull android.uwb.UwbAddress);
+ method @NonNull public android.uwb.RangingMeasurement.Builder setStatus(int);
+ }
+
+ public final class RangingReport implements android.os.Parcelable {
+ method public int describeContents();
+ method @NonNull public java.util.List<android.uwb.RangingMeasurement> getMeasurements();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.uwb.RangingReport> CREATOR;
+ }
+
+ public static final class RangingReport.Builder {
+ ctor public RangingReport.Builder();
+ method @NonNull public android.uwb.RangingReport.Builder addMeasurement(@NonNull android.uwb.RangingMeasurement);
+ method @NonNull public android.uwb.RangingReport.Builder addMeasurements(@NonNull java.util.List<android.uwb.RangingMeasurement>);
+ method @NonNull public android.uwb.RangingReport build();
+ }
+
+ public final class RangingSession implements java.lang.AutoCloseable {
+ method public void close();
+ method public void reconfigure(@NonNull android.os.PersistableBundle);
+ method public void start(@NonNull android.os.PersistableBundle);
+ method public void stop();
+ }
+
+ public static interface RangingSession.Callback {
+ method public void onClosed(int, @NonNull android.os.PersistableBundle);
+ method public void onOpenFailed(int, @NonNull android.os.PersistableBundle);
+ method public void onOpened(@NonNull android.uwb.RangingSession);
+ method public void onReconfigureFailed(int, @NonNull android.os.PersistableBundle);
+ method public void onReconfigured(@NonNull android.os.PersistableBundle);
+ method public void onReportReceived(@NonNull android.uwb.RangingReport);
+ method public void onStartFailed(int, @NonNull android.os.PersistableBundle);
+ method public void onStarted(@NonNull android.os.PersistableBundle);
+ method public void onStopFailed(int, @NonNull android.os.PersistableBundle);
+ method public void onStopped();
+ field public static final int REASON_BAD_PARAMETERS = 3; // 0x3
+ field public static final int REASON_GENERIC_ERROR = 4; // 0x4
+ field public static final int REASON_LOCAL_REQUEST = 1; // 0x1
+ field public static final int REASON_MAX_SESSIONS_REACHED = 5; // 0x5
+ field public static final int REASON_PROTOCOL_SPECIFIC_ERROR = 7; // 0x7
+ field public static final int REASON_REMOTE_REQUEST = 2; // 0x2
+ field public static final int REASON_SYSTEM_POLICY = 6; // 0x6
+ field public static final int REASON_UNKNOWN = 0; // 0x0
+ }
+
+ public final class UwbAddress implements android.os.Parcelable {
+ method public int describeContents();
+ method @NonNull public static android.uwb.UwbAddress fromBytes(@NonNull byte[]);
+ method public int size();
+ method @NonNull public byte[] toBytes();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.uwb.UwbAddress> CREATOR;
+ field public static final int EXTENDED_ADDRESS_BYTE_LENGTH = 8; // 0x8
+ field public static final int SHORT_ADDRESS_BYTE_LENGTH = 2; // 0x2
+ }
+
+ public final class UwbManager {
+ method public long elapsedRealtimeResolutionNanos();
+ method public int getAngleOfArrivalSupport();
+ method public int getMaxRemoteDevicesPerInitiatorSession();
+ method public int getMaxRemoteDevicesPerResponderSession();
+ method public int getMaxSimultaneousSessions();
+ method @NonNull public android.os.PersistableBundle getSpecificationInfo();
+ method @NonNull public java.util.List<java.lang.Integer> getSupportedChannelNumbers();
+ method @NonNull public java.util.Set<java.lang.Integer> getSupportedPreambleCodeIndices();
+ method public boolean isRangingSupported();
+ method @NonNull public AutoCloseable openRangingSession(@NonNull android.os.PersistableBundle, @NonNull java.util.concurrent.Executor, @NonNull android.uwb.RangingSession.Callback);
+ method public void registerAdapterStateCallback(@NonNull java.util.concurrent.Executor, @NonNull android.uwb.UwbManager.AdapterStateCallback);
+ method public void unregisterAdapterStateCallback(@NonNull android.uwb.UwbManager.AdapterStateCallback);
+ field public static final int ANGLE_OF_ARRIVAL_SUPPORT_TYPE_2D = 2; // 0x2
+ field public static final int ANGLE_OF_ARRIVAL_SUPPORT_TYPE_3D_HEMISPHERICAL = 3; // 0x3
+ field public static final int ANGLE_OF_ARRIVAL_SUPPORT_TYPE_3D_SPHERICAL = 4; // 0x4
+ field public static final int ANGLE_OF_ARRIVAL_SUPPORT_TYPE_NONE = 1; // 0x1
+ }
+
+ public static interface UwbManager.AdapterStateCallback {
+ method public void onStateChanged(boolean, int);
+ field public static final int STATE_CHANGED_REASON_ALL_SESSIONS_CLOSED = 1; // 0x1
+ field public static final int STATE_CHANGED_REASON_ERROR_UNKNOWN = 4; // 0x4
+ field public static final int STATE_CHANGED_REASON_SESSION_STARTED = 0; // 0x0
+ field public static final int STATE_CHANGED_REASON_SYSTEM_BOOT = 3; // 0x3
+ field public static final int STATE_CHANGED_REASON_SYSTEM_POLICY = 2; // 0x2
+ }
+
+}
+
package android.view {
public abstract class Window {
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 9cf9ce4..ea9e926 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -980,10 +980,6 @@
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);
- }
-
public class EthernetManager {
method public void setIncludeTestInterfaces(boolean);
}
@@ -992,31 +988,10 @@
field public static final int INVALID_SECURITY_PARAMETER_INDEX = 0; // 0x0
}
- public final class NetworkCapabilities implements android.os.Parcelable {
- method public int[] getCapabilities();
- field public static final int TRANSPORT_TEST = 7; // 0x7
- }
-
public class NetworkStack {
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 c6f42f7..a31cfae 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 602b835..12c9cd9 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1428,6 +1428,45 @@
}
}
+ /**
+ * <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/OWNERS b/core/java/android/app/OWNERS
index 6d79e2d..60bfac5 100644
--- a/core/java/android/app/OWNERS
+++ b/core/java/android/app/OWNERS
@@ -42,8 +42,10 @@
# 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/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 9acf6756..69d3879 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -85,8 +85,10 @@
import android.service.restrictions.RestrictionsReceiver;
import android.telephony.TelephonyManager;
import android.telephony.data.ApnSetting;
+import android.text.TextUtils;
import android.util.ArraySet;
import android.util.Log;
+import android.util.Pair;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.net.NetworkUtilsInternal;
@@ -4524,30 +4526,10 @@
if (!proxySpec.type().equals(Proxy.Type.HTTP)) {
throw new IllegalArgumentException();
}
- InetSocketAddress sa = (InetSocketAddress)proxySpec.address();
- String hostName = sa.getHostName();
- int port = sa.getPort();
- StringBuilder hostBuilder = new StringBuilder();
- hostSpec = hostBuilder.append(hostName)
- .append(":").append(Integer.toString(port)).toString();
- if (exclusionList == null) {
- exclSpec = "";
- } else {
- StringBuilder listBuilder = new StringBuilder();
- boolean firstDomain = true;
- for (String exclDomain : exclusionList) {
- if (!firstDomain) {
- listBuilder = listBuilder.append(",");
- } else {
- firstDomain = false;
- }
- listBuilder = listBuilder.append(exclDomain.trim());
- }
- exclSpec = listBuilder.toString();
- }
- if (android.net.Proxy.validate(hostName, Integer.toString(port), exclSpec)
- != android.net.Proxy.PROXY_VALID)
- throw new IllegalArgumentException();
+ final Pair<String, String> proxyParams =
+ getProxyParameters(proxySpec, exclusionList);
+ hostSpec = proxyParams.first;
+ exclSpec = proxyParams.second;
}
return mService.setGlobalProxy(admin, hostSpec, exclSpec);
} catch (RemoteException e) {
@@ -4558,6 +4540,35 @@
}
/**
+ * Build HTTP proxy parameters for {@link IDevicePolicyManager#setGlobalProxy}.
+ * @throws IllegalArgumentException Invalid proxySpec
+ * @hide
+ */
+ @VisibleForTesting
+ public Pair<String, String> getProxyParameters(Proxy proxySpec, List<String> exclusionList) {
+ InetSocketAddress sa = (InetSocketAddress) proxySpec.address();
+ String hostName = sa.getHostName();
+ int port = sa.getPort();
+ final List<String> trimmedExclList;
+ if (exclusionList == null) {
+ trimmedExclList = Collections.emptyList();
+ } else {
+ trimmedExclList = new ArrayList<>(exclusionList.size());
+ for (String exclDomain : exclusionList) {
+ trimmedExclList.add(exclDomain.trim());
+ }
+ }
+ final ProxyInfo info = ProxyInfo.buildDirectProxy(hostName, port, trimmedExclList);
+ // The hostSpec is built assuming that there is a specified port and hostname,
+ // but ProxyInfo.isValid() accepts 0 / empty as unspecified: also reject them.
+ if (port == 0 || TextUtils.isEmpty(hostName) || !info.isValid()) {
+ throw new IllegalArgumentException();
+ }
+
+ return new Pair<>(hostName + ":" + port, TextUtils.join(",", trimmedExclList));
+ }
+
+ /**
* Set a network-independent global HTTP proxy. This is not normally what you want for typical
* HTTP proxies - they are generally network dependent. However if you're doing something
* unusual like general internal filtering this may be useful. On a private network where the
diff --git a/core/java/android/appwidget/OWNERS b/core/java/android/appwidget/OWNERS
new file mode 100644
index 0000000..439df4b
--- /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 15daf1c..cd91aa9 100644
--- a/core/java/android/bluetooth/BluetoothA2dp.java
+++ b/core/java/android/bluetooth/BluetoothA2dp.java
@@ -225,6 +225,39 @@
@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 @@
}
/**
+ * 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 0000000..cbffc78
--- /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 0000000..7e5ec1e
--- /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 92ede1c..eecdb84 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -2602,6 +2602,36 @@
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 @@
* 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 5bdd521..e351c244 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -617,6 +617,35 @@
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 44b5c44..0b950b4 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 @@
* @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 217f637c..7c14c28 100644
--- a/core/java/android/content/om/OverlayManager.java
+++ b/core/java/android/content/om/OverlayManager.java
@@ -254,6 +254,29 @@
}
/**
+ * 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 0000000..6715c82
--- /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 0000000..1fa8973
--- /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/graphics/fonts/OWNERS b/core/java/android/graphics/fonts/OWNERS
new file mode 100644
index 0000000..18486af
--- /dev/null
+++ b/core/java/android/graphics/fonts/OWNERS
@@ -0,0 +1 @@
+include /graphics/java/android/graphics/fonts/OWNERS
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index ce0ed5b..d107261 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -19,6 +19,7 @@
import static android.net.NetworkRequest.Type.LISTEN;
import static android.net.NetworkRequest.Type.REQUEST;
import static android.net.NetworkRequest.Type.TRACK_DEFAULT;
+import static android.net.QosCallback.QosCallbackRegistrationException;
import android.annotation.CallbackExecutor;
import android.annotation.IntDef;
@@ -29,7 +30,6 @@
import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SystemApi;
import android.annotation.SystemService;
-import android.annotation.TestApi;
import android.app.PendingIntent;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
@@ -4823,6 +4823,8 @@
/**
* Simulates a Data Stall for the specified Network.
*
+ * <p>This method should only be used for tests.
+ *
* <p>The caller must be the owner of the specified Network.
*
* @param detectionMethod The detection method used to identify the Data Stall.
@@ -4832,7 +4834,7 @@
* @throws SecurityException if the caller is not the owner of the given network.
* @hide
*/
- @TestApi
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
@RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_TEST_NETWORKS,
android.Manifest.permission.NETWORK_STACK})
public void simulateDataStall(int detectionMethod, long timestampMillis,
@@ -4848,4 +4850,118 @@
Log.d(TAG, "setOemNetworkPreference called with preference: "
+ preference.toString());
}
+
+ @NonNull
+ private final List<QosCallbackConnection> mQosCallbackConnections = new ArrayList<>();
+
+ /**
+ * Registers a {@link QosSocketInfo} with an associated {@link QosCallback}. The callback will
+ * receive available QoS events related to the {@link Network} and local ip + port
+ * specified within socketInfo.
+ * <p/>
+ * The same {@link QosCallback} must be unregistered before being registered a second time,
+ * otherwise {@link QosCallbackRegistrationException} is thrown.
+ * <p/>
+ * This API does not, in itself, require any permission if called with a network that is not
+ * restricted. However, the underlying implementation currently only supports the IMS network,
+ * which is always restricted. That means non-preinstalled callers can't possibly find this API
+ * useful, because they'd never be called back on networks that they would have access to.
+ *
+ * @throws SecurityException if {@link QosSocketInfo#getNetwork()} is restricted and the app is
+ * missing CONNECTIVITY_USE_RESTRICTED_NETWORKS permission.
+ * @throws QosCallback.QosCallbackRegistrationException if qosCallback is already registered.
+ * @throws RuntimeException if the app already has too many callbacks registered.
+ *
+ * Exceptions after the time of registration is passed through
+ * {@link QosCallback#onError(QosCallbackException)}. see: {@link QosCallbackException}.
+ *
+ * @param socketInfo the socket information used to match QoS events
+ * @param callback receives qos events that satisfy socketInfo
+ * @param executor The executor on which the callback will be invoked. The provided
+ * {@link Executor} must run callback sequentially, otherwise the order of
+ * callbacks cannot be guaranteed.
+ *
+ * @hide
+ */
+ @SystemApi
+ public void registerQosCallback(@NonNull final QosSocketInfo socketInfo,
+ @NonNull final QosCallback callback,
+ @CallbackExecutor @NonNull final Executor executor) {
+ Objects.requireNonNull(socketInfo, "socketInfo must be non-null");
+ Objects.requireNonNull(callback, "callback must be non-null");
+ Objects.requireNonNull(executor, "executor must be non-null");
+
+ try {
+ synchronized (mQosCallbackConnections) {
+ if (getQosCallbackConnection(callback) == null) {
+ final QosCallbackConnection connection =
+ new QosCallbackConnection(this, callback, executor);
+ mQosCallbackConnections.add(connection);
+ mService.registerQosSocketCallback(socketInfo, connection);
+ } else {
+ Log.e(TAG, "registerQosCallback: Callback already registered");
+ throw new QosCallbackRegistrationException();
+ }
+ }
+ } catch (final RemoteException e) {
+ Log.e(TAG, "registerQosCallback: Error while registering ", e);
+
+ // The same unregister method method is called for consistency even though nothing
+ // will be sent to the ConnectivityService since the callback was never successfully
+ // registered.
+ unregisterQosCallback(callback);
+ e.rethrowFromSystemServer();
+ } catch (final ServiceSpecificException e) {
+ Log.e(TAG, "registerQosCallback: Error while registering ", e);
+ unregisterQosCallback(callback);
+ throw convertServiceException(e);
+ }
+ }
+
+ /**
+ * Unregisters the given {@link QosCallback}. The {@link QosCallback} will no longer receive
+ * events once unregistered and can be registered a second time.
+ * <p/>
+ * If the {@link QosCallback} does not have an active registration, it is a no-op.
+ *
+ * @param callback the callback being unregistered
+ *
+ * @hide
+ */
+ @SystemApi
+ public void unregisterQosCallback(@NonNull final QosCallback callback) {
+ Objects.requireNonNull(callback, "The callback must be non-null");
+ try {
+ synchronized (mQosCallbackConnections) {
+ final QosCallbackConnection connection = getQosCallbackConnection(callback);
+ if (connection != null) {
+ connection.stopReceivingMessages();
+ mService.unregisterQosCallback(connection);
+ mQosCallbackConnections.remove(connection);
+ } else {
+ Log.d(TAG, "unregisterQosCallback: Callback not registered");
+ }
+ }
+ } catch (final RemoteException e) {
+ Log.e(TAG, "unregisterQosCallback: Error while unregistering ", e);
+ e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Gets the connection related to the callback.
+ *
+ * @param callback the callback to look up
+ * @return the related connection
+ */
+ @Nullable
+ private QosCallbackConnection getQosCallbackConnection(final QosCallback callback) {
+ for (final QosCallbackConnection connection : mQosCallbackConnections) {
+ // Checking by reference here is intentional
+ if (connection.getCallback() == callback) {
+ return connection;
+ }
+ }
+ return null;
+ }
}
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index 5e925b6..6fecee6 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -20,6 +20,8 @@
import android.net.ConnectionInfo;
import android.net.ConnectivityDiagnosticsManager;
import android.net.IConnectivityDiagnosticsCallback;
+import android.net.IQosCallback;
+import android.net.ISocketKeepaliveCallback;
import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkAgentConfig;
@@ -27,9 +29,9 @@
import android.net.NetworkInfo;
import android.net.NetworkRequest;
import android.net.NetworkState;
-import android.net.ISocketKeepaliveCallback;
import android.net.ProxyInfo;
import android.net.UidRange;
+import android.net.QosSocketInfo;
import android.os.Bundle;
import android.os.IBinder;
import android.os.INetworkActivityListener;
@@ -206,11 +208,11 @@
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);
@@ -239,4 +241,7 @@
void unregisterNetworkActivityListener(in INetworkActivityListener l);
boolean isDefaultNetworkActive();
+
+ void registerQosSocketCallback(in QosSocketInfo socketInfo, in IQosCallback callback);
+ void unregisterQosCallback(in IQosCallback callback);
}
diff --git a/core/java/android/net/INetworkPolicyManager.aidl b/core/java/android/net/INetworkPolicyManager.aidl
index 792e5b4..29a3fdf 100644
--- a/core/java/android/net/INetworkPolicyManager.aidl
+++ b/core/java/android/net/INetworkPolicyManager.aidl
@@ -81,4 +81,5 @@
void factoryReset(String subscriber);
boolean isUidNetworkingBlocked(int uid, boolean meteredNetwork);
+ boolean isUidRestrictedOnMeteredNetworks(int uid);
}
diff --git a/core/java/android/net/IQosCallback.aidl b/core/java/android/net/IQosCallback.aidl
new file mode 100644
index 0000000..91c7575
--- /dev/null
+++ b/core/java/android/net/IQosCallback.aidl
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.os.Bundle;
+import android.net.QosSession;
+import android.telephony.data.EpsBearerQosSessionAttributes;
+
+/**
+ * AIDL interface for QosCallback
+ *
+ * @hide
+ */
+oneway interface IQosCallback
+{
+ void onQosEpsBearerSessionAvailable(in QosSession session,
+ in EpsBearerQosSessionAttributes attributes);
+ void onQosSessionLost(in QosSession session);
+ void onError(in int type);
+}
diff --git a/core/java/android/net/NattSocketKeepalive.java b/core/java/android/net/NattSocketKeepalive.java
index b0ce0c7..a15d165 100644
--- a/core/java/android/net/NattSocketKeepalive.java
+++ b/core/java/android/net/NattSocketKeepalive.java
@@ -51,7 +51,7 @@
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 4f46736..d22d82d 100644
--- a/core/java/android/net/NetworkAgent.java
+++ b/core/java/android/net/NetworkAgent.java
@@ -30,6 +30,7 @@
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
+import android.telephony.data.EpsBearerQosSessionAttributes;
import android.util.Log;
import com.android.connectivity.aidl.INetworkAgent;
@@ -228,12 +229,6 @@
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
* CONNECTED so it can be given special treatment at that time.
@@ -347,6 +342,24 @@
*/
private static final int EVENT_AGENT_DISCONNECTED = BASE + 19;
+ /**
+ * Sent by QosCallbackTracker to {@link NetworkAgent} to register a new filter with
+ * callback.
+ *
+ * arg1 = QoS agent callback ID
+ * obj = {@link QosFilter}
+ * @hide
+ */
+ public static final int CMD_REGISTER_QOS_CALLBACK = BASE + 20;
+
+ /**
+ * Sent by QosCallbackTracker to {@link NetworkAgent} to unregister a callback.
+ *
+ * arg1 = QoS agent callback ID
+ * @hide
+ */
+ public static final int CMD_UNREGISTER_QOS_CALLBACK = BASE + 21;
+
private static NetworkInfo getLegacyNetworkInfo(final NetworkAgentConfig config) {
// The subtype can be changed with (TODO) setLegacySubtype, but it starts
// with 0 (TelephonyManager.NETWORK_TYPE_UNKNOWN) and an empty description.
@@ -526,6 +539,17 @@
onRemoveKeepalivePacketFilter(msg.arg1 /* slot */);
break;
}
+ case CMD_REGISTER_QOS_CALLBACK: {
+ onQosCallbackRegistered(
+ msg.arg1 /* QoS callback id */,
+ (QosFilter) msg.obj /* QoS filter */);
+ break;
+ }
+ case CMD_UNREGISTER_QOS_CALLBACK: {
+ onQosCallbackUnregistered(
+ msg.arg1 /* QoS callback id */);
+ break;
+ }
}
}
}
@@ -559,6 +583,8 @@
}
private static class NetworkAgentBinder extends INetworkAgent.Stub {
+ private static final String LOG_TAG = NetworkAgentBinder.class.getSimpleName();
+
private final Handler mHandler;
private NetworkAgentBinder(Handler handler) {
@@ -645,6 +671,25 @@
mHandler.sendMessage(mHandler.obtainMessage(CMD_REMOVE_KEEPALIVE_PACKET_FILTER,
slot, 0));
}
+
+ @Override
+ public void onQosFilterCallbackRegistered(final int qosCallbackId,
+ final QosFilterParcelable qosFilterParcelable) {
+ if (qosFilterParcelable.getQosFilter() != null) {
+ mHandler.sendMessage(
+ mHandler.obtainMessage(CMD_REGISTER_QOS_CALLBACK, qosCallbackId, 0,
+ qosFilterParcelable.getQosFilter()));
+ return;
+ }
+
+ Log.wtf(LOG_TAG, "onQosFilterCallbackRegistered: qos filter is null.");
+ }
+
+ @Override
+ public void onQosCallbackUnregistered(final int qosCallbackId) {
+ mHandler.sendMessage(mHandler.obtainMessage(
+ CMD_UNREGISTER_QOS_CALLBACK, qosCallbackId, 0, null));
+ }
}
/**
@@ -1073,8 +1118,68 @@
protected void preventAutomaticReconnect() {
}
+ /**
+ * Called when a qos callback is registered with a filter.
+ * @param qosCallbackId the id for the callback registered
+ * @param filter the filter being registered
+ */
+ public void onQosCallbackRegistered(final int qosCallbackId, final @NonNull QosFilter filter) {
+ }
+
+ /**
+ * Called when a qos callback is registered with a filter.
+ * <p/>
+ * Any QoS events that are sent with the same callback id after this method is called
+ * are a no-op.
+ *
+ * @param qosCallbackId the id for the callback being unregistered
+ */
+ public void onQosCallbackUnregistered(final int qosCallbackId) {
+ }
+
+
+ /**
+ * Sends the attributes of Eps Bearer Qos Session back to the Application
+ *
+ * @param qosCallbackId the callback id that the session belongs to
+ * @param sessionId the unique session id across all Eps Bearer Qos Sessions
+ * @param attributes the attributes of the Eps Qos Session
+ */
+ public final void sendQosSessionAvailable(final int qosCallbackId, final int sessionId,
+ @NonNull final EpsBearerQosSessionAttributes attributes) {
+ Objects.requireNonNull(attributes, "The attributes must be non-null");
+ queueOrSendMessage(ra -> ra.sendEpsQosSessionAvailable(qosCallbackId,
+ new QosSession(sessionId, QosSession.TYPE_EPS_BEARER),
+ attributes));
+ }
+
+ /**
+ * Sends event that the Eps Qos Session was lost.
+ *
+ * @param qosCallbackId the callback id that the session belongs to
+ * @param sessionId the unique session id across all Eps Bearer Qos Sessions
+ */
+ public final void sendQosSessionLost(final int qosCallbackId, final int sessionId) {
+ queueOrSendMessage(ra -> ra.sendQosSessionLost(qosCallbackId,
+ new QosSession(sessionId, QosSession.TYPE_EPS_BEARER)));
+ }
+
+ /**
+ * Sends the exception type back to the application.
+ *
+ * The NetworkAgent should not send anymore messages with this id.
+ *
+ * @param qosCallbackId the callback id this exception belongs to
+ * @param exceptionType the type of exception
+ */
+ public final void sendQosCallbackError(final int qosCallbackId,
+ @QosCallbackException.ExceptionType final int exceptionType) {
+ queueOrSendMessage(ra -> ra.sendQosCallbackError(qosCallbackId, exceptionType));
+ }
+
+
/** @hide */
- protected void log(String s) {
+ protected void log(final String s) {
Log.d(LOG_TAG, "NetworkAgent: " + s);
}
}
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index 2d9f6d8..0a895b9 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -23,7 +23,6 @@
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
-import android.annotation.TestApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.net.ConnectivityManager.NetworkCallback;
import android.os.Build;
@@ -576,7 +575,6 @@
* @hide
*/
@UnsupportedAppUsage
- @TestApi
public @NetCapability int[] getCapabilities() {
return BitUtils.unpackBits(mNetworkCapabilities);
}
@@ -821,7 +819,7 @@
*
* @hide
*/
- @TestApi
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static final int TRANSPORT_TEST = 7;
/** @hide */
diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java
index c029dea..82b035b 100644
--- a/core/java/android/net/NetworkPolicyManager.java
+++ b/core/java/android/net/NetworkPolicyManager.java
@@ -460,6 +460,22 @@
}
/**
+ * Check that the given uid is restricted from doing networking on metered networks.
+ *
+ * @param uid The target uid.
+ * @return true if the given uid is restricted from doing networking on metered networks.
+ *
+ * @hide
+ */
+ public boolean isUidRestrictedOnMeteredNetworks(int uid) {
+ try {
+ return mService.isUidRestrictedOnMeteredNetworks(uid);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Get multipath preference for the given network.
*/
public int getMultipathPreference(Network network) {
diff --git a/core/java/android/net/NetworkReleasedException.java b/core/java/android/net/NetworkReleasedException.java
new file mode 100644
index 0000000..0629b75
--- /dev/null
+++ b/core/java/android/net/NetworkReleasedException.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.annotation.SystemApi;
+
+/**
+ * Indicates that the {@link Network} was released and is no longer available.
+ *
+ * @hide
+ */
+@SystemApi
+public class NetworkReleasedException extends Exception {
+ /** @hide */
+ public NetworkReleasedException() {
+ super("The network was released and is no longer available");
+ }
+}
diff --git a/core/java/android/net/QosCallback.java b/core/java/android/net/QosCallback.java
new file mode 100644
index 0000000..22f06bc
--- /dev/null
+++ b/core/java/android/net/QosCallback.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+
+import java.util.concurrent.Executor;
+
+/**
+ * Receives Qos information given a {@link Network}. The callback is registered with
+ * {@link ConnectivityManager#registerQosCallback}.
+ *
+ * <p>
+ * <br/>
+ * The callback will no longer receive calls if any of the following takes place:
+ * <ol>
+ * <li>{@link ConnectivityManager#unregisterQosCallback(QosCallback)} is called with the same
+ * callback instance.</li>
+ * <li>{@link QosCallback#onError(QosCallbackException)} is called.</li>
+ * <li>A network specific issue occurs. eg. Congestion on a carrier network.</li>
+ * <li>The network registered with the callback has no associated QoS providers</li>
+ * </ul>
+ * {@hide}
+ */
+@SystemApi
+public abstract class QosCallback {
+ /**
+ * Invoked after an error occurs on a registered callback. Once called, the callback is
+ * automatically unregistered and the callback will no longer receive calls.
+ *
+ * <p>The underlying exception can either be a runtime exception or a custom exception made for
+ * {@link QosCallback}. see: {@link QosCallbackException}.
+ *
+ * @param exception wraps the underlying cause
+ */
+ public void onError(@NonNull final QosCallbackException exception) {
+ }
+
+ /**
+ * Called when a Qos Session first becomes available to the callback or if its attributes have
+ * changed.
+ * <p>
+ * Note: The callback may be called multiple times with the same attributes.
+ *
+ * @param session the available session
+ * @param sessionAttributes the attributes of the session
+ */
+ public void onQosSessionAvailable(@NonNull final QosSession session,
+ @NonNull final QosSessionAttributes sessionAttributes) {
+ }
+
+ /**
+ * Called after a Qos Session is lost.
+ * <p>
+ * At least one call to
+ * {@link QosCallback#onQosSessionAvailable(QosSession, QosSessionAttributes)}
+ * with the same {@link QosSession} will precede a call to lost.
+ *
+ * @param session the lost session
+ */
+ public void onQosSessionLost(@NonNull final QosSession session) {
+ }
+
+ /**
+ * Thrown when there is a problem registering {@link QosCallback} with
+ * {@link ConnectivityManager#registerQosCallback(QosSocketInfo, QosCallback, Executor)}.
+ */
+ public static class QosCallbackRegistrationException extends RuntimeException {
+ /**
+ * @hide
+ */
+ public QosCallbackRegistrationException() {
+ super();
+ }
+ }
+}
diff --git a/core/java/android/net/QosCallbackConnection.java b/core/java/android/net/QosCallbackConnection.java
new file mode 100644
index 0000000..bdb4ad6
--- /dev/null
+++ b/core/java/android/net/QosCallbackConnection.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.telephony.data.EpsBearerQosSessionAttributes;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.Objects;
+import java.util.concurrent.Executor;
+
+/**
+ * Sends messages from {@link com.android.server.ConnectivityService} to the registered
+ * {@link QosCallback}.
+ * <p/>
+ * This is a satellite class of {@link ConnectivityManager} and not meant
+ * to be used in other contexts.
+ *
+ * @hide
+ */
+class QosCallbackConnection extends android.net.IQosCallback.Stub {
+
+ @NonNull private final ConnectivityManager mConnectivityManager;
+ @Nullable private volatile QosCallback mCallback;
+ @NonNull private final Executor mExecutor;
+
+ @VisibleForTesting
+ @Nullable
+ public QosCallback getCallback() {
+ return mCallback;
+ }
+
+ /**
+ * The constructor for the connection
+ *
+ * @param connectivityManager the mgr that created this connection
+ * @param callback the callback to send messages back to
+ * @param executor The executor on which the callback will be invoked. The provided
+ * {@link Executor} must run callback sequentially, otherwise the order of
+ * callbacks cannot be guaranteed.
+ */
+ QosCallbackConnection(@NonNull final ConnectivityManager connectivityManager,
+ @NonNull final QosCallback callback,
+ @NonNull final Executor executor) {
+ mConnectivityManager = Objects.requireNonNull(connectivityManager,
+ "connectivityManager must be non-null");
+ mCallback = Objects.requireNonNull(callback, "callback must be non-null");
+ mExecutor = Objects.requireNonNull(executor, "executor must be non-null");
+ }
+
+ /**
+ * Called when either the {@link EpsBearerQosSessionAttributes} has changed or on the first time
+ * the attributes have become available.
+ *
+ * @param session the session that is now available
+ * @param attributes the corresponding attributes of session
+ */
+ @Override
+ public void onQosEpsBearerSessionAvailable(@NonNull final QosSession session,
+ @NonNull final EpsBearerQosSessionAttributes attributes) {
+
+ mExecutor.execute(() -> {
+ final QosCallback callback = mCallback;
+ if (callback != null) {
+ callback.onQosSessionAvailable(session, attributes);
+ }
+ });
+ }
+
+ /**
+ * Called when the session is lost.
+ *
+ * @param session the session that was lost
+ */
+ @Override
+ public void onQosSessionLost(@NonNull final QosSession session) {
+ mExecutor.execute(() -> {
+ final QosCallback callback = mCallback;
+ if (callback != null) {
+ callback.onQosSessionLost(session);
+ }
+ });
+ }
+
+ /**
+ * Called when there is an error on the registered callback.
+ *
+ * @param errorType the type of error
+ */
+ @Override
+ public void onError(@QosCallbackException.ExceptionType final int errorType) {
+ mExecutor.execute(() -> {
+ final QosCallback callback = mCallback;
+ if (callback != null) {
+ // Messages no longer need to be received since there was an error.
+ stopReceivingMessages();
+ mConnectivityManager.unregisterQosCallback(callback);
+ callback.onError(QosCallbackException.createException(errorType));
+ }
+ });
+ }
+
+ /**
+ * The callback will stop receiving messages.
+ * <p/>
+ * There are no synchronization guarantees on exactly when the callback will stop receiving
+ * messages.
+ */
+ void stopReceivingMessages() {
+ mCallback = null;
+ }
+}
diff --git a/core/java/android/net/QosCallbackException.java b/core/java/android/net/QosCallbackException.java
new file mode 100644
index 0000000..7fd9a527e
--- /dev/null
+++ b/core/java/android/net/QosCallbackException.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;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.util.Log;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * This is the exception type passed back through the onError method on {@link QosCallback}.
+ * {@link QosCallbackException#getCause()} contains the actual error that caused this exception.
+ *
+ * The possible exception types as causes are:
+ * 1. {@link NetworkReleasedException}
+ * 2. {@link SocketNotBoundException}
+ * 3. {@link UnsupportedOperationException}
+ * 4. {@link SocketLocalAddressChangedException}
+ *
+ * @hide
+ */
+@SystemApi
+public final class QosCallbackException extends Exception {
+
+ /** @hide */
+ @IntDef(prefix = {"EX_TYPE_"}, value = {
+ EX_TYPE_FILTER_NONE,
+ EX_TYPE_FILTER_NETWORK_RELEASED,
+ EX_TYPE_FILTER_SOCKET_NOT_BOUND,
+ EX_TYPE_FILTER_NOT_SUPPORTED,
+ EX_TYPE_FILTER_SOCKET_LOCAL_ADDRESS_CHANGED,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ExceptionType {}
+
+ private static final String TAG = "QosCallbackException";
+
+ // Types of exceptions supported //
+ /** {@hide} */
+ public static final int EX_TYPE_FILTER_NONE = 0;
+
+ /** {@hide} */
+ public static final int EX_TYPE_FILTER_NETWORK_RELEASED = 1;
+
+ /** {@hide} */
+ public static final int EX_TYPE_FILTER_SOCKET_NOT_BOUND = 2;
+
+ /** {@hide} */
+ public static final int EX_TYPE_FILTER_NOT_SUPPORTED = 3;
+
+ /** {@hide} */
+ public static final int EX_TYPE_FILTER_SOCKET_LOCAL_ADDRESS_CHANGED = 4;
+
+ /**
+ * Creates exception based off of a type and message. Not all types of exceptions accept a
+ * custom message.
+ *
+ * {@hide}
+ */
+ @NonNull
+ static QosCallbackException createException(@ExceptionType final int type) {
+ switch (type) {
+ case EX_TYPE_FILTER_NETWORK_RELEASED:
+ return new QosCallbackException(new NetworkReleasedException());
+ case EX_TYPE_FILTER_SOCKET_NOT_BOUND:
+ return new QosCallbackException(new SocketNotBoundException());
+ case EX_TYPE_FILTER_NOT_SUPPORTED:
+ return new QosCallbackException(new UnsupportedOperationException(
+ "This device does not support the specified filter"));
+ case EX_TYPE_FILTER_SOCKET_LOCAL_ADDRESS_CHANGED:
+ return new QosCallbackException(
+ new SocketLocalAddressChangedException());
+ default:
+ Log.wtf(TAG, "create: No case setup for exception type: '" + type + "'");
+ return new QosCallbackException(
+ new RuntimeException("Unknown exception code: " + type));
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public QosCallbackException(@NonNull final String message) {
+ super(message);
+ }
+
+ /**
+ * @hide
+ */
+ public QosCallbackException(@NonNull final Throwable cause) {
+ super(cause);
+ }
+}
diff --git a/core/java/android/net/QosFilter.java b/core/java/android/net/QosFilter.java
new file mode 100644
index 0000000..ab55002
--- /dev/null
+++ b/core/java/android/net/QosFilter.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+
+import java.net.InetAddress;
+
+/**
+ * Provides the related filtering logic to the {@link NetworkAgent} to match {@link QosSession}s
+ * to their related {@link QosCallback}.
+ *
+ * Used by the {@link com.android.server.ConnectivityService} to validate a {@link QosCallback}
+ * is still able to receive a {@link QosSession}.
+ *
+ * @hide
+ */
+@SystemApi
+public abstract class QosFilter {
+
+ /**
+ * The constructor is kept hidden from outside this package to ensure that all derived types
+ * are known and properly handled when being passed to and from {@link NetworkAgent}.
+ *
+ * @hide
+ */
+ QosFilter() {
+ }
+
+ /**
+ * The network used with this filter.
+ *
+ * @return the registered {@link Network}
+ */
+ @NonNull
+ public abstract Network getNetwork();
+
+ /**
+ * Validates that conditions have not changed such that no further {@link QosSession}s should
+ * be passed back to the {@link QosCallback} associated to this filter.
+ *
+ * @return the error code when present, otherwise the filter is valid
+ *
+ * @hide
+ */
+ @QosCallbackException.ExceptionType
+ public abstract int validate();
+
+ /**
+ * Determines whether or not the parameters is a match for the filter.
+ *
+ * @param address the local address
+ * @param startPort the start of the port range
+ * @param endPort the end of the port range
+ * @return whether the parameters match the local address of the filter
+ */
+ public abstract boolean matchesLocalAddress(@NonNull InetAddress address,
+ int startPort, int endPort);
+}
+
diff --git a/core/java/android/net/QosFilterParcelable.aidl b/core/java/android/net/QosFilterParcelable.aidl
new file mode 100644
index 0000000..312d635
--- /dev/null
+++ b/core/java/android/net/QosFilterParcelable.aidl
@@ -0,0 +1,21 @@
+/*
+**
+** 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;
+
+parcelable QosFilterParcelable;
+
diff --git a/core/java/android/net/QosFilterParcelable.java b/core/java/android/net/QosFilterParcelable.java
new file mode 100644
index 0000000..da3b2cf
--- /dev/null
+++ b/core/java/android/net/QosFilterParcelable.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+
+import java.util.Objects;
+
+/**
+ * Aware of how to parcel different types of {@link QosFilter}s. Any new type of qos filter must
+ * have a specialized case written here.
+ * <p/>
+ * Specifically leveraged when transferring {@link QosFilter} from
+ * {@link com.android.server.ConnectivityService} to {@link NetworkAgent} when the filter is first
+ * registered.
+ * <p/>
+ * This is not meant to be used in other contexts.
+ *
+ * @hide
+ */
+public final class QosFilterParcelable implements Parcelable {
+
+ private static final String LOG_TAG = QosFilterParcelable.class.getSimpleName();
+
+ // Indicates that the filter was not successfully written to the parcel.
+ private static final int NO_FILTER_PRESENT = 0;
+
+ // The parcel is of type qos socket filter.
+ private static final int QOS_SOCKET_FILTER = 1;
+
+ private final QosFilter mQosFilter;
+
+ /**
+ * The underlying qos filter.
+ * <p/>
+ * Null only in the case parceling failed.
+ */
+ @Nullable
+ public QosFilter getQosFilter() {
+ return mQosFilter;
+ }
+
+ public QosFilterParcelable(@NonNull final QosFilter qosFilter) {
+ Objects.requireNonNull(qosFilter, "qosFilter must be non-null");
+
+ // NOTE: Normally a type check would belong here, but doing so breaks unit tests that rely
+ // on mocking qos filter.
+ mQosFilter = qosFilter;
+ }
+
+ private QosFilterParcelable(final Parcel in) {
+ final int filterParcelType = in.readInt();
+
+ switch (filterParcelType) {
+ case QOS_SOCKET_FILTER: {
+ mQosFilter = new QosSocketFilter(QosSocketInfo.CREATOR.createFromParcel(in));
+ break;
+ }
+
+ case NO_FILTER_PRESENT:
+ default: {
+ mQosFilter = null;
+ }
+ }
+ }
+
+ public static final Creator<QosFilterParcelable> CREATOR = new Creator<QosFilterParcelable>() {
+ @Override
+ public QosFilterParcelable createFromParcel(final Parcel in) {
+ return new QosFilterParcelable(in);
+ }
+
+ @Override
+ public QosFilterParcelable[] newArray(final int size) {
+ return new QosFilterParcelable[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(final Parcel dest, final int flags) {
+ if (mQosFilter instanceof QosSocketFilter) {
+ dest.writeInt(QOS_SOCKET_FILTER);
+ final QosSocketFilter qosSocketFilter = (QosSocketFilter) mQosFilter;
+ qosSocketFilter.getQosSocketInfo().writeToParcel(dest, 0);
+ return;
+ }
+ dest.writeInt(NO_FILTER_PRESENT);
+ Log.e(LOG_TAG, "Parceling failed, unknown type of filter present: " + mQosFilter);
+ }
+}
diff --git a/core/java/android/net/QosSession.aidl b/core/java/android/net/QosSession.aidl
new file mode 100644
index 0000000..c2cf366
--- /dev/null
+++ b/core/java/android/net/QosSession.aidl
@@ -0,0 +1,21 @@
+/*
+**
+** 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;
+
+parcelable QosSession;
+
diff --git a/core/java/android/net/QosSession.java b/core/java/android/net/QosSession.java
new file mode 100644
index 0000000..4f3bb77
--- /dev/null
+++ b/core/java/android/net/QosSession.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Provides identifying information of a QoS session. Sent to an application through
+ * {@link QosCallback}.
+ *
+ * @hide
+ */
+@SystemApi
+public final class QosSession implements Parcelable {
+
+ /**
+ * The {@link QosSession} is a LTE EPS Session.
+ */
+ public static final int TYPE_EPS_BEARER = 1;
+
+ private final int mSessionId;
+
+ private final int mSessionType;
+
+ /**
+ * Gets the unique id of the session that is used to differentiate sessions across different
+ * types.
+ * <p/>
+ * Note: Different qos sessions can be provided by different actors.
+ *
+ * @return the unique id
+ */
+ public long getUniqueId() {
+ return (long) mSessionType << 32 | mSessionId;
+ }
+
+ /**
+ * Gets the session id that is unique within that type.
+ * <p/>
+ * Note: The session id is set by the actor providing the qos. It can be either manufactured by
+ * the actor, but also may have a particular meaning within that type. For example, using the
+ * bearer id as the session id for {@link android.telephony.data.EpsBearerQosSessionAttributes}
+ * is a straight forward way to keep the sessions unique from one another within that type.
+ *
+ * @return the id of the session
+ */
+ public int getSessionId() {
+ return mSessionId;
+ }
+
+ /**
+ * Gets the type of session.
+ */
+ @QosSessionType
+ public int getSessionType() {
+ return mSessionType;
+ }
+
+ /**
+ * Creates a {@link QosSession}.
+ *
+ * @param sessionId uniquely identifies the session across all sessions of the same type
+ * @param sessionType the type of session
+ */
+ public QosSession(final int sessionId, @QosSessionType final int sessionType) {
+ //Ensures the session id is unique across types of sessions
+ mSessionId = sessionId;
+ mSessionType = sessionType;
+ }
+
+
+ @Override
+ public String toString() {
+ return "QosSession{"
+ + "mSessionId=" + mSessionId
+ + ", mSessionType=" + mSessionType
+ + '}';
+ }
+
+ /**
+ * Annotations for types of qos sessions.
+ */
+ @IntDef(value = {
+ TYPE_EPS_BEARER,
+ })
+ @interface QosSessionType {}
+
+ private QosSession(final Parcel in) {
+ mSessionId = in.readInt();
+ mSessionType = in.readInt();
+ }
+
+ @NonNull
+ public static final Creator<QosSession> CREATOR = new Creator<QosSession>() {
+ @NonNull
+ @Override
+ public QosSession createFromParcel(@NonNull final Parcel in) {
+ return new QosSession(in);
+ }
+
+ @NonNull
+ @Override
+ public QosSession[] newArray(final int size) {
+ return new QosSession[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull final Parcel dest, final int flags) {
+ dest.writeInt(mSessionId);
+ dest.writeInt(mSessionType);
+ }
+}
diff --git a/core/java/android/net/QosSessionAttributes.java b/core/java/android/net/QosSessionAttributes.java
new file mode 100644
index 0000000..7a88594
--- /dev/null
+++ b/core/java/android/net/QosSessionAttributes.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.annotation.SystemApi;
+
+/**
+ * Implemented by classes that encapsulate Qos related attributes that describe a Qos Session.
+ *
+ * Use the instanceof keyword to determine the underlying type.
+ *
+ * @hide
+ */
+@SystemApi
+public interface QosSessionAttributes {
+}
diff --git a/core/java/android/net/QosSocketFilter.java b/core/java/android/net/QosSocketFilter.java
new file mode 100644
index 0000000..2080e68
--- /dev/null
+++ b/core/java/android/net/QosSocketFilter.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import static android.net.QosCallbackException.EX_TYPE_FILTER_NONE;
+import static android.net.QosCallbackException.EX_TYPE_FILTER_SOCKET_LOCAL_ADDRESS_CHANGED;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.ParcelFileDescriptor;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.io.FileDescriptor;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.net.SocketAddress;
+import java.util.Objects;
+
+/**
+ * Filters a {@link QosSession} according to the binding on the provided {@link Socket}.
+ *
+ * @hide
+ */
+public class QosSocketFilter extends QosFilter {
+
+ private static final String TAG = QosSocketFilter.class.getSimpleName();
+
+ @NonNull
+ private final QosSocketInfo mQosSocketInfo;
+
+ /**
+ * Creates a {@link QosSocketFilter} based off of {@link QosSocketInfo}.
+ *
+ * @param qosSocketInfo the information required to filter and validate
+ */
+ public QosSocketFilter(@NonNull final QosSocketInfo qosSocketInfo) {
+ Objects.requireNonNull(qosSocketInfo, "qosSocketInfo must be non-null");
+ mQosSocketInfo = qosSocketInfo;
+ }
+
+ /**
+ * Gets the parcelable qos socket info that was used to create the filter.
+ */
+ @NonNull
+ public QosSocketInfo getQosSocketInfo() {
+ return mQosSocketInfo;
+ }
+
+ /**
+ * Performs two validations:
+ * 1. If the socket is not bound, then return
+ * {@link QosCallbackException.EX_TYPE_FILTER_SOCKET_NOT_BOUND}. This is detected
+ * by checking the local address on the filter which becomes null when the socket is no
+ * longer bound.
+ * 2. In the scenario that the socket is now bound to a different local address, which can
+ * happen in the case of UDP, then
+ * {@link QosCallbackException.EX_TYPE_FILTER_SOCKET_LOCAL_ADDRESS_CHANGED} is returned.
+ * @return validation error code
+ */
+ @Override
+ public int validate() {
+ final InetSocketAddress sa = getAddressFromFileDescriptor();
+ if (sa == null) {
+ return QosCallbackException.EX_TYPE_FILTER_SOCKET_NOT_BOUND;
+ }
+
+ if (!sa.equals(mQosSocketInfo.getLocalSocketAddress())) {
+ return EX_TYPE_FILTER_SOCKET_LOCAL_ADDRESS_CHANGED;
+ }
+
+ return EX_TYPE_FILTER_NONE;
+ }
+
+ /**
+ * The local address of the socket's binding.
+ *
+ * Note: If the socket is no longer bound, null is returned.
+ *
+ * @return the local address
+ */
+ @Nullable
+ private InetSocketAddress getAddressFromFileDescriptor() {
+ final ParcelFileDescriptor parcelFileDescriptor = mQosSocketInfo.getParcelFileDescriptor();
+ if (parcelFileDescriptor == null) return null;
+
+ final FileDescriptor fd = parcelFileDescriptor.getFileDescriptor();
+ if (fd == null) return null;
+
+ final SocketAddress address;
+ try {
+ address = Os.getsockname(fd);
+ } catch (final ErrnoException e) {
+ Log.e(TAG, "getAddressFromFileDescriptor: getLocalAddress exception", e);
+ return null;
+ }
+ if (address instanceof InetSocketAddress) {
+ return (InetSocketAddress) address;
+ }
+ return null;
+ }
+
+ /**
+ * The network used with this filter.
+ *
+ * @return the registered {@link Network}
+ */
+ @NonNull
+ @Override
+ public Network getNetwork() {
+ return mQosSocketInfo.getNetwork();
+ }
+
+ /**
+ * @inheritDoc
+ */
+ @Override
+ public boolean matchesLocalAddress(@NonNull final InetAddress address, final int startPort,
+ final int endPort) {
+ if (mQosSocketInfo.getLocalSocketAddress() == null) {
+ return false;
+ }
+
+ return matchesLocalAddress(mQosSocketInfo.getLocalSocketAddress(), address, startPort,
+ endPort);
+ }
+
+ /**
+ * Called from {@link QosSocketFilter#matchesLocalAddress(InetAddress, int, int)} with the
+ * filterSocketAddress coming from {@link QosSocketInfo#getLocalSocketAddress()}.
+ * <p>
+ * This method exists for testing purposes since {@link QosSocketInfo} couldn't be mocked
+ * due to being final.
+ *
+ * @param filterSocketAddress the socket address of the filter
+ * @param address the address to compare the filterSocketAddressWith
+ * @param startPort the start of the port range to check
+ * @param endPort the end of the port range to check
+ */
+ @VisibleForTesting
+ public static boolean matchesLocalAddress(@NonNull final InetSocketAddress filterSocketAddress,
+ @NonNull final InetAddress address,
+ final int startPort, final int endPort) {
+ return startPort <= filterSocketAddress.getPort()
+ && endPort >= filterSocketAddress.getPort()
+ && filterSocketAddress.getAddress().equals(address);
+ }
+}
diff --git a/core/java/android/net/QosSocketInfo.aidl b/core/java/android/net/QosSocketInfo.aidl
new file mode 100644
index 0000000..476c090
--- /dev/null
+++ b/core/java/android/net/QosSocketInfo.aidl
@@ -0,0 +1,21 @@
+/*
+**
+** 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;
+
+parcelable QosSocketInfo;
+
diff --git a/core/java/android/net/QosSocketInfo.java b/core/java/android/net/QosSocketInfo.java
new file mode 100644
index 0000000..d37c469
--- /dev/null
+++ b/core/java/android/net/QosSocketInfo.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.ParcelFileDescriptor;
+import android.os.Parcelable;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.net.UnknownHostException;
+import java.util.Objects;
+
+/**
+ * Used in conjunction with
+ * {@link ConnectivityManager#registerQosCallback}
+ * in order to receive Qos Sessions related to the local address and port of a bound {@link Socket}.
+ *
+ * @hide
+ */
+@SystemApi
+public final class QosSocketInfo implements Parcelable {
+
+ @NonNull
+ private final Network mNetwork;
+
+ @NonNull
+ private final ParcelFileDescriptor mParcelFileDescriptor;
+
+ @NonNull
+ private final InetSocketAddress mLocalSocketAddress;
+
+ /**
+ * The {@link Network} the socket is on.
+ *
+ * @return the registered {@link Network}
+ */
+ @NonNull
+ public Network getNetwork() {
+ return mNetwork;
+ }
+
+ /**
+ * The parcel file descriptor wrapped around the socket's file descriptor.
+ *
+ * @return the parcel file descriptor of the socket
+ */
+ @NonNull
+ ParcelFileDescriptor getParcelFileDescriptor() {
+ return mParcelFileDescriptor;
+ }
+
+ /**
+ * The local address of the socket passed into {@link QosSocketInfo(Network, Socket)}.
+ * The value does not reflect any changes that occur to the socket after it is first set
+ * in the constructor.
+ *
+ * @return the local address of the socket
+ */
+ @NonNull
+ public InetSocketAddress getLocalSocketAddress() {
+ return mLocalSocketAddress;
+ }
+
+ /**
+ * Creates a {@link QosSocketInfo} given a {@link Network} and bound {@link Socket}. The
+ * {@link Socket} must remain bound in order to receive {@link QosSession}s.
+ *
+ * @param network the network
+ * @param socket the bound {@link Socket}
+ */
+ public QosSocketInfo(@NonNull final Network network, @NonNull final Socket socket)
+ throws IOException {
+ Objects.requireNonNull(socket, "socket cannot be null");
+
+ mNetwork = Objects.requireNonNull(network, "network cannot be null");
+ mParcelFileDescriptor = ParcelFileDescriptor.dup(socket.getFileDescriptor$());
+ mLocalSocketAddress =
+ new InetSocketAddress(socket.getLocalAddress(), socket.getLocalPort());
+ }
+
+ /* Parcelable methods */
+ private QosSocketInfo(final Parcel in) {
+ mNetwork = Objects.requireNonNull(Network.CREATOR.createFromParcel(in));
+ mParcelFileDescriptor = ParcelFileDescriptor.CREATOR.createFromParcel(in);
+
+ final int addressLength = in.readInt();
+ mLocalSocketAddress = readSocketAddress(in, addressLength);
+ }
+
+ private InetSocketAddress readSocketAddress(final Parcel in, final int addressLength) {
+ final byte[] address = new byte[addressLength];
+ in.readByteArray(address);
+ final int port = in.readInt();
+
+ try {
+ return new InetSocketAddress(InetAddress.getByAddress(address), port);
+ } catch (final UnknownHostException e) {
+ /* The catch block was purposely left empty. UnknownHostException will never be thrown
+ since the address provided is numeric and non-null. */
+ }
+ return new InetSocketAddress();
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull final Parcel dest, final int flags) {
+ mNetwork.writeToParcel(dest, 0);
+ mParcelFileDescriptor.writeToParcel(dest, 0);
+
+ final byte[] address = mLocalSocketAddress.getAddress().getAddress();
+ dest.writeInt(address.length);
+ dest.writeByteArray(address);
+ dest.writeInt(mLocalSocketAddress.getPort());
+ }
+
+ @NonNull
+ public static final Parcelable.Creator<QosSocketInfo> CREATOR =
+ new Parcelable.Creator<QosSocketInfo>() {
+ @NonNull
+ @Override
+ public QosSocketInfo createFromParcel(final Parcel in) {
+ return new QosSocketInfo(in);
+ }
+
+ @NonNull
+ @Override
+ public QosSocketInfo[] newArray(final int size) {
+ return new QosSocketInfo[size];
+ }
+ };
+}
diff --git a/core/java/android/net/SocketLocalAddressChangedException.java b/core/java/android/net/SocketLocalAddressChangedException.java
new file mode 100644
index 0000000..9daad83
--- /dev/null
+++ b/core/java/android/net/SocketLocalAddressChangedException.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.annotation.SystemApi;
+
+/**
+ * Thrown when the local address of the socket has changed.
+ *
+ * @hide
+ */
+@SystemApi
+public class SocketLocalAddressChangedException extends Exception {
+ /** @hide */
+ public SocketLocalAddressChangedException() {
+ super("The local address of the socket changed");
+ }
+}
diff --git a/core/java/android/net/SocketNotBoundException.java b/core/java/android/net/SocketNotBoundException.java
new file mode 100644
index 0000000..b1d7026
--- /dev/null
+++ b/core/java/android/net/SocketNotBoundException.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.annotation.SystemApi;
+
+/**
+ * Thrown when a previously bound socket becomes unbound.
+ *
+ * @hide
+ */
+@SystemApi
+public class SocketNotBoundException extends Exception {
+ /** @hide */
+ public SocketNotBoundException() {
+ super("The socket is unbound");
+ }
+}
diff --git a/core/java/android/net/TcpSocketKeepalive.java b/core/java/android/net/TcpSocketKeepalive.java
index 436397e..d89814d 100644
--- a/core/java/android/net/TcpSocketKeepalive.java
+++ b/core/java/android/net/TcpSocketKeepalive.java
@@ -21,7 +21,6 @@
import android.os.RemoteException;
import android.util.Log;
-import java.io.FileDescriptor;
import java.util.concurrent.Executor;
/** @hide */
@@ -54,8 +53,7 @@
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 8455083..4449ff8 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 @@
*
* @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 @@
}
@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 a0a563b..4e89414 100644
--- a/core/java/android/net/TestNetworkManager.java
+++ b/core/java/android/net/TestNetworkManager.java
@@ -17,18 +17,21 @@
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 @@
* @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 @@
* @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 @@
* @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 @@
* 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 ab12cdd..3d79f284 100644
--- a/core/java/android/net/metrics/ApfProgramEvent.java
+++ b/core/java/android/net/metrics/ApfProgramEvent.java
@@ -39,7 +39,11 @@
* 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 fcafb7e..a32d3a6 100644
--- a/core/java/android/net/metrics/ApfStats.java
+++ b/core/java/android/net/metrics/ApfStats.java
@@ -27,7 +27,11 @@
/**
* 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 8de427d..e175d58 100644
--- a/core/java/android/net/metrics/DhcpClientEvent.java
+++ b/core/java/android/net/metrics/DhcpClientEvent.java
@@ -28,7 +28,11 @@
/**
* 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 de3129d..7dd0696 100644
--- a/core/java/android/net/metrics/DhcpErrorEvent.java
+++ b/core/java/android/net/metrics/DhcpErrorEvent.java
@@ -27,7 +27,11 @@
/**
* 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 bb91f89..5cadb45 100644
--- a/core/java/android/net/metrics/IpConnectivityLog.java
+++ b/core/java/android/net/metrics/IpConnectivityLog.java
@@ -35,7 +35,11 @@
/**
* 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();
diff --git a/core/java/android/net/metrics/IpManagerEvent.java b/core/java/android/net/metrics/IpManagerEvent.java
index 4f7f326..3abcc05 100644
--- a/core/java/android/net/metrics/IpManagerEvent.java
+++ b/core/java/android/net/metrics/IpManagerEvent.java
@@ -33,7 +33,11 @@
* 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 d5003ba..0b65bbd 100644
--- a/core/java/android/net/metrics/IpReachabilityEvent.java
+++ b/core/java/android/net/metrics/IpReachabilityEvent.java
@@ -29,7 +29,11 @@
* 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 8c28f7a..47eeeff 100644
--- a/core/java/android/net/metrics/NetworkEvent.java
+++ b/core/java/android/net/metrics/NetworkEvent.java
@@ -31,7 +31,11 @@
/**
* {@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 b54874f..05a47e5 100644
--- a/core/java/android/net/metrics/RaEvent.java
+++ b/core/java/android/net/metrics/RaEvent.java
@@ -25,7 +25,11 @@
/**
* 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 7f4e4a7..8118fe0 100644
--- a/core/java/android/net/metrics/ValidationProbeEvent.java
+++ b/core/java/android/net/metrics/ValidationProbeEvent.java
@@ -32,7 +32,11 @@
/**
* 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 8dfd4e1..85e3fa3 100644
--- a/core/java/android/net/util/MultinetworkPolicyTracker.java
+++ b/core/java/android/net/util/MultinetworkPolicyTracker.java
@@ -29,7 +29,6 @@
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 @@
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 04b585c..80ac64b 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 @@
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 0000000..f8ae492
--- /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 039360a..d531cdb 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 @@
*
* @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 @@
*
* @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 @@
* @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 @@
* @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 @@
* @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 @@
* @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 b881a339..2ccdc26 100644
--- a/core/java/android/net/vcn/VcnManager.java
+++ b/core/java/android/net/vcn/VcnManager.java
@@ -25,7 +25,12 @@
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 @@
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 @@
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 0000000..6cb6ee6
--- /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 0000000..dd7c86d8
--- /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 0b2cfdd..bc3d5c4 100644
--- a/core/java/android/nfc/INfcAdapter.aidl
+++ b/core/java/android/nfc/INfcAdapter.aidl
@@ -72,4 +72,7 @@
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 a17a5370..e85eb93 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -350,6 +350,22 @@
"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 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 @@
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 fdccaae..2256365 100644
--- a/core/java/android/nfc/tech/Ndef.java
+++ b/core/java/android/nfc/tech/Ndef.java
@@ -112,7 +112,7 @@
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 33736d3..305c686 100644
--- a/core/java/android/os/BugreportManager.java
+++ b/core/java/android/os/BugreportManager.java
@@ -22,6 +22,7 @@
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;
@@ -40,12 +41,7 @@
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 {
@@ -60,28 +56,30 @@
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;
@@ -99,6 +97,7 @@
/**
* 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) {}
@@ -113,14 +112,12 @@
* 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() {}
/**
@@ -137,20 +134,23 @@
* 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,
@@ -164,17 +164,21 @@
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,14 +193,60 @@
}
/**
+ * 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.
+ */
+ @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
*/
- @RequiresPermission(android.Manifest.permission.DUMP)
+ @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
public void cancelBugreport() {
try {
mBinder.cancelBugreport(-1 /* callingUid */, mContext.getOpPackageName());
@@ -209,23 +259,26 @@
* 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();
}
@@ -236,8 +289,8 @@
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;
@@ -247,9 +300,7 @@
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);
}
@@ -259,9 +310,7 @@
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);
}
@@ -271,9 +320,7 @@
public void onFinished() throws RemoteException {
final long identity = Binder.clearCallingIdentity();
try {
- mExecutor.execute(() -> {
- mCallback.onFinished();
- });
+ mExecutor.execute(() -> mCallback.onFinished());
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -288,20 +335,19 @@
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/Build.java b/core/java/android/os/Build.java
index 0d8769e..1076118 100755
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -317,6 +317,7 @@
* @see #SDK_INT
* @hide
*/
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
@TestApi
public static final int FIRST_SDK_INT = SystemProperties
.getInt("ro.product.first_api_level", 0);
diff --git a/core/java/android/os/storage/OWNERS b/core/java/android/os/storage/OWNERS
index 8af7de5..7e17a08 100644
--- a/core/java/android/os/storage/OWNERS
+++ b/core/java/android/os/storage/OWNERS
@@ -5,3 +5,6 @@
corinac@google.com
zezeozue@google.com
maco@google.com
+sahanas@google.com
+abkaur@google.com
+chiangi@google.com
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 4086161..0f7365d 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -999,6 +999,20 @@
"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 f1539dc..5682fd3 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 f1539dc..5682fd3 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/se/omapi/SEService.java b/core/java/android/se/omapi/SEService.java
index a5c5c61..333af91 100644
--- a/core/java/android/se/omapi/SEService.java
+++ b/core/java/android/se/omapi/SEService.java
@@ -22,7 +22,10 @@
package android.se.omapi;
+import android.annotation.BroadcastBehavior;
import android.annotation.NonNull;
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -71,6 +74,28 @@
}
/**
+ * Broadcast Action: Intent to notify if the secure element state is changed.
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ @BroadcastBehavior(registeredOnly = true, protectedBroadcast = true)
+ public static final String ACTION_SECURE_ELEMENT_STATE_CHANGED =
+ "android.se.omapi.action.SECURE_ELEMENT_STATE_CHANGED";
+
+ /**
+ * Mandatory extra containing the reader name of the state changed secure element.
+ *
+ * @see Reader#getName()
+ */
+ public static final String EXTRA_READER_NAME = "android.se.omapi.extra.READER_NAME";
+
+ /**
+ * Mandatory extra containing the connected state of the state changed secure element.
+ *
+ * True if the secure element is connected correctly, false otherwise.
+ */
+ public static final String EXTRA_READER_STATE = "android.se.omapi.extra.READER_STATE";
+
+ /**
* Listener object that allows the notification of the caller if this
* SEService could be bound to the backend.
*/
diff --git a/core/java/android/service/textservice/OWNERS b/core/java/android/service/textservice/OWNERS
index 10b8b76..0471e29 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/uwb/AngleMeasurement.java b/core/java/android/uwb/AngleMeasurement.java
index 93b5fd4..9df213b 100644
--- a/core/java/android/uwb/AngleMeasurement.java
+++ b/core/java/android/uwb/AngleMeasurement.java
@@ -18,6 +18,7 @@
import android.annotation.FloatRange;
import android.annotation.NonNull;
+import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
@@ -31,6 +32,7 @@
*
* @hide
*/
+@SystemApi
public final class AngleMeasurement implements Parcelable {
private final double mRadians;
private final double mErrorRadians;
diff --git a/core/java/android/uwb/AngleOfArrivalMeasurement.java b/core/java/android/uwb/AngleOfArrivalMeasurement.java
index 20a1c7a..3d8626b 100644
--- a/core/java/android/uwb/AngleOfArrivalMeasurement.java
+++ b/core/java/android/uwb/AngleOfArrivalMeasurement.java
@@ -18,6 +18,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
@@ -28,6 +29,7 @@
*
* @hide
*/
+@SystemApi
public final class AngleOfArrivalMeasurement implements Parcelable {
private final AngleMeasurement mAzimuthAngleMeasurement;
private final AngleMeasurement mAltitudeAngleMeasurement;
@@ -53,7 +55,7 @@
* @return the azimuth {@link AngleMeasurement}
*/
@NonNull
- public AngleMeasurement getAzimuthAngleMeasurement() {
+ public AngleMeasurement getAzimuth() {
return mAzimuthAngleMeasurement;
}
@@ -70,7 +72,7 @@
* @return altitude {@link AngleMeasurement} or null when this is not available
*/
@Nullable
- public AngleMeasurement getAltitudeAngleMeasurement() {
+ public AngleMeasurement getAltitude() {
return mAltitudeAngleMeasurement;
}
@@ -85,8 +87,8 @@
if (obj instanceof AngleOfArrivalMeasurement) {
AngleOfArrivalMeasurement other = (AngleOfArrivalMeasurement) obj;
- return mAzimuthAngleMeasurement.equals(other.getAzimuthAngleMeasurement())
- && mAltitudeAngleMeasurement.equals(other.getAltitudeAngleMeasurement());
+ return mAzimuthAngleMeasurement.equals(other.getAzimuth())
+ && mAltitudeAngleMeasurement.equals(other.getAltitude());
}
return false;
}
@@ -116,11 +118,9 @@
public AngleOfArrivalMeasurement createFromParcel(Parcel in) {
Builder builder = new Builder();
- builder.setAzimuthAngleMeasurement(
- in.readParcelable(AngleMeasurement.class.getClassLoader()));
+ builder.setAzimuth(in.readParcelable(AngleMeasurement.class.getClassLoader()));
- builder.setAltitudeAngleMeasurement(
- in.readParcelable(AngleMeasurement.class.getClassLoader()));
+ builder.setAltitude(in.readParcelable(AngleMeasurement.class.getClassLoader()));
return builder.build();
}
@@ -144,7 +144,7 @@
* @param azimuthAngle azimuth angle
*/
@NonNull
- public Builder setAzimuthAngleMeasurement(@NonNull AngleMeasurement azimuthAngle) {
+ public Builder setAzimuth(@NonNull AngleMeasurement azimuthAngle) {
mAzimuthAngleMeasurement = azimuthAngle;
return this;
}
@@ -155,7 +155,7 @@
* @param altitudeAngle altitude angle
*/
@NonNull
- public Builder setAltitudeAngleMeasurement(@NonNull AngleMeasurement altitudeAngle) {
+ public Builder setAltitude(@NonNull AngleMeasurement altitudeAngle) {
mAltitudeAngleMeasurement = altitudeAngle;
return this;
}
diff --git a/core/java/android/uwb/DistanceMeasurement.java b/core/java/android/uwb/DistanceMeasurement.java
index 10c2172..2a9bbdf 100644
--- a/core/java/android/uwb/DistanceMeasurement.java
+++ b/core/java/android/uwb/DistanceMeasurement.java
@@ -19,6 +19,7 @@
import android.annotation.FloatRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
@@ -32,6 +33,7 @@
*
* @hide
*/
+@SystemApi
public final class DistanceMeasurement implements Parcelable {
private final double mMeters;
private final double mErrorMeters;
diff --git a/core/java/android/uwb/RangingMeasurement.java b/core/java/android/uwb/RangingMeasurement.java
index 50e5f0d..249e2b7 100644
--- a/core/java/android/uwb/RangingMeasurement.java
+++ b/core/java/android/uwb/RangingMeasurement.java
@@ -20,6 +20,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
+import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.SystemClock;
@@ -33,6 +34,7 @@
*
* @hide
*/
+@SystemApi
public final class RangingMeasurement implements Parcelable {
private final UwbAddress mRemoteDeviceAddress;
private final @Status int mStatus;
diff --git a/core/java/android/uwb/RangingReport.java b/core/java/android/uwb/RangingReport.java
index 5b5f084..7a2df86 100644
--- a/core/java/android/uwb/RangingReport.java
+++ b/core/java/android/uwb/RangingReport.java
@@ -18,6 +18,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
@@ -30,6 +31,7 @@
*
* @hide
*/
+@SystemApi
public final class RangingReport implements Parcelable {
private final List<RangingMeasurement> mRangingMeasurements;
diff --git a/core/java/android/uwb/RangingSession.java b/core/java/android/uwb/RangingSession.java
index 0f87af4..bfa8bf2 100644
--- a/core/java/android/uwb/RangingSession.java
+++ b/core/java/android/uwb/RangingSession.java
@@ -18,6 +18,7 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.SystemApi;
import android.os.Binder;
import android.os.PersistableBundle;
import android.os.RemoteException;
@@ -42,6 +43,7 @@
*
* @hide
*/
+@SystemApi
public final class RangingSession implements AutoCloseable {
private static final String TAG = "Uwb.RangingSession";
private final SessionHandle mSessionHandle;
diff --git a/core/java/android/uwb/UwbAddress.java b/core/java/android/uwb/UwbAddress.java
index b9523a3..22883be 100644
--- a/core/java/android/uwb/UwbAddress.java
+++ b/core/java/android/uwb/UwbAddress.java
@@ -18,6 +18,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
@@ -28,6 +29,7 @@
*
* @hide
*/
+@SystemApi
public final class UwbAddress implements Parcelable {
public static final int SHORT_ADDRESS_BYTE_LENGTH = 2;
public static final int EXTENDED_ADDRESS_BYTE_LENGTH = 8;
diff --git a/core/java/android/uwb/UwbManager.java b/core/java/android/uwb/UwbManager.java
index 15ee5b5..8adfe06 100644
--- a/core/java/android/uwb/UwbManager.java
+++ b/core/java/android/uwb/UwbManager.java
@@ -20,6 +20,7 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.SuppressLint;
+import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.content.Context;
import android.os.IBinder;
@@ -44,6 +45,7 @@
*
* @hide
*/
+@SystemApi
@SystemService(Context.UWB_SERVICE)
public final class UwbManager {
private IUwbAdapter mUwbAdapter;
diff --git a/core/java/android/view/accessibility/OWNERS b/core/java/android/view/accessibility/OWNERS
index 93b5a2e..b1d3967 100644
--- a/core/java/android/view/accessibility/OWNERS
+++ b/core/java/android/view/accessibility/OWNERS
@@ -9,3 +9,4 @@
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 582be8d..0471e29 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 b9ff26b..6281ee9 100644
--- a/core/java/android/widget/AbsSeekBar.java
+++ b/core/java/android/widget/AbsSeekBar.java
@@ -39,6 +39,7 @@
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 @@
/**
* 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/app/OWNERS b/core/java/com/android/internal/app/OWNERS
index c5a956a..99692d0 100644
--- a/core/java/com/android/internal/app/OWNERS
+++ b/core/java/com/android/internal/app/OWNERS
@@ -3,3 +3,5 @@
per-file *Chooser* = file:/packages/SystemUI/OWNERS
per-file SimpleIconFactory.java = file:/packages/SystemUI/OWNERS
per-file NetInitiatedActivity.java = file:/location/java/android/location/OWNERS
+per-file IVoice* = file:/core/java/android/service/voice/OWNERS
+per-file *Hotword* = file:/core/java/android/service/voice/OWNERS
diff --git a/core/java/com/android/internal/compat/IPlatformCompat.aidl b/core/java/com/android/internal/compat/IPlatformCompat.aidl
index cc266d6..a5eb5f6 100644
--- a/core/java/com/android/internal/compat/IPlatformCompat.aidl
+++ b/core/java/com/android/internal/compat/IPlatformCompat.aidl
@@ -22,17 +22,16 @@
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 @@
* <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 @@
* <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 @@
* <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 @@
* <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 @@
* <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 @@
* <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.
+ * <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/graphics/fonts/OWNERS b/core/java/com/android/internal/graphics/fonts/OWNERS
new file mode 100644
index 0000000..18486af
--- /dev/null
+++ b/core/java/com/android/internal/graphics/fonts/OWNERS
@@ -0,0 +1 @@
+include /graphics/java/android/graphics/fonts/OWNERS
diff --git a/core/java/com/android/internal/os/WrapperInit.java b/core/java/com/android/internal/os/WrapperInit.java
index 790d7f7..6860759e 100644
--- a/core/java/com/android/internal/os/WrapperInit.java
+++ b/core/java/com/android/internal/os/WrapperInit.java
@@ -69,15 +69,16 @@
// 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 0000000..0471e29
--- /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 0fb2911..a9db91b 100644
--- a/core/jni/android_os_HwBlob.cpp
+++ b/core/jni/android_os_HwBlob.cpp
@@ -257,7 +257,17 @@
// 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 dc98aaf..b2e562c 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -1559,7 +1559,6 @@
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 @@
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 03ef35b..3183ed3 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -309,9 +309,14 @@
<protected-broadcast android:name="android.net.nsd.STATE_CHANGED" />
+ <!-- For OMAPI -->
+ <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" />
@@ -1622,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 222471a..09f16a8 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
@@ -76,6 +76,12 @@
private static final long DUMPSTATE_STARTUP_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(10);
private static final long UIAUTOMATOR_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(10);
+
+ // A small timeout used when waiting for the result of a BugreportCallback to be received.
+ // This value must be at least 1000ms since there is an intentional delay in
+ // BugreportManagerServiceImpl in the error case.
+ private static final long CALLBACK_RESULT_TIMEOUT_MS = 1500;
+
// Sent by Shell when its bugreport finishes (contains final bugreport/screenshot file name
// associated with the bugreport).
private static final String INTENT_BUGREPORT_FINISHED =
@@ -185,7 +191,7 @@
ParcelFileDescriptor bugreportFd2 = parcelFd(bugreportFile2);
ParcelFileDescriptor screenshotFd2 = parcelFd(screenshotFile2);
mBrm.startBugreport(bugreportFd2, screenshotFd2, wifi(), mExecutor, callback2);
- Thread.sleep(500 /* .5s */);
+ Thread.sleep(CALLBACK_RESULT_TIMEOUT_MS);
// Verify #2 encounters an error.
assertThat(callback2.getErrorCode()).isEqualTo(
@@ -194,7 +200,7 @@
// Cancel #1 so we can move on to the next test.
mBrm.cancelBugreport();
- Thread.sleep(500 /* .5s */);
+ waitTillDoneOrTimeout(callback);
assertThat(callback.isDone()).isTrue();
assertFdsAreClosed(mBugreportFd, mScreenshotFd);
}
@@ -220,7 +226,7 @@
// Try again, with DUMP permission.
getPermissions();
mBrm.cancelBugreport();
- Thread.sleep(500 /* .5s */);
+ waitTillDoneOrTimeout(callback);
assertThat(callback.isDone()).isTrue();
assertFdsAreClosed(mBugreportFd, mScreenshotFd);
}
diff --git a/core/tests/coretests/src/android/app/OWNERS b/core/tests/coretests/src/android/app/OWNERS
index bd7da0c..b3f3993 100644
--- a/core/tests/coretests/src/android/app/OWNERS
+++ b/core/tests/coretests/src/android/app/OWNERS
@@ -1 +1,6 @@
per-file Window*.java = file:/services/core/java/com/android/server/wm/OWNERS
+
+# 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
diff --git a/core/tests/coretests/src/android/app/people/OWNERS b/core/tests/coretests/src/android/app/people/OWNERS
new file mode 100644
index 0000000..6ec8e6a
--- /dev/null
+++ b/core/tests/coretests/src/android/app/people/OWNERS
@@ -0,0 +1 @@
+file:/core/java/android/app/people/OWNERS
\ No newline at end of file
diff --git a/core/tests/coretests/src/android/content/OWNERS b/core/tests/coretests/src/android/content/OWNERS
index 696aa11..912db1e 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 0000000..7b76706
--- /dev/null
+++ b/core/tests/coretests/src/android/content/pm/OWNERS
@@ -0,0 +1,3 @@
+per-file AppSearchPersonTest.java = file:/core/java/android/content/pm/SHORTCUT_OWNERS
+per-file SigningDetailsTest.java = mpgroover@google.com
+per-file SigningDetailsTest.java = cbrubaker@google.com
diff --git a/core/tests/coretests/src/android/text/format/DateIntervalFormatTest.java b/core/tests/coretests/src/android/text/format/DateIntervalFormatTest.java
index 0f17d27..6be9306 100644
--- a/core/tests/coretests/src/android/text/format/DateIntervalFormatTest.java
+++ b/core/tests/coretests/src/android/text/format/DateIntervalFormatTest.java
@@ -254,7 +254,7 @@
assertEquals("19–22 de ene. de 2009",
formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * DAY,
FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
- assertEquals("lun., 19 de ene. – jue., 22 de ene. de 2009",
+ assertEquals("lun, 19 de ene. – jue, 22 de ene. de 2009",
formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * DAY,
FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_ALL));
assertEquals("lunes, 19 de enero–jueves, 22 de enero de 2009",
@@ -265,7 +265,7 @@
assertEquals("19 de ene. – 22 de abr. 2009",
formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * MONTH,
FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
- assertEquals("lun., 19 de ene. – mié., 22 de abr. de 2009",
+ assertEquals("lun, 19 de ene. – mié, 22 de abr. de 2009",
formatDateRange(es_US, tz, fixedTime, fixedTime + 3 * MONTH,
FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_ALL));
assertEquals("enero–abril de 2009",
@@ -286,9 +286,9 @@
assertEquals("19–22 de enero de 2009",
formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * DAY, 0));
- assertEquals("19–22 ene. 2009", formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * DAY,
+ assertEquals("19–22 ene 2009", formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * DAY,
FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
- assertEquals("lun., 19 ene. – jue., 22 ene. 2009",
+ assertEquals("lun, 19 ene – jue, 22 ene 2009",
formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * DAY,
FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_ALL));
assertEquals("lunes, 19 de enero–jueves, 22 de enero de 2009",
@@ -296,19 +296,19 @@
assertEquals("19 de enero–22 de abril de 2009",
formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * MONTH, 0));
- assertEquals("19 ene. – 22 abr. 2009",
+ assertEquals("19 ene – 22 abr 2009",
formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * MONTH,
FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
- assertEquals("lun., 19 ene. – mié., 22 abr. 2009",
+ assertEquals("lun, 19 ene – mié, 22 abr 2009",
formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * MONTH,
FORMAT_SHOW_WEEKDAY | FORMAT_ABBREV_ALL));
assertEquals("enero–abril de 2009",
formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * MONTH, FORMAT_NO_MONTH_DAY));
- assertEquals("19 ene. 2009 – 9 feb. 2012",
+ assertEquals("19 ene 2009 – 9 feb 2012",
formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * YEAR,
FORMAT_SHOW_DATE | FORMAT_ABBREV_ALL));
- assertEquals("ene. 2009 – feb. 2012",
+ assertEquals("ene 2009 – feb 2012",
formatDateRange(es_ES, tz, fixedTime, fixedTime + 3 * YEAR,
FORMAT_NO_MONTH_DAY | FORMAT_ABBREV_ALL));
assertEquals("19 de enero de 2009–9 de febrero de 2012",
diff --git a/core/tests/coretests/src/android/text/format/FormatterTest.java b/core/tests/coretests/src/android/text/format/FormatterTest.java
index 068d047..5612833 100644
--- a/core/tests/coretests/src/android/text/format/FormatterTest.java
+++ b/core/tests/coretests/src/android/text/format/FormatterTest.java
@@ -212,7 +212,7 @@
// Make sure it works on different locales.
setLocale(new Locale("ru", "RU"));
- assertEquals("1 мин.", Formatter.formatShortElapsedTimeRoundingUpToMinutes(
+ assertEquals("1 мин", Formatter.formatShortElapsedTimeRoundingUpToMinutes(
mContext, 1 * SECOND));
}
diff --git a/core/tests/coretests/src/android/text/format/RelativeDateTimeFormatterTest.java b/core/tests/coretests/src/android/text/format/RelativeDateTimeFormatterTest.java
index 4b3b573..b342516 100644
--- a/core/tests/coretests/src/android/text/format/RelativeDateTimeFormatterTest.java
+++ b/core/tests/coretests/src/android/text/format/RelativeDateTimeFormatterTest.java
@@ -755,8 +755,8 @@
final Locale locale = new Locale("fr");
android.icu.text.RelativeDateTimeFormatter icuFormatter =
android.icu.text.RelativeDateTimeFormatter.getInstance(locale);
- assertEquals("D Ã T", icuFormatter.combineDateAndTime("D", "T"));
+ assertEquals("D, T", icuFormatter.combineDateAndTime("D", "T"));
// Ensure single quote ' and curly braces {} are not interpreted in input values.
- assertEquals("D'x' Ã T{0}", icuFormatter.combineDateAndTime("D'x'", "T{0}"));
+ assertEquals("D'x', T{0}", icuFormatter.combineDateAndTime("D'x'", "T{0}"));
}
}
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 0000000..0471e29
--- /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 5371a0f..ccd873d 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.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 @@
@Presubmit
public class AbsSeekBarTest {
+ public static final int PADDING = 10;
private Context mContext;
private AbsSeekBar mBar;
@@ -59,34 +59,42 @@
@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 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 @@
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 12a2b08..f86ac9c 100644
--- a/core/tests/overlaytests/device/Android.bp
+++ b/core/tests/overlaytests/device/Android.bp
@@ -16,7 +16,11 @@
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 4881636..a69911f 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 6507839..ebbdda5 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 390bb76..76c01a7 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 @@
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);
- }
- return str.toString();
+ 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 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 0000000..0b4f5e2
--- /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 d28c47d..420f755 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.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 @@
@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 6566ad3..a86255e 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.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 @@
}
@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 48cfeab..51c4118 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.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 @@
@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 da3aa00..847b491 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 215b66da3..7d5f82a 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/core/tests/uwbtests/src/android/uwb/AngleOfArrivalMeasurementTest.java b/core/tests/uwbtests/src/android/uwb/AngleOfArrivalMeasurementTest.java
index e0884e3..9394dec 100644
--- a/core/tests/uwbtests/src/android/uwb/AngleOfArrivalMeasurementTest.java
+++ b/core/tests/uwbtests/src/android/uwb/AngleOfArrivalMeasurementTest.java
@@ -42,14 +42,14 @@
AngleOfArrivalMeasurement.Builder builder = new AngleOfArrivalMeasurement.Builder();
tryBuild(builder, false);
- builder.setAltitudeAngleMeasurement(altitude);
+ builder.setAltitude(altitude);
tryBuild(builder, false);
- builder.setAzimuthAngleMeasurement(azimuth);
+ builder.setAzimuth(azimuth);
AngleOfArrivalMeasurement measurement = tryBuild(builder, true);
- assertEquals(azimuth, measurement.getAzimuthAngleMeasurement());
- assertEquals(altitude, measurement.getAltitudeAngleMeasurement());
+ assertEquals(azimuth, measurement.getAzimuth());
+ assertEquals(altitude, measurement.getAltitude());
}
private AngleMeasurement getAngleMeasurement(double radian, double error, double confidence) {
diff --git a/core/tests/uwbtests/src/android/uwb/UwbTestUtils.java b/core/tests/uwbtests/src/android/uwb/UwbTestUtils.java
index b4b2e30..8e7f7c56 100644
--- a/core/tests/uwbtests/src/android/uwb/UwbTestUtils.java
+++ b/core/tests/uwbtests/src/android/uwb/UwbTestUtils.java
@@ -42,8 +42,8 @@
public static AngleOfArrivalMeasurement getAngleOfArrivalMeasurement() {
return new AngleOfArrivalMeasurement.Builder()
- .setAltitudeAngleMeasurement(getAngleMeasurement())
- .setAzimuthAngleMeasurement(getAngleMeasurement())
+ .setAltitude(getAngleMeasurement())
+ .setAzimuth(getAngleMeasurement())
.build();
}
diff --git a/data/etc/OWNERS b/data/etc/OWNERS
index 9867d81..65d3a01 100644
--- a/data/etc/OWNERS
+++ b/data/etc/OWNERS
@@ -1,3 +1,4 @@
+alanstokes@google.com
cbrubaker@google.com
hackbod@android.com
hackbod@google.com
@@ -12,4 +13,4 @@
toddke@google.com
yamasani@google.com
-per-file preinstalled-packages* = file:/MULTIUSER_OWNERS
\ No newline at end of file
+per-file preinstalled-packages* = file:/MULTIUSER_OWNERS
diff --git a/keystore/java/android/security/AuthTokenUtils.java b/keystore/java/android/security/AuthTokenUtils.java
new file mode 100644
index 0000000..e637600
--- /dev/null
+++ b/keystore/java/android/security/AuthTokenUtils.java
@@ -0,0 +1,75 @@
+/*
+ * 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.security;
+
+import android.annotation.NonNull;
+import android.hardware.security.keymint.HardwareAuthToken;
+import android.hardware.security.secureclock.Timestamp;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * @hide This Utils class provides method(s) for AuthToken conversion.
+ */
+public class AuthTokenUtils {
+
+ private AuthTokenUtils(){
+ }
+
+ /**
+ * Build a HardwareAuthToken from a byte array
+ * @param array byte array representing an auth token
+ * @return HardwareAuthToken representation of an auth token
+ */
+ public static @NonNull HardwareAuthToken toHardwareAuthToken(@NonNull byte[] array) {
+ final HardwareAuthToken hardwareAuthToken = new HardwareAuthToken();
+
+ // First byte is version, which does not exist in HardwareAuthToken anymore
+ // Next 8 bytes is the challenge.
+ hardwareAuthToken.challenge =
+ ByteBuffer.wrap(array, 1, 8).order(ByteOrder.nativeOrder()).getLong();
+
+ // Next 8 bytes is the userId
+ hardwareAuthToken.userId =
+ ByteBuffer.wrap(array, 9, 8).order(ByteOrder.nativeOrder()).getLong();
+
+ // Next 8 bytes is the authenticatorId.
+ hardwareAuthToken.authenticatorId =
+ ByteBuffer.wrap(array, 17, 8).order(ByteOrder.nativeOrder()).getLong();
+
+ // while the other fields are in machine byte order, authenticatorType and timestamp
+ // are in network byte order.
+ // Next 4 bytes is the authenticatorType.
+ hardwareAuthToken.authenticatorType =
+ ByteBuffer.wrap(array, 25, 4).order(ByteOrder.BIG_ENDIAN).getInt();
+ // Next 8 bytes is the timestamp.
+ final Timestamp timestamp = new Timestamp();
+ timestamp.milliSeconds =
+ ByteBuffer.wrap(array, 29, 8).order(ByteOrder.BIG_ENDIAN).getLong();
+ hardwareAuthToken.timestamp = timestamp;
+
+ // Last 32 bytes is the mac, 37:69
+ hardwareAuthToken.mac = new byte[32];
+ System.arraycopy(array, 37 /* srcPos */,
+ hardwareAuthToken.mac,
+ 0 /* destPos */,
+ 32 /* length */);
+
+ return hardwareAuthToken;
+ }
+}
diff --git a/keystore/java/android/security/Authorization.java b/keystore/java/android/security/Authorization.java
new file mode 100644
index 0000000..fcc518c
--- /dev/null
+++ b/keystore/java/android/security/Authorization.java
@@ -0,0 +1,107 @@
+/*
+ * 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.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;
+
+/**
+ * @hide This is the client side for IKeystoreAuthorization AIDL.
+ * It shall only be used by biometric authentication providers and Gatekeeper.
+ */
+public class Authorization {
+ private static final String TAG = "KeystoreAuthorization";
+ private static IKeystoreAuthorization sIKeystoreAuthorization;
+
+ public static final int SYSTEM_ERROR = ResponseCode.SYSTEM_ERROR;
+
+ public Authorization() {
+ sIKeystoreAuthorization = null;
+ }
+
+ private static synchronized IKeystoreAuthorization getService() {
+ if (sIKeystoreAuthorization == null) {
+ sIKeystoreAuthorization = IKeystoreAuthorization.Stub.asInterface(
+ ServiceManager.checkService("android.security.authorization"));
+ }
+ return sIKeystoreAuthorization;
+ }
+
+ /**
+ * Adds an auth token to keystore2.
+ *
+ * @param authToken created by Android authenticators.
+ * @return 0 if successful or {@code ResponseCode.SYSTEM_ERROR}.
+ */
+ public int addAuthToken(@NonNull HardwareAuthToken authToken) {
+ if (!android.security.keystore2.AndroidKeyStoreProvider.isInstalled()) return 0;
+ try {
+ getService().addAuthToken(authToken);
+ return 0;
+ } catch (RemoteException e) {
+ Log.w(TAG, "Can not connect to keystore", e);
+ return SYSTEM_ERROR;
+ } catch (ServiceSpecificException e) {
+ return e.errorCode;
+ }
+ }
+
+ /**
+ * Add an auth token to Keystore 2.0 in the legacy serialized auth token format.
+ * @param authToken
+ * @return 0 if successful or a {@code ResponseCode}.
+ */
+ public int addAuthToken(@NonNull byte[] authToken) {
+ 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/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index c70c986..4a67135 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -996,6 +996,7 @@
*/
public int addAuthToken(byte[] authToken) {
try {
+ new Authorization().addAuthToken(authToken);
return mBinder.addAuthToken(authToken);
} catch (RemoteException e) {
Log.w(TAG, "Cannot connect to keystore", e);
diff --git a/libs/androidfw/LocaleDataTables.cpp b/libs/androidfw/LocaleDataTables.cpp
index 6c6c5c9..8a10599 100644
--- a/libs/androidfw/LocaleDataTables.cpp
+++ b/libs/androidfw/LocaleDataTables.cpp
@@ -64,42 +64,43 @@
/* 60 */ {'N', 'k', 'o', 'o'},
/* 61 */ {'N', 's', 'h', 'u'},
/* 62 */ {'O', 'g', 'a', 'm'},
- /* 63 */ {'O', 'r', 'k', 'h'},
- /* 64 */ {'O', 'r', 'y', 'a'},
- /* 65 */ {'O', 's', 'g', 'e'},
- /* 66 */ {'P', 'a', 'u', 'c'},
- /* 67 */ {'P', 'h', 'l', 'i'},
- /* 68 */ {'P', 'h', 'n', 'x'},
- /* 69 */ {'P', 'l', 'r', 'd'},
- /* 70 */ {'P', 'r', 't', 'i'},
- /* 71 */ {'R', 'u', 'n', 'r'},
- /* 72 */ {'S', 'a', 'm', 'r'},
- /* 73 */ {'S', 'a', 'r', 'b'},
- /* 74 */ {'S', 'a', 'u', 'r'},
- /* 75 */ {'S', 'g', 'n', 'w'},
- /* 76 */ {'S', 'i', 'n', 'h'},
- /* 77 */ {'S', 'o', 'g', 'd'},
- /* 78 */ {'S', 'o', 'r', 'a'},
- /* 79 */ {'S', 'o', 'y', 'o'},
- /* 80 */ {'S', 'y', 'r', 'c'},
- /* 81 */ {'T', 'a', 'l', 'e'},
- /* 82 */ {'T', 'a', 'l', 'u'},
- /* 83 */ {'T', 'a', 'm', 'l'},
- /* 84 */ {'T', 'a', 'n', 'g'},
- /* 85 */ {'T', 'a', 'v', 't'},
- /* 86 */ {'T', 'e', 'l', 'u'},
- /* 87 */ {'T', 'f', 'n', 'g'},
- /* 88 */ {'T', 'h', 'a', 'a'},
- /* 89 */ {'T', 'h', 'a', 'i'},
- /* 90 */ {'T', 'i', 'b', 't'},
- /* 91 */ {'U', 'g', 'a', 'r'},
- /* 92 */ {'V', 'a', 'i', 'i'},
- /* 93 */ {'W', 'c', 'h', 'o'},
- /* 94 */ {'X', 'p', 'e', 'o'},
- /* 95 */ {'X', 's', 'u', 'x'},
- /* 96 */ {'Y', 'i', 'i', 'i'},
- /* 97 */ {'~', '~', '~', 'A'},
- /* 98 */ {'~', '~', '~', 'B'},
+ /* 63 */ {'O', 'l', 'c', 'k'},
+ /* 64 */ {'O', 'r', 'k', 'h'},
+ /* 65 */ {'O', 'r', 'y', 'a'},
+ /* 66 */ {'O', 's', 'g', 'e'},
+ /* 67 */ {'P', 'a', 'u', 'c'},
+ /* 68 */ {'P', 'h', 'l', 'i'},
+ /* 69 */ {'P', 'h', 'n', 'x'},
+ /* 70 */ {'P', 'l', 'r', 'd'},
+ /* 71 */ {'P', 'r', 't', 'i'},
+ /* 72 */ {'R', 'u', 'n', 'r'},
+ /* 73 */ {'S', 'a', 'm', 'r'},
+ /* 74 */ {'S', 'a', 'r', 'b'},
+ /* 75 */ {'S', 'a', 'u', 'r'},
+ /* 76 */ {'S', 'g', 'n', 'w'},
+ /* 77 */ {'S', 'i', 'n', 'h'},
+ /* 78 */ {'S', 'o', 'g', 'd'},
+ /* 79 */ {'S', 'o', 'r', 'a'},
+ /* 80 */ {'S', 'o', 'y', 'o'},
+ /* 81 */ {'S', 'y', 'r', 'c'},
+ /* 82 */ {'T', 'a', 'l', 'e'},
+ /* 83 */ {'T', 'a', 'l', 'u'},
+ /* 84 */ {'T', 'a', 'm', 'l'},
+ /* 85 */ {'T', 'a', 'n', 'g'},
+ /* 86 */ {'T', 'a', 'v', 't'},
+ /* 87 */ {'T', 'e', 'l', 'u'},
+ /* 88 */ {'T', 'f', 'n', 'g'},
+ /* 89 */ {'T', 'h', 'a', 'a'},
+ /* 90 */ {'T', 'h', 'a', 'i'},
+ /* 91 */ {'T', 'i', 'b', 't'},
+ /* 92 */ {'U', 'g', 'a', 'r'},
+ /* 93 */ {'V', 'a', 'i', 'i'},
+ /* 94 */ {'W', 'c', 'h', 'o'},
+ /* 95 */ {'X', 'p', 'e', 'o'},
+ /* 96 */ {'X', 's', 'u', 'x'},
+ /* 97 */ {'Y', 'i', 'i', 'i'},
+ /* 98 */ {'~', '~', '~', 'A'},
+ /* 99 */ {'~', '~', '~', 'B'},
};
@@ -120,7 +121,7 @@
{0x80600000u, 46u}, // ada -> Latn
{0x90600000u, 46u}, // ade -> Latn
{0xA4600000u, 46u}, // adj -> Latn
- {0xBC600000u, 90u}, // adp -> Tibt
+ {0xBC600000u, 91u}, // adp -> Tibt
{0xE0600000u, 17u}, // ady -> Cyrl
{0xE4600000u, 46u}, // adz -> Latn
{0x61650000u, 4u}, // ae -> Avst
@@ -138,7 +139,7 @@
{0xB8E00000u, 0u}, // aho -> Ahom
{0x99200000u, 46u}, // ajg -> Latn
{0x616B0000u, 46u}, // ak -> Latn
- {0xA9400000u, 95u}, // akk -> Xsux
+ {0xA9400000u, 96u}, // akk -> Xsux
{0x81600000u, 46u}, // ala -> Latn
{0xA1600000u, 46u}, // ali -> Latn
{0xB5600000u, 46u}, // aln -> Latn
@@ -163,7 +164,7 @@
{0xC9E00000u, 46u}, // aps -> Latn
{0xE5E00000u, 46u}, // apz -> Latn
{0x61720000u, 1u}, // ar -> Arab
- {0x61725842u, 98u}, // ar-XB -> ~~~B
+ {0x61725842u, 99u}, // ar-XB -> ~~~B
{0x8A200000u, 2u}, // arc -> Armi
{0x9E200000u, 46u}, // arh -> Latn
{0xB6200000u, 46u}, // arn -> Latn
@@ -174,7 +175,7 @@
{0xE6200000u, 1u}, // arz -> Arab
{0x61730000u, 7u}, // as -> Beng
{0x82400000u, 46u}, // asa -> Latn
- {0x92400000u, 75u}, // ase -> Sgnw
+ {0x92400000u, 76u}, // ase -> Sgnw
{0x9A400000u, 46u}, // asg -> Latn
{0xBA400000u, 46u}, // aso -> Latn
{0xCE400000u, 46u}, // ast -> Latn
@@ -231,7 +232,7 @@
{0xDC810000u, 46u}, // bex -> Latn
{0xE4810000u, 46u}, // bez -> Latn
{0x8CA10000u, 46u}, // bfd -> Latn
- {0xC0A10000u, 83u}, // bfq -> Taml
+ {0xC0A10000u, 84u}, // bfq -> Taml
{0xCCA10000u, 1u}, // bft -> Arab
{0xE0A10000u, 18u}, // bfy -> Deva
{0x62670000u, 17u}, // bg -> Cyrl
@@ -265,7 +266,7 @@
{0xC1410000u, 46u}, // bkq -> Latn
{0xD1410000u, 46u}, // bku -> Latn
{0xD5410000u, 46u}, // bkv -> Latn
- {0xCD610000u, 85u}, // blt -> Tavt
+ {0xCD610000u, 86u}, // blt -> Tavt
{0x626D0000u, 46u}, // bm -> Latn
{0x9D810000u, 46u}, // bmh -> Latn
{0xA9810000u, 46u}, // bmk -> Latn
@@ -275,7 +276,7 @@
{0x99A10000u, 46u}, // bng -> Latn
{0xB1A10000u, 46u}, // bnm -> Latn
{0xBDA10000u, 46u}, // bnp -> Latn
- {0x626F0000u, 90u}, // bo -> Tibt
+ {0x626F0000u, 91u}, // bo -> Tibt
{0xA5C10000u, 46u}, // boj -> Latn
{0xB1C10000u, 46u}, // bom -> Latn
{0xB5C10000u, 46u}, // bon -> Latn
@@ -322,6 +323,7 @@
{0x9F210000u, 46u}, // bzh -> Latn
{0xDB210000u, 46u}, // bzw -> Latn
{0x63610000u, 46u}, // ca -> Latn
+ {0x8C020000u, 46u}, // cad -> Latn
{0xB4020000u, 46u}, // can -> Latn
{0xA4220000u, 46u}, // cbj -> Latn
{0x9C420000u, 46u}, // cch -> Latn
@@ -346,7 +348,7 @@
{0xE1420000u, 46u}, // cky -> Latn
{0x81620000u, 46u}, // cla -> Latn
{0x91820000u, 46u}, // cme -> Latn
- {0x99820000u, 79u}, // cmg -> Soyo
+ {0x99820000u, 80u}, // cmg -> Soyo
{0x636F0000u, 46u}, // co -> Latn
{0xBDC20000u, 15u}, // cop -> Copt
{0xC9E20000u, 46u}, // cps -> Latn
@@ -360,7 +362,7 @@
{0x63730000u, 46u}, // cs -> Latn
{0x86420000u, 46u}, // csb -> Latn
{0xDA420000u, 10u}, // csw -> Cans
- {0x8E620000u, 66u}, // ctd -> Pauc
+ {0x8E620000u, 67u}, // ctd -> Pauc
{0x63750000u, 17u}, // cu -> Cyrl
{0x63760000u, 17u}, // cv -> Cyrl
{0x63790000u, 46u}, // cy -> Latn
@@ -389,7 +391,7 @@
{0x91230000u, 46u}, // dje -> Latn
{0xA5A30000u, 46u}, // dnj -> Latn
{0x85C30000u, 46u}, // dob -> Latn
- {0xA1C30000u, 1u}, // doi -> Arab
+ {0xA1C30000u, 18u}, // doi -> Deva
{0xBDC30000u, 46u}, // dop -> Latn
{0xD9C30000u, 46u}, // dow -> Latn
{0x9E230000u, 56u}, // drh -> Mong
@@ -404,12 +406,12 @@
{0x8A830000u, 46u}, // duc -> Latn
{0x8E830000u, 46u}, // dud -> Latn
{0x9A830000u, 46u}, // dug -> Latn
- {0x64760000u, 88u}, // dv -> Thaa
+ {0x64760000u, 89u}, // dv -> Thaa
{0x82A30000u, 46u}, // dva -> Latn
{0xDAC30000u, 46u}, // dww -> Latn
{0xBB030000u, 46u}, // dyo -> Latn
{0xD3030000u, 46u}, // dyu -> Latn
- {0x647A0000u, 90u}, // dz -> Tibt
+ {0x647A0000u, 91u}, // dz -> Tibt
{0x9B230000u, 46u}, // dzg -> Latn
{0xD0240000u, 46u}, // ebu -> Latn
{0x65650000u, 46u}, // ee -> Latn
@@ -422,7 +424,7 @@
{0x81840000u, 46u}, // ema -> Latn
{0xA1840000u, 46u}, // emi -> Latn
{0x656E0000u, 46u}, // en -> Latn
- {0x656E5841u, 97u}, // en-XA -> ~~~A
+ {0x656E5841u, 98u}, // en-XA -> ~~~A
{0xB5A40000u, 46u}, // enn -> Latn
{0xC1A40000u, 46u}, // enq -> Latn
{0x656F0000u, 46u}, // eo -> Latn
@@ -438,6 +440,7 @@
{0x65750000u, 46u}, // eu -> Latn
{0xBAC40000u, 46u}, // ewo -> Latn
{0xCEE40000u, 46u}, // ext -> Latn
+ {0x83240000u, 46u}, // eza -> Latn
{0x66610000u, 1u}, // fa -> Arab
{0x80050000u, 46u}, // faa -> Latn
{0x84050000u, 46u}, // fab -> Latn
@@ -521,7 +524,7 @@
{0x95C60000u, 20u}, // gof -> Ethi
{0xA1C60000u, 46u}, // goi -> Latn
{0xB1C60000u, 18u}, // gom -> Deva
- {0xB5C60000u, 86u}, // gon -> Telu
+ {0xB5C60000u, 87u}, // gon -> Telu
{0xC5C60000u, 46u}, // gor -> Latn
{0xC9C60000u, 46u}, // gos -> Latn
{0xCDC60000u, 24u}, // got -> Goth
@@ -566,7 +569,7 @@
{0xAD070000u, 46u}, // hil -> Latn
{0x81670000u, 46u}, // hla -> Latn
{0xD1670000u, 32u}, // hlu -> Hluw
- {0x8D870000u, 69u}, // hmd -> Plrd
+ {0x8D870000u, 70u}, // hmd -> Plrd
{0xCD870000u, 46u}, // hmt -> Latn
{0x8DA70000u, 1u}, // hnd -> Arab
{0x91A70000u, 18u}, // hne -> Deva
@@ -601,7 +604,7 @@
{0x69670000u, 46u}, // ig -> Latn
{0x84C80000u, 46u}, // igb -> Latn
{0x90C80000u, 46u}, // ige -> Latn
- {0x69690000u, 96u}, // ii -> Yiii
+ {0x69690000u, 97u}, // ii -> Yiii
{0xA5280000u, 46u}, // ijj -> Latn
{0x696B0000u, 46u}, // ik -> Latn
{0xA9480000u, 46u}, // ikk -> Latn
@@ -626,6 +629,7 @@
{0x6A610000u, 36u}, // ja -> Jpan
{0x84090000u, 46u}, // jab -> Latn
{0xB0090000u, 46u}, // jam -> Latn
+ {0xC4090000u, 46u}, // jar -> Latn
{0xB8290000u, 46u}, // jbo -> Latn
{0xD0290000u, 46u}, // jbu -> Latn
{0xB4890000u, 46u}, // jen -> Latn
@@ -661,7 +665,7 @@
{0x906A0000u, 46u}, // kde -> Latn
{0x9C6A0000u, 1u}, // kdh -> Arab
{0xAC6A0000u, 46u}, // kdl -> Latn
- {0xCC6A0000u, 89u}, // kdt -> Thai
+ {0xCC6A0000u, 90u}, // kdt -> Thai
{0x808A0000u, 46u}, // kea -> Latn
{0xB48A0000u, 46u}, // ken -> Latn
{0xE48A0000u, 46u}, // kez -> Latn
@@ -673,7 +677,7 @@
{0x94CA0000u, 46u}, // kgf -> Latn
{0xBCCA0000u, 46u}, // kgp -> Latn
{0x80EA0000u, 46u}, // kha -> Latn
- {0x84EA0000u, 82u}, // khb -> Talu
+ {0x84EA0000u, 83u}, // khb -> Talu
{0xB4EA0000u, 18u}, // khn -> Deva
{0xC0EA0000u, 46u}, // khq -> Latn
{0xC8EA0000u, 46u}, // khs -> Latn
@@ -766,7 +770,8 @@
{0x82EA0000u, 46u}, // kxa -> Latn
{0x8AEA0000u, 20u}, // kxc -> Ethi
{0x92EA0000u, 46u}, // kxe -> Latn
- {0xB2EA0000u, 89u}, // kxm -> Thai
+ {0xAEEA0000u, 18u}, // kxl -> Deva
+ {0xB2EA0000u, 90u}, // kxm -> Thai
{0xBEEA0000u, 1u}, // kxp -> Arab
{0xDAEA0000u, 46u}, // kxw -> Latn
{0xE6EA0000u, 46u}, // kxz -> Latn
@@ -775,6 +780,7 @@
{0x6B795452u, 46u}, // ky-TR -> Latn
{0x930A0000u, 46u}, // kye -> Latn
{0xDF0A0000u, 46u}, // kyx -> Latn
+ {0x9F2A0000u, 1u}, // kzh -> Arab
{0xA72A0000u, 46u}, // kzj -> Latn
{0xC72A0000u, 46u}, // kzr -> Latn
{0xCF2A0000u, 46u}, // kzt -> Latn
@@ -790,7 +796,7 @@
{0xD02B0000u, 46u}, // lbu -> Latn
{0xD82B0000u, 46u}, // lbw -> Latn
{0xB04B0000u, 46u}, // lcm -> Latn
- {0xBC4B0000u, 89u}, // lcp -> Thai
+ {0xBC4B0000u, 90u}, // lcp -> Thai
{0x846B0000u, 46u}, // ldb -> Latn
{0x8C8B0000u, 46u}, // led -> Latn
{0x908B0000u, 46u}, // lee -> Latn
@@ -814,7 +820,7 @@
{0xCD4B0000u, 46u}, // lkt -> Latn
{0x916B0000u, 46u}, // lle -> Latn
{0xB56B0000u, 46u}, // lln -> Latn
- {0xB58B0000u, 86u}, // lmn -> Telu
+ {0xB58B0000u, 87u}, // lmn -> Telu
{0xB98B0000u, 46u}, // lmo -> Latn
{0xBD8B0000u, 46u}, // lmp -> Latn
{0x6C6E0000u, 46u}, // ln -> Latn
@@ -836,7 +842,7 @@
{0xE28B0000u, 46u}, // luy -> Latn
{0xE68B0000u, 1u}, // luz -> Arab
{0x6C760000u, 46u}, // lv -> Latn
- {0xAECB0000u, 89u}, // lwl -> Thai
+ {0xAECB0000u, 90u}, // lwl -> Thai
{0x9F2B0000u, 28u}, // lzh -> Hans
{0xE72B0000u, 46u}, // lzz -> Latn
{0x8C0C0000u, 46u}, // mad -> Latn
@@ -927,7 +933,6 @@
{0xBA2C0000u, 57u}, // mro -> Mroo
{0x6D730000u, 46u}, // ms -> Latn
{0x6D734343u, 1u}, // ms-CC -> Arab
- {0x6D734944u, 1u}, // ms-ID -> Arab
{0x6D740000u, 46u}, // mt -> Latn
{0x8A6C0000u, 46u}, // mtc -> Latn
{0x966C0000u, 46u}, // mtf -> Latn
@@ -1006,11 +1011,11 @@
{0x9DAD0000u, 46u}, // nnh -> Latn
{0xA9AD0000u, 46u}, // nnk -> Latn
{0xB1AD0000u, 46u}, // nnm -> Latn
- {0xBDAD0000u, 93u}, // nnp -> Wcho
+ {0xBDAD0000u, 94u}, // nnp -> Wcho
{0x6E6F0000u, 46u}, // no -> Latn
{0x8DCD0000u, 44u}, // nod -> Lana
{0x91CD0000u, 18u}, // noe -> Deva
- {0xB5CD0000u, 71u}, // non -> Runr
+ {0xB5CD0000u, 72u}, // non -> Runr
{0xBDCD0000u, 46u}, // nop -> Latn
{0xD1CD0000u, 46u}, // nou -> Latn
{0xBA0D0000u, 60u}, // nqo -> Nkoo
@@ -1044,18 +1049,18 @@
{0xB5AE0000u, 46u}, // onn -> Latn
{0xC9AE0000u, 46u}, // ons -> Latn
{0xB1EE0000u, 46u}, // opm -> Latn
- {0x6F720000u, 64u}, // or -> Orya
+ {0x6F720000u, 65u}, // or -> Orya
{0xBA2E0000u, 46u}, // oro -> Latn
{0xD22E0000u, 1u}, // oru -> Arab
{0x6F730000u, 17u}, // os -> Cyrl
- {0x824E0000u, 65u}, // osa -> Osge
+ {0x824E0000u, 66u}, // osa -> Osge
{0x826E0000u, 1u}, // ota -> Arab
- {0xAA6E0000u, 63u}, // otk -> Orkh
+ {0xAA6E0000u, 64u}, // otk -> Orkh
{0xB32E0000u, 46u}, // ozm -> Latn
{0x70610000u, 27u}, // pa -> Guru
{0x7061504Bu, 1u}, // pa-PK -> Arab
{0x980F0000u, 46u}, // pag -> Latn
- {0xAC0F0000u, 67u}, // pal -> Phli
+ {0xAC0F0000u, 68u}, // pal -> Phli
{0xB00F0000u, 46u}, // pam -> Latn
{0xBC0F0000u, 46u}, // pap -> Latn
{0xD00F0000u, 46u}, // pau -> Latn
@@ -1065,11 +1070,11 @@
{0x886F0000u, 46u}, // pdc -> Latn
{0xCC6F0000u, 46u}, // pdt -> Latn
{0x8C8F0000u, 46u}, // ped -> Latn
- {0xB88F0000u, 94u}, // peo -> Xpeo
+ {0xB88F0000u, 95u}, // peo -> Xpeo
{0xDC8F0000u, 46u}, // pex -> Latn
{0xACAF0000u, 46u}, // pfl -> Latn
{0xACEF0000u, 1u}, // phl -> Arab
- {0xB4EF0000u, 68u}, // phn -> Phnx
+ {0xB4EF0000u, 69u}, // phn -> Phnx
{0xAD0F0000u, 46u}, // pil -> Latn
{0xBD0F0000u, 46u}, // pip -> Latn
{0x814F0000u, 8u}, // pka -> Brah
@@ -1105,7 +1110,7 @@
{0xB4D10000u, 46u}, // rgn -> Latn
{0x98F10000u, 1u}, // rhg -> Arab
{0x81110000u, 46u}, // ria -> Latn
- {0x95110000u, 87u}, // rif -> Tfng
+ {0x95110000u, 88u}, // rif -> Tfng
{0x95114E4Cu, 46u}, // rif-NL -> Latn
{0xC9310000u, 18u}, // rjs -> Deva
{0xCD510000u, 7u}, // rkt -> Beng
@@ -1135,9 +1140,9 @@
{0x9C120000u, 17u}, // sah -> Cyrl
{0xC0120000u, 46u}, // saq -> Latn
{0xC8120000u, 46u}, // sas -> Latn
- {0xCC120000u, 46u}, // sat -> Latn
+ {0xCC120000u, 63u}, // sat -> Olck
{0xD4120000u, 46u}, // sav -> Latn
- {0xE4120000u, 74u}, // saz -> Saur
+ {0xE4120000u, 75u}, // saz -> Saur
{0x80320000u, 46u}, // sba -> Latn
{0x90320000u, 46u}, // sbe -> Latn
{0xBC320000u, 46u}, // sbp -> Latn
@@ -1161,11 +1166,11 @@
{0xD8D20000u, 20u}, // sgw -> Ethi
{0xE4D20000u, 46u}, // sgz -> Latn
{0x73680000u, 46u}, // sh -> Latn
- {0xA0F20000u, 87u}, // shi -> Tfng
+ {0xA0F20000u, 88u}, // shi -> Tfng
{0xA8F20000u, 46u}, // shk -> Latn
{0xB4F20000u, 58u}, // shn -> Mymr
{0xD0F20000u, 1u}, // shu -> Arab
- {0x73690000u, 76u}, // si -> Sinh
+ {0x73690000u, 77u}, // si -> Sinh
{0x8D120000u, 46u}, // sid -> Latn
{0x99120000u, 46u}, // sig -> Latn
{0xAD120000u, 46u}, // sil -> Latn
@@ -1184,7 +1189,7 @@
{0x81920000u, 46u}, // sma -> Latn
{0xA5920000u, 46u}, // smj -> Latn
{0xB5920000u, 46u}, // smn -> Latn
- {0xBD920000u, 72u}, // smp -> Samr
+ {0xBD920000u, 73u}, // smp -> Samr
{0xC1920000u, 46u}, // smq -> Latn
{0xC9920000u, 46u}, // sms -> Latn
{0x736E0000u, 46u}, // sn -> Latn
@@ -1194,10 +1199,10 @@
{0xDDB20000u, 46u}, // snx -> Latn
{0xE1B20000u, 46u}, // sny -> Latn
{0x736F0000u, 46u}, // so -> Latn
- {0x99D20000u, 77u}, // sog -> Sogd
+ {0x99D20000u, 78u}, // sog -> Sogd
{0xA9D20000u, 46u}, // sok -> Latn
{0xC1D20000u, 46u}, // soq -> Latn
- {0xD1D20000u, 89u}, // sou -> Thai
+ {0xD1D20000u, 90u}, // sou -> Thai
{0xE1D20000u, 46u}, // soy -> Latn
{0x8DF20000u, 46u}, // spd -> Latn
{0xADF20000u, 46u}, // spl -> Latn
@@ -1208,7 +1213,7 @@
{0x7372524Fu, 46u}, // sr-RO -> Latn
{0x73725255u, 46u}, // sr-RU -> Latn
{0x73725452u, 46u}, // sr-TR -> Latn
- {0x86320000u, 78u}, // srb -> Sora
+ {0x86320000u, 79u}, // srb -> Sora
{0xB6320000u, 46u}, // srn -> Latn
{0xC6320000u, 46u}, // srr -> Latn
{0xDE320000u, 18u}, // srx -> Deva
@@ -1235,9 +1240,9 @@
{0xB6F20000u, 46u}, // sxn -> Latn
{0xDAF20000u, 46u}, // sxw -> Latn
{0xAF120000u, 7u}, // syl -> Beng
- {0xC7120000u, 80u}, // syr -> Syrc
+ {0xC7120000u, 81u}, // syr -> Syrc
{0xAF320000u, 46u}, // szl -> Latn
- {0x74610000u, 83u}, // ta -> Taml
+ {0x74610000u, 84u}, // ta -> Taml
{0xA4130000u, 18u}, // taj -> Deva
{0xAC130000u, 46u}, // tal -> Latn
{0xB4130000u, 46u}, // tan -> Latn
@@ -1251,11 +1256,11 @@
{0xE4330000u, 46u}, // tbz -> Latn
{0xA0530000u, 46u}, // tci -> Latn
{0xE0530000u, 42u}, // tcy -> Knda
- {0x8C730000u, 81u}, // tdd -> Tale
+ {0x8C730000u, 82u}, // tdd -> Tale
{0x98730000u, 18u}, // tdg -> Deva
{0x9C730000u, 18u}, // tdh -> Deva
{0xD0730000u, 46u}, // tdu -> Latn
- {0x74650000u, 86u}, // te -> Telu
+ {0x74650000u, 87u}, // te -> Telu
{0x8C930000u, 46u}, // ted -> Latn
{0xB0930000u, 46u}, // tem -> Latn
{0xB8930000u, 46u}, // teo -> Latn
@@ -1266,7 +1271,7 @@
{0x88D30000u, 46u}, // tgc -> Latn
{0xB8D30000u, 46u}, // tgo -> Latn
{0xD0D30000u, 46u}, // tgu -> Latn
- {0x74680000u, 89u}, // th -> Thai
+ {0x74680000u, 90u}, // th -> Thai
{0xACF30000u, 18u}, // thl -> Deva
{0xC0F30000u, 18u}, // thq -> Deva
{0xC4F30000u, 18u}, // thr -> Deva
@@ -1305,14 +1310,14 @@
{0x8E530000u, 25u}, // tsd -> Grek
{0x96530000u, 18u}, // tsf -> Deva
{0x9A530000u, 46u}, // tsg -> Latn
- {0xA6530000u, 90u}, // tsj -> Tibt
+ {0xA6530000u, 91u}, // tsj -> Tibt
{0xDA530000u, 46u}, // tsw -> Latn
{0x74740000u, 17u}, // tt -> Cyrl
{0x8E730000u, 46u}, // ttd -> Latn
{0x92730000u, 46u}, // tte -> Latn
{0xA6730000u, 46u}, // ttj -> Latn
{0xC6730000u, 46u}, // ttr -> Latn
- {0xCA730000u, 89u}, // tts -> Thai
+ {0xCA730000u, 90u}, // tts -> Thai
{0xCE730000u, 46u}, // ttt -> Latn
{0x9E930000u, 46u}, // tuh -> Latn
{0xAE930000u, 46u}, // tul -> Latn
@@ -1323,7 +1328,7 @@
{0xD2B30000u, 46u}, // tvu -> Latn
{0x9ED30000u, 46u}, // twh -> Latn
{0xC2D30000u, 46u}, // twq -> Latn
- {0x9AF30000u, 84u}, // txg -> Tang
+ {0x9AF30000u, 85u}, // txg -> Tang
{0x74790000u, 46u}, // ty -> Latn
{0x83130000u, 46u}, // tya -> Latn
{0xD7130000u, 17u}, // tyv -> Cyrl
@@ -1333,7 +1338,7 @@
{0x75670000u, 1u}, // ug -> Arab
{0x75674B5Au, 17u}, // ug-KZ -> Cyrl
{0x75674D4Eu, 17u}, // ug-MN -> Cyrl
- {0x80D40000u, 91u}, // uga -> Ugar
+ {0x80D40000u, 92u}, // uga -> Ugar
{0x756B0000u, 17u}, // uk -> Cyrl
{0xA1740000u, 46u}, // uli -> Latn
{0x85940000u, 46u}, // umb -> Latn
@@ -1346,6 +1351,7 @@
{0xCE340000u, 46u}, // urt -> Latn
{0xDA340000u, 46u}, // urw -> Latn
{0x82540000u, 46u}, // usa -> Latn
+ {0x9E740000u, 46u}, // uth -> Latn
{0xC6740000u, 46u}, // utr -> Latn
{0x9EB40000u, 46u}, // uvh -> Latn
{0xAEB40000u, 46u}, // uvl -> Latn
@@ -1353,7 +1359,7 @@
{0x757A4146u, 1u}, // uz-AF -> Arab
{0x757A434Eu, 17u}, // uz-CN -> Cyrl
{0x98150000u, 46u}, // vag -> Latn
- {0xA0150000u, 92u}, // vai -> Vaii
+ {0xA0150000u, 93u}, // vai -> Vaii
{0xB4150000u, 46u}, // van -> Latn
{0x76650000u, 46u}, // ve -> Latn
{0x88950000u, 46u}, // vec -> Latn
@@ -1376,7 +1382,7 @@
{0xB4160000u, 46u}, // wan -> Latn
{0xC4160000u, 46u}, // war -> Latn
{0xBC360000u, 46u}, // wbp -> Latn
- {0xC0360000u, 86u}, // wbq -> Telu
+ {0xC0360000u, 87u}, // wbq -> Telu
{0xC4360000u, 18u}, // wbr -> Deva
{0xA0560000u, 46u}, // wci -> Latn
{0xC4960000u, 46u}, // wer -> Latn
@@ -1418,9 +1424,9 @@
{0xC5B70000u, 18u}, // xnr -> Deva
{0x99D70000u, 46u}, // xog -> Latn
{0xB5D70000u, 46u}, // xon -> Latn
- {0xC5F70000u, 70u}, // xpr -> Prti
+ {0xC5F70000u, 71u}, // xpr -> Prti
{0x86370000u, 46u}, // xrb -> Latn
- {0x82570000u, 73u}, // xsa -> Sarb
+ {0x82570000u, 74u}, // xsa -> Sarb
{0xA2570000u, 46u}, // xsi -> Latn
{0xB2570000u, 46u}, // xsm -> Latn
{0xC6570000u, 18u}, // xsr -> Deva
@@ -1461,7 +1467,7 @@
{0x98190000u, 46u}, // zag -> Latn
{0xA4790000u, 1u}, // zdj -> Arab
{0x80990000u, 46u}, // zea -> Latn
- {0x9CD90000u, 87u}, // zgh -> Tfng
+ {0x9CD90000u, 88u}, // zgh -> Tfng
{0x7A680000u, 28u}, // zh -> Hans
{0x7A684155u, 29u}, // zh-AU -> Hant
{0x7A68424Eu, 29u}, // zh-BN -> Hant
@@ -1470,7 +1476,6 @@
{0x7A68484Bu, 29u}, // zh-HK -> Hant
{0x7A684944u, 29u}, // zh-ID -> Hant
{0x7A684D4Fu, 29u}, // zh-MO -> Hant
- {0x7A684D59u, 29u}, // zh-MY -> Hant
{0x7A685041u, 29u}, // zh-PA -> Hant
{0x7A685046u, 29u}, // zh-PF -> Hant
{0x7A685048u, 29u}, // zh-PH -> Hant
@@ -1592,6 +1597,7 @@
0xD701434D4C61746ELLU, // byv_Latn_CM
0x93214D4C4C61746ELLU, // bze_Latn_ML
0x636145534C61746ELLU, // ca_Latn_ES
+ 0x8C0255534C61746ELLU, // cad_Latn_US
0x9C424E474C61746ELLU, // cch_Latn_NG
0xBC42424443616B6DLLU, // ccp_Cakm_BD
0x636552554379726CLLU, // ce_Cyrl_RU
@@ -1627,6 +1633,7 @@
0x637652554379726CLLU, // cv_Cyrl_RU
0x637947424C61746ELLU, // cy_Latn_GB
0x6461444B4C61746ELLU, // da_Latn_DK
+ 0x940343494C61746ELLU, // daf_Latn_CI
0xA80355534C61746ELLU, // dak_Latn_US
0xC40352554379726CLLU, // dar_Cyrl_RU
0xD4034B454C61746ELLU, // dav_Latn_KE
@@ -1636,7 +1643,7 @@
0xC4C343414C61746ELLU, // dgr_Latn_CA
0x91234E454C61746ELLU, // dje_Latn_NE
0xA5A343494C61746ELLU, // dnj_Latn_CI
- 0xA1C3494E41726162LLU, // doi_Arab_IN
+ 0xA1C3494E44657661LLU, // doi_Deva_IN
0x9E23434E4D6F6E67LLU, // drh_Mong_CN
0x864344454C61746ELLU, // dsb_Latn_DE
0xB2634D4C4C61746ELLU, // dtm_Latn_ML
@@ -1839,6 +1846,7 @@
0xC6AA49444C61746ELLU, // kvr_Latn_ID
0xDEAA504B41726162LLU, // kvx_Arab_PK
0x6B7747424C61746ELLU, // kw_Latn_GB
+ 0xAEEA494E44657661LLU, // kxl_Deva_IN
0xB2EA544854686169LLU, // kxm_Thai_TH
0xBEEA504B41726162LLU, // kxp_Arab_PK
0x6B79434E41726162LLU, // ky_Arab_CN
@@ -2047,7 +2055,7 @@
0x9C1252554379726CLLU, // sah_Cyrl_RU
0xC0124B454C61746ELLU, // saq_Latn_KE
0xC81249444C61746ELLU, // sas_Latn_ID
- 0xCC12494E4C61746ELLU, // sat_Latn_IN
+ 0xCC12494E4F6C636BLLU, // sat_Olck_IN
0xD412534E4C61746ELLU, // sav_Latn_SN
0xE412494E53617572LLU, // saz_Saur_IN
0xBC32545A4C61746ELLU, // sbp_Latn_TZ
@@ -2149,6 +2157,7 @@
0x747254524C61746ELLU, // tr_Latn_TR
0xD23354524C61746ELLU, // tru_Latn_TR
0xD63354574C61746ELLU, // trv_Latn_TW
+ 0xDA33504B41726162LLU, // trw_Arab_PK
0x74735A414C61746ELLU, // ts_Latn_ZA
0x8E5347524772656BLLU, // tsd_Grek_GR
0x96534E5044657661LLU, // tsf_Deva_NP
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index bce70e2..2233827 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -30,6 +30,7 @@
#include <memory>
#include <set>
#include <type_traits>
+#include <vector>
#include <android-base/macros.h>
#include <androidfw/ByteBucketArray.h>
@@ -1029,7 +1030,7 @@
// But we don't want to hit the cache, so instead we will have a
// local temporary allocation for the conversions.
size_t convBufferLen = strLen + 4;
- char16_t* convBuffer = (char16_t*)calloc(convBufferLen, sizeof(char16_t));
+ std::vector<char16_t> convBuffer(convBufferLen);
ssize_t l = 0;
ssize_t h = mHeader->stringCount-1;
@@ -1043,8 +1044,8 @@
}
if (s.has_value()) {
char16_t* end = utf8_to_utf16(reinterpret_cast<const uint8_t*>(s->data()),
- s->size(), convBuffer, convBufferLen);
- c = strzcmp16(convBuffer, end-convBuffer, str, strLen);
+ s->size(), convBuffer.data(), convBufferLen);
+ c = strzcmp16(convBuffer.data(), end-convBuffer.data(), str, strLen);
}
if (kDebugStringPoolNoisy) {
ALOGI("Looking at %s, cmp=%d, l/mid/h=%d/%d/%d\n",
@@ -1054,7 +1055,6 @@
if (kDebugStringPoolNoisy) {
ALOGI("MATCH!");
}
- free(convBuffer);
return mid;
} else if (c < 0) {
l = mid + 1;
@@ -1062,7 +1062,6 @@
h = mid - 1;
}
}
- free(convBuffer);
} else {
// It is unusual to get the ID from an unsorted string block...
// most often this happens because we want to get IDs for style
diff --git a/libs/hwui/pipeline/skia/SkiaDisplayList.cpp b/libs/hwui/pipeline/skia/SkiaDisplayList.cpp
index 158c349..2edd48c 100644
--- a/libs/hwui/pipeline/skia/SkiaDisplayList.cpp
+++ b/libs/hwui/pipeline/skia/SkiaDisplayList.cpp
@@ -102,12 +102,12 @@
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 068f968..4b8a8ad 100644
--- a/media/java/android/media/IMediaRouterService.aidl
+++ b/media/java/android/media/IMediaRouterService.aidl
@@ -73,6 +73,8 @@
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 4b09a5f..68237de 100644
--- a/media/java/android/media/MediaRouter2Manager.java
+++ b/media/java/android/media/MediaRouter2Manager.java
@@ -147,6 +147,36 @@
}
/**
+ * 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 68f2964..2f95247 100644
--- a/media/java/android/media/RouteDiscoveryPreference.java
+++ b/media/java/android/media/RouteDiscoveryPreference.java
@@ -153,6 +153,7 @@
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 1249e0d..0bedbd3 100644
--- a/media/java/android/media/tv/TvInputHardwareInfo.java
+++ b/media/java/android/media/tv/TvInputHardwareInfo.java
@@ -190,13 +190,16 @@
/** @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 8871167..c4b622d 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 @@
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 @@
.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 @@
.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 @@
*/
@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/Android.bp b/packages/SystemUI/Android.bp
index 6ecf303..249b194 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -45,7 +45,7 @@
"WindowManager-Shell",
"SystemUIPluginLib",
"SystemUISharedLib",
- "SystemUI-statsd",
+ "SystemUI-statsd",
"SettingsLib",
"androidx.viewpager2_viewpager2",
"androidx.legacy_legacy-support-v4",
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 5a7c5c9..f65f97a 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 @@
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 ef52c2a..785ca35 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -147,11 +147,20 @@
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/OWNERS b/services/OWNERS
index 88d0b61..f1fa542 100644
--- a/services/OWNERS
+++ b/services/OWNERS
@@ -1 +1,4 @@
per-file Android.bp = file:platform/build/soong:/OWNERS
+
+# art-team@ manages the system server profile
+per-file art-profile* = calin@google.com, mathieuc@google.com, ngeoffray@google.com
diff --git a/services/accessibility/OWNERS b/services/accessibility/OWNERS
index c6f42f7..a31cfae 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 0000000..d724cac
--- /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 307d344..5ad5805 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -112,6 +112,9 @@
"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",
@@ -200,6 +203,8 @@
"java/com/android/server/connectivity/NetworkRanker.java",
"java/com/android/server/connectivity/PermissionMonitor.java",
"java/com/android/server/connectivity/ProxyTracker.java",
+ "java/com/android/server/connectivity/QosCallbackAgentConnection.java",
+ "java/com/android/server/connectivity/QosCallbackTracker.java",
"java/com/android/server/connectivity/TcpKeepaliveController.java",
"java/com/android/server/connectivity/Vpn.java",
"java/com/android/server/connectivity/VpnIkev2Utils.java",
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 90a17e7..b6232a0 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -94,6 +94,7 @@
import android.net.INetworkMonitorCallbacks;
import android.net.INetworkPolicyListener;
import android.net.INetworkStatsService;
+import android.net.IQosCallback;
import android.net.ISocketKeepaliveCallback;
import android.net.InetAddresses;
import android.net.IpMemoryStore;
@@ -121,6 +122,10 @@
import android.net.NetworkWatchlistManager;
import android.net.PrivateDnsConfigParcel;
import android.net.ProxyInfo;
+import android.net.QosCallbackException;
+import android.net.QosFilter;
+import android.net.QosSocketFilter;
+import android.net.QosSocketInfo;
import android.net.RouteInfo;
import android.net.RouteInfoParcel;
import android.net.SocketKeepalive;
@@ -204,6 +209,7 @@
import com.android.server.connectivity.NetworkRanker;
import com.android.server.connectivity.PermissionMonitor;
import com.android.server.connectivity.ProxyTracker;
+import com.android.server.connectivity.QosCallbackTracker;
import com.android.server.connectivity.Vpn;
import com.android.server.net.BaseNetworkObserver;
import com.android.server.net.LockdownVpnTracker;
@@ -279,6 +285,10 @@
// Default to 30s linger time-out. Modifiable only for testing.
private static final String LINGER_DELAY_PROPERTY = "persist.netmon.linger";
private static final int DEFAULT_LINGER_DELAY_MS = 30_000;
+
+ // The maximum number of network request allowed per uid before an exception is thrown.
+ private static final int MAX_NETWORK_REQUESTS_PER_UID = 100;
+
@VisibleForTesting
protected int mLingerDelayMs; // Can't be final, or test subclass constructors can't change it.
@@ -291,6 +301,8 @@
@VisibleForTesting
protected final PermissionMonitor mPermissionMonitor;
+ private final PerUidCounter mNetworkRequestCounter;
+
private KeyStore mKeyStore;
@VisibleForTesting
@@ -614,6 +626,7 @@
private final LocationPermissionChecker mLocationPermissionChecker;
private KeepaliveTracker mKeepaliveTracker;
+ private QosCallbackTracker mQosCallbackTracker;
private NetworkNotificationManager mNotifier;
private LingerMonitor mLingerMonitor;
@@ -858,6 +871,66 @@
};
/**
+ * Keeps track of the number of requests made under different uids.
+ */
+ public static class PerUidCounter {
+ private final int mMaxCountPerUid;
+
+ // Map from UID to number of NetworkRequests that UID has filed.
+ @GuardedBy("mUidToNetworkRequestCount")
+ private final SparseIntArray mUidToNetworkRequestCount = new SparseIntArray();
+
+ /**
+ * Constructor
+ *
+ * @param maxCountPerUid the maximum count per uid allowed
+ */
+ public PerUidCounter(final int maxCountPerUid) {
+ mMaxCountPerUid = maxCountPerUid;
+ }
+
+ /**
+ * Increments the request count of the given uid. Throws an exception if the number
+ * of open requests for the uid exceeds the value of maxCounterPerUid which is the value
+ * passed into the constructor. see: {@link #PerUidCounter(int)}.
+ *
+ * @throws ServiceSpecificException with
+ * {@link ConnectivityManager.Errors.TOO_MANY_REQUESTS} if the number of requests for
+ * the uid exceed the allowed number.
+ *
+ * @param uid the uid that the request was made under
+ */
+ public void incrementCountOrThrow(final int uid) {
+ synchronized (mUidToNetworkRequestCount) {
+ final int networkRequests = mUidToNetworkRequestCount.get(uid, 0) + 1;
+ if (networkRequests >= mMaxCountPerUid) {
+ throw new ServiceSpecificException(
+ ConnectivityManager.Errors.TOO_MANY_REQUESTS);
+ }
+ mUidToNetworkRequestCount.put(uid, networkRequests);
+ }
+ }
+
+ /**
+ * Decrements the request count of the given uid.
+ *
+ * @param uid the uid that the request was made under
+ */
+ public void decrementCount(final int uid) {
+ synchronized (mUidToNetworkRequestCount) {
+ final int requests = mUidToNetworkRequestCount.get(uid, 0);
+ if (requests < 1) {
+ logwtf("BUG: too small request count " + requests + " for UID " + uid);
+ } else if (requests == 1) {
+ mUidToNetworkRequestCount.delete(uid);
+ } else {
+ mUidToNetworkRequestCount.put(uid, requests - 1);
+ }
+ }
+ }
+ }
+
+ /**
* Dependencies of ConnectivityService, for injection in tests.
*/
@VisibleForTesting
@@ -945,6 +1018,7 @@
mSystemProperties = mDeps.getSystemProperties();
mNetIdManager = mDeps.makeNetIdManager();
mContext = Objects.requireNonNull(context, "missing Context");
+ mNetworkRequestCounter = new PerUidCounter(MAX_NETWORK_REQUESTS_PER_UID);
mMetricsLog = logger;
mDefaultRequest = createDefaultInternetRequestForTransport(-1, NetworkRequest.Type.REQUEST);
@@ -1115,11 +1189,7 @@
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();
@@ -1129,6 +1199,7 @@
mKeepaliveTracker = new KeepaliveTracker(mContext, mHandler);
mNotifier = new NetworkNotificationManager(mContext, mTelephonyManager);
+ mQosCallbackTracker = new QosCallbackTracker(mHandler, mNetworkRequestCounter);
final int dailyLimit = Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.NETWORK_SWITCH_NOTIFICATION_DAILY_LIMIT,
@@ -1802,30 +1873,6 @@
}
}
- 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.
*/
@@ -2274,20 +2321,6 @@
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
@@ -2393,74 +2426,6 @@
}
/**
- * 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.
*/
@@ -2874,13 +2839,7 @@
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;
@@ -2893,6 +2852,7 @@
updateCapabilitiesForNetwork(nai);
notifyIfacesChangedForNetworkStats();
}
+ break;
}
}
}
@@ -3454,6 +3414,8 @@
// of rematchAllNetworksAndRequests
notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_LOST);
mKeepaliveTracker.handleStopAllKeepalives(nai, SocketKeepalive.ERROR_INVALID_NETWORK);
+
+ mQosCallbackTracker.handleNetworkReleased(nai.network);
for (String iface : nai.linkProperties.getAllInterfaceNames()) {
// Disable wakeup packet monitoring for each interface.
wakeupModifyInterface(iface, nai.networkCapabilities, false);
@@ -3466,6 +3428,7 @@
// 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);
@@ -3478,10 +3441,12 @@
}
}
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());
}
@@ -3720,7 +3685,7 @@
nri.unlinkDeathRecipient();
mNetworkRequests.remove(nri.request);
- decrementNetworkRequestPerUidCount(nri);
+ mNetworkRequestCounter.decrementCount(nri.mUid);
mNetworkRequestInfoLogs.log("RELEASE " + nri);
if (nri.request.isRequest()) {
@@ -3793,19 +3758,6 @@
}
}
- private void decrementNetworkRequestPerUidCount(final NetworkRequestInfo nri) {
- synchronized (mUidToNetworkRequestCount) {
- final int requests = mUidToNetworkRequestCount.get(nri.mUid, 0);
- if (requests < 1) {
- Log.wtf(TAG, "BUG: too small request count " + requests + " for UID " + nri.mUid);
- } else if (requests == 1) {
- mUidToNetworkRequestCount.removeAt(mUidToNetworkRequestCount.indexOfKey(nri.mUid));
- } else {
- mUidToNetworkRequestCount.put(nri.mUid, requests - 1);
- }
- }
- }
-
@Override
public void setAcceptUnvalidated(Network network, boolean accept, boolean always) {
enforceNetworkStackSettingsOrSetup();
@@ -4632,6 +4584,10 @@
Log.w(TAG, s);
}
+ private static void logwtf(String s) {
+ Log.wtf(TAG, s);
+ }
+
private static void loge(String s) {
Log.e(TAG, s);
}
@@ -4995,6 +4951,8 @@
@Override
public boolean updateLockdownVpn() {
+ // 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");
@@ -5372,11 +5330,6 @@
private final HashMap<Messenger, NetworkProviderInfo> mNetworkProviderInfos = new HashMap<>();
private final HashMap<NetworkRequest, NetworkRequestInfo> mNetworkRequests = new HashMap<>();
- private static final int MAX_NETWORK_REQUESTS_PER_UID = 100;
- // Map from UID to number of NetworkRequests that UID has filed.
- @GuardedBy("mUidToNetworkRequestCount")
- private final SparseIntArray mUidToNetworkRequestCount = new SparseIntArray();
-
private static class NetworkProviderInfo {
public final String name;
public final Messenger messenger;
@@ -5490,7 +5443,7 @@
mBinder = null;
mPid = getCallingPid();
mUid = mDeps.getCallingUid();
- enforceRequestCountLimit();
+ mNetworkRequestCounter.incrementCountOrThrow(mUid);
}
NetworkRequestInfo(Messenger m, NetworkRequest r, IBinder binder) {
@@ -5503,7 +5456,7 @@
mPid = getCallingPid();
mUid = mDeps.getCallingUid();
mPendingIntent = null;
- enforceRequestCountLimit();
+ mNetworkRequestCounter.incrementCountOrThrow(mUid);
try {
mBinder.linkToDeath(this, 0);
@@ -5540,17 +5493,6 @@
return null;
}
- private void enforceRequestCountLimit() {
- synchronized (mUidToNetworkRequestCount) {
- int networkRequests = mUidToNetworkRequestCount.get(mUid, 0) + 1;
- if (networkRequests >= MAX_NETWORK_REQUESTS_PER_UID) {
- throw new ServiceSpecificException(
- ConnectivityManager.Errors.TOO_MANY_REQUESTS);
- }
- mUidToNetworkRequestCount.put(mUid, networkRequests);
- }
- }
-
void unlinkDeathRecipient() {
if (mBinder != null) {
mBinder.unlinkToDeath(this, 0);
@@ -5772,9 +5714,14 @@
// Policy already enforced.
return;
}
- if (mPolicyManagerInternal.isUidRestrictedOnMeteredNetworks(uid)) {
- // If UID is restricted, don't allow them to bring up metered APNs.
- networkCapabilities.addCapability(NET_CAPABILITY_NOT_METERED);
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ if (mPolicyManager.isUidRestrictedOnMeteredNetworks(uid)) {
+ // If UID is restricted, don't allow them to bring up metered APNs.
+ networkCapabilities.addCapability(NET_CAPABILITY_NOT_METERED);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
}
@@ -6109,7 +6056,7 @@
final NetworkAgentInfo nai = new NetworkAgentInfo(na,
new Network(mNetIdManager.reserveNetId()), new NetworkInfo(networkInfo), lp, nc,
currentScore, mContext, mTrackerHandler, new NetworkAgentConfig(networkAgentConfig),
- this, mNetd, mDnsResolver, mNMS, providerId, uid);
+ this, mNetd, mDnsResolver, mNMS, providerId, uid, mQosCallbackTracker);
// Make sure the LinkProperties and NetworkCapabilities reflect what the agent info says.
processCapabilitiesFromAgent(nai, nc);
@@ -7309,7 +7256,8 @@
if (oldDefaultNetwork != null) {
mLingerMonitor.noteLingerDefaultNetwork(oldDefaultNetwork, newDefaultNetwork);
}
- updateDataActivityTracking(newDefaultNetwork, oldDefaultNetwork);
+ mNetworkActivityTracker.updateDataActivityTracking(
+ newDefaultNetwork, oldDefaultNetwork);
// Notify system services of the new default.
makeDefault(newDefaultNetwork);
@@ -7907,10 +7855,11 @@
}
@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,
@@ -7918,24 +7867,25 @@
} 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);
}
}
}
@@ -8386,7 +8336,7 @@
// Decrement the reference count for this NetworkRequestInfo. The reference count is
// incremented when the NetworkRequestInfo is created as part of
// enforceRequestCountLimit().
- decrementNetworkRequestPerUidCount(nri);
+ mNetworkRequestCounter.decrementCount(nri.mUid);
return;
}
@@ -8452,7 +8402,7 @@
// Decrement the reference count for this NetworkRequestInfo. The reference count is
// incremented when the NetworkRequestInfo is created as part of
// enforceRequestCountLimit().
- decrementNetworkRequestPerUidCount(nri);
+ mNetworkRequestCounter.decrementCount(nri.mUid);
iCb.unlinkToDeath(cbInfo, 0);
}
@@ -8661,4 +8611,194 @@
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);
+ }
+ }
+ }
+ /**
+ * Registers {@link QosSocketFilter} with {@link IQosCallback}.
+ *
+ * @param socketInfo the socket information
+ * @param callback the callback to register
+ */
+ @Override
+ public void registerQosSocketCallback(@NonNull final QosSocketInfo socketInfo,
+ @NonNull final IQosCallback callback) {
+ final NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(socketInfo.getNetwork());
+ if (nai == null || nai.networkCapabilities == null) {
+ try {
+ callback.onError(QosCallbackException.EX_TYPE_FILTER_NETWORK_RELEASED);
+ } catch (final RemoteException ex) {
+ loge("registerQosCallbackInternal: RemoteException", ex);
+ }
+ return;
+ }
+ registerQosCallbackInternal(new QosSocketFilter(socketInfo), callback, nai);
+ }
+
+ /**
+ * Register a {@link IQosCallback} with base {@link QosFilter}.
+ *
+ * @param filter the filter to register
+ * @param callback the callback to register
+ * @param nai the agent information related to the filter's network
+ */
+ @VisibleForTesting
+ public void registerQosCallbackInternal(@NonNull final QosFilter filter,
+ @NonNull final IQosCallback callback, @NonNull final NetworkAgentInfo nai) {
+ if (filter == null) throw new IllegalArgumentException("filter must be non-null");
+ if (callback == null) throw new IllegalArgumentException("callback must be non-null");
+
+ if (!nai.networkCapabilities.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)) {
+ enforceConnectivityRestrictedNetworksPermission();
+ }
+ mQosCallbackTracker.registerCallback(callback, filter, nai);
+ }
+
+ /**
+ * Unregisters the given callback.
+ *
+ * @param callback the callback to unregister
+ */
+ @Override
+ public void unregisterQosCallback(@NonNull final IQosCallback callback) {
+ mQosCallbackTracker.unregisterCallback(callback);
+ }
}
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 1ea4a89..d30a640 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -405,6 +405,9 @@
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 @@
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 f6b72d6..222c96f 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 = 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 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 5c34584..4e2519b 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -3297,6 +3297,12 @@
enforcePermission(android.Manifest.permission.STORAGE_INTERNAL);
if (isFsEncrypted) {
+ // When a user has secure lock screen, require secret to actually unlock.
+ // This check is mostly in place for emulation mode.
+ if (StorageManager.isFileEncryptedEmulatedOnly() &&
+ mLockPatternUtils.isSecure(userId) && ArrayUtils.isEmpty(secret)) {
+ throw new IllegalStateException("Secret required to unlock secure user " + userId);
+ }
try {
mVold.unlockUserKey(userId, serialNumber, encodeBytes(token),
encodeBytes(secret));
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 5560f81..81d2b83 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.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 @@
@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 c191a78..76db019 100644
--- a/services/core/java/com/android/server/VcnManagementService.java
+++ b/services/core/java/com/android/server/VcnManagementService.java
@@ -26,20 +26,24 @@
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;
import android.os.HandlerThread;
+import android.os.IBinder;
import android.os.Looper;
import android.os.ParcelUuid;
import android.os.PersistableBundle;
import android.os.Process;
+import android.os.RemoteException;
import android.os.ServiceSpecificException;
import android.os.UserHandle;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.util.ArrayMap;
+import android.util.Log;
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
@@ -154,6 +158,11 @@
@NonNull private final PersistableBundleUtils.LockingReadWriteHelper mConfigDiskRwHelper;
+ @GuardedBy("mLock")
+ @NonNull
+ private final Map<IBinder, PolicyListenerBinderDeath> mRegisteredPolicyListeners =
+ new ArrayMap<>();
+
@VisibleForTesting(visibility = Visibility.PRIVATE)
VcnManagementService(@NonNull Context context, @NonNull Dependencies deps) {
mContext = requireNonNull(context, "Missing context");
@@ -495,4 +504,61 @@
return Collections.unmodifiableMap(mVcns);
}
}
+
+ /** Binder death recipient used to remove a registered policy listener. */
+ private class PolicyListenerBinderDeath implements Binder.DeathRecipient {
+ @NonNull private final IVcnUnderlyingNetworkPolicyListener mListener;
+
+ PolicyListenerBinderDeath(@NonNull IVcnUnderlyingNetworkPolicyListener listener) {
+ mListener = listener;
+ }
+
+ @Override
+ public void binderDied() {
+ Log.e(TAG, "app died without removing VcnUnderlyingNetworkPolicyListener");
+ removeVcnUnderlyingNetworkPolicyListener(mListener);
+ }
+ }
+
+ /** Adds the provided listener for receiving VcnUnderlyingNetworkPolicy updates. */
+ @GuardedBy("mLock")
+ @Override
+ public void addVcnUnderlyingNetworkPolicyListener(
+ @NonNull IVcnUnderlyingNetworkPolicyListener listener) {
+ requireNonNull(listener, "listener was null");
+
+ mContext.enforceCallingPermission(
+ android.Manifest.permission.NETWORK_FACTORY,
+ "Must have permission NETWORK_FACTORY to register a policy listener");
+
+ PolicyListenerBinderDeath listenerBinderDeath = new PolicyListenerBinderDeath(listener);
+
+ synchronized (mLock) {
+ mRegisteredPolicyListeners.put(listener.asBinder(), listenerBinderDeath);
+
+ try {
+ listener.asBinder().linkToDeath(listenerBinderDeath, 0 /* flags */);
+ } catch (RemoteException e) {
+ // Remote binder already died - cleanup registered Listener
+ listenerBinderDeath.binderDied();
+ }
+ }
+ }
+
+ /** Removes the provided listener from receiving VcnUnderlyingNetworkPolicy updates. */
+ @GuardedBy("mLock")
+ @Override
+ public void removeVcnUnderlyingNetworkPolicyListener(
+ @NonNull IVcnUnderlyingNetworkPolicyListener listener) {
+ requireNonNull(listener, "listener was null");
+
+ synchronized (mLock) {
+ PolicyListenerBinderDeath listenerBinderDeath =
+ mRegisteredPolicyListeners.remove(listener.asBinder());
+
+ if (listenerBinderDeath != null) {
+ listener.asBinder().unlinkToDeath(listenerBinderDeath, 0 /* flags */);
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 928ddab..686adbb 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.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.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 @@
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 @@
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 1ade8e7..3c53880 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.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.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.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.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 @@
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 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 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 @@
// 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 88b0c3b..b6e632d 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.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 @@
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 @@
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 @@
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 9376e8d..69686a2 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.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 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 @@
@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.
*
- * @param change The change to add. Any change with the same ID will be overwritten.
+ * <p>This is intended to be used by code that reads change config from the filesystem. This
+ * should be done at system startup time.
+ *
+ * <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 @@
}
/**
- * 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.
*
- * @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.
+ * <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
*/
long[] getDisabledChanges(ApplicationInfo app) {
LongArray disabled = new LongArray();
@@ -110,10 +131,10 @@
}
/**
- * 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 @@
}
/**
- * 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 @@
}
/**
- * 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 @@
}
/**
- * 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>Note, package overrides are not persistent and will be lost on system or runtime restart.
+ * <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.
*
- * @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.
+ * <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
+ * @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 @@
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 @@
}
/**
- * 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 @@
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 @@
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)}.
*
- * @param changeId The ID of the change that was overridden.
- * @param packageName The app package name that was overridden.
+ * <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
* @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 @@
/**
* 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 @@
*
* <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 @@
}
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 @@
}
OverrideAllowedState allowedState =
mOverrideValidator.getOverrideAllowedState(change.getId(),
- packageName);
+ packageName);
if (allowedState.state == OverrideAllowedState.ALLOWED) {
allowed.add(change.getId());
}
@@ -361,10 +367,9 @@
* 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 @@
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 @@
/**
* 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 @@
}
/**
- * 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 @@
/**
* 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 @@
}
}
- 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 @@
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 1ea468c..6b2a1c9 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 @@
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 @@
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 @@
if (appInfo == null) {
return mCompatConfig.willChangeBeEnabled(changeId, packageName);
}
- return isChangeEnabled(changeId, appInfo);
+ return isChangeEnabledInternal(changeId, appInfo);
}
@Override
@@ -152,81 +128,82 @@
}
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.
- *
- * @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.
+ * TODO(b/167551701): Remove this method and add 'loggability' as a changeid property.
*/
- public boolean registerListener(long changeId, CompatChange.ChangeListener listener) {
- return mCompatConfig.registerListener(changeId, listener);
+ public boolean isChangeEnabledInternalNoLogging(long changeId, ApplicationInfo appInfo) {
+ return mCompatConfig.isChangeEnabled(changeId, appInfo);
+ }
+
+ /**
+ * Internal version of {@link #isChangeEnabled(long, ApplicationInfo)}.
+ *
+ * <p>Does not perform costly permission check.
+ */
+ 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 @@
}
@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 @@
@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 @@
@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 @@
/**
* 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 @@
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 @@
}
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 @@
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 @@
}
}
- 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 @@
}
}
- private void checkCompatChangeReadAndLogPermission() throws SecurityException {
+ private void checkCompatChangeReadAndLogPermission() {
checkCompatChangeReadPermission();
checkCompatChangeLogPermission();
}
@@ -391,16 +364,34 @@
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 @@
}
/**
- * 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 1024556..26244e6 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 @@
@Override
public void logDefaultNetworkValidity(boolean valid) {
+ NetworkStack.checkNetworkStackPermission(getContext());
mDefaultNetworkMetrics.logDefaultNetworkValidity(SystemClock.elapsedRealtime(), valid);
}
@@ -375,6 +376,7 @@
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/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index ba6cbcd..ab0360b 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -36,13 +36,17 @@
import android.net.NetworkMonitorManager;
import android.net.NetworkRequest;
import android.net.NetworkState;
+import android.net.QosCallbackException;
+import android.net.QosFilter;
+import android.net.QosFilterParcelable;
+import android.net.QosSession;
import android.net.TcpKeepalivePacketData;
-import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.INetworkManagementService;
import android.os.RemoteException;
import android.os.SystemClock;
+import android.telephony.data.EpsBearerQosSessionAttributes;
import android.util.Log;
import android.util.Pair;
import android.util.SparseArray;
@@ -53,7 +57,6 @@
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;
@@ -323,18 +326,20 @@
private final ConnectivityService mConnService;
private final Context mContext;
private final Handler mHandler;
+ private final QosCallbackTracker mQosCallbackTracker;
public NetworkAgentInfo(INetworkAgent na, Network net, NetworkInfo info,
LinkProperties lp, NetworkCapabilities nc, int score, Context context,
Handler handler, NetworkAgentConfig config, ConnectivityService connService, INetd netd,
IDnsResolver dnsResolver, INetworkManagementService nms, int factorySerialNumber,
- int creatorUid) {
+ int creatorUid, QosCallbackTracker qosCallbackTracker) {
Objects.requireNonNull(net);
Objects.requireNonNull(info);
Objects.requireNonNull(lp);
Objects.requireNonNull(nc);
Objects.requireNonNull(context);
Objects.requireNonNull(config);
+ Objects.requireNonNull(qosCallbackTracker);
networkAgent = na;
network = net;
networkInfo = info;
@@ -348,6 +353,7 @@
networkAgentConfig = config;
this.factorySerialNumber = factorySerialNumber;
this.creatorUid = creatorUid;
+ mQosCallbackTracker = qosCallbackTracker;
}
private class AgentDeathMonitor implements IBinder.DeathRecipient {
@@ -533,6 +539,31 @@
}
}
+ /**
+ * Notify the NetworkAgent that the qos filter should be registered against the given qos
+ * callback id.
+ */
+ public void onQosFilterCallbackRegistered(final int qosCallbackId,
+ final QosFilter qosFilter) {
+ try {
+ networkAgent.onQosFilterCallbackRegistered(qosCallbackId,
+ new QosFilterParcelable(qosFilter));
+ } catch (final RemoteException e) {
+ Log.e(TAG, "Error registering a qos callback id against a qos filter", e);
+ }
+ }
+
+ /**
+ * Notify the NetworkAgent that the given qos callback id should be unregistered.
+ */
+ public void onQosCallbackUnregistered(final int qosCallbackId) {
+ try {
+ networkAgent.onQosCallbackUnregistered(qosCallbackId);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error unregistering a qos callback id", e);
+ }
+ }
+
// TODO: consider moving out of NetworkAgentInfo into its own class
private class NetworkAgentMessageHandler extends INetworkAgentRegistry.Stub {
private final Handler mHandler;
@@ -583,16 +614,25 @@
@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();
+ }
+
+ @Override
+ public void sendEpsQosSessionAvailable(final int qosCallbackId, final QosSession session,
+ final EpsBearerQosSessionAttributes attributes) {
+ mQosCallbackTracker.sendEventQosSessionAvailable(qosCallbackId, session, attributes);
+ }
+
+ @Override
+ public void sendQosSessionLost(final int qosCallbackId, final QosSession session) {
+ mQosCallbackTracker.sendEventQosSessionLost(qosCallbackId, session);
+ }
+
+ @Override
+ public void sendQosCallbackError(final int qosCallbackId,
+ @QosCallbackException.ExceptionType final int exceptionType) {
+ mQosCallbackTracker.sendEventQosCallbackError(qosCallbackId, exceptionType);
}
}
diff --git a/services/core/java/com/android/server/connectivity/QosCallbackAgentConnection.java b/services/core/java/com/android/server/connectivity/QosCallbackAgentConnection.java
new file mode 100644
index 0000000..816bf2b
--- /dev/null
+++ b/services/core/java/com/android/server/connectivity/QosCallbackAgentConnection.java
@@ -0,0 +1,192 @@
+/*
+ * 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.connectivity;
+
+import static android.net.QosCallbackException.EX_TYPE_FILTER_NONE;
+
+import android.annotation.NonNull;
+import android.net.IQosCallback;
+import android.net.Network;
+import android.net.QosCallbackException;
+import android.net.QosFilter;
+import android.net.QosSession;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.telephony.data.EpsBearerQosSessionAttributes;
+import android.util.Slog;
+
+import java.util.Objects;
+
+/**
+ * Wraps callback related information and sends messages between network agent and the application.
+ * <p/>
+ * This is a satellite class of {@link com.android.server.ConnectivityService} and not meant
+ * to be used in other contexts.
+ *
+ * @hide
+ */
+class QosCallbackAgentConnection implements IBinder.DeathRecipient {
+ private static final String TAG = QosCallbackAgentConnection.class.getSimpleName();
+ private static final boolean DBG = false;
+
+ private final int mAgentCallbackId;
+ @NonNull private final QosCallbackTracker mQosCallbackTracker;
+ @NonNull private final IQosCallback mCallback;
+ @NonNull private final IBinder mBinder;
+ @NonNull private final QosFilter mFilter;
+ @NonNull private final NetworkAgentInfo mNetworkAgentInfo;
+
+ private final int mUid;
+
+ /**
+ * Gets the uid
+ * @return uid
+ */
+ int getUid() {
+ return mUid;
+ }
+
+ /**
+ * Gets the binder
+ * @return binder
+ */
+ @NonNull
+ IBinder getBinder() {
+ return mBinder;
+ }
+
+ /**
+ * Gets the callback id
+ *
+ * @return callback id
+ */
+ int getAgentCallbackId() {
+ return mAgentCallbackId;
+ }
+
+ /**
+ * Gets the network tied to the callback of this connection
+ *
+ * @return network
+ */
+ @NonNull
+ Network getNetwork() {
+ return mFilter.getNetwork();
+ }
+
+ QosCallbackAgentConnection(@NonNull final QosCallbackTracker qosCallbackTracker,
+ final int agentCallbackId,
+ @NonNull final IQosCallback callback,
+ @NonNull final QosFilter filter,
+ final int uid,
+ @NonNull final NetworkAgentInfo networkAgentInfo) {
+ Objects.requireNonNull(qosCallbackTracker, "qosCallbackTracker must be non-null");
+ Objects.requireNonNull(callback, "callback must be non-null");
+ Objects.requireNonNull(filter, "filter must be non-null");
+ Objects.requireNonNull(networkAgentInfo, "networkAgentInfo must be non-null");
+
+ mQosCallbackTracker = qosCallbackTracker;
+ mAgentCallbackId = agentCallbackId;
+ mCallback = callback;
+ mFilter = filter;
+ mUid = uid;
+ mBinder = mCallback.asBinder();
+ mNetworkAgentInfo = networkAgentInfo;
+ }
+
+ @Override
+ public void binderDied() {
+ logw("binderDied: binder died with callback id: " + mAgentCallbackId);
+ mQosCallbackTracker.unregisterCallback(mCallback);
+ }
+
+ void unlinkToDeathRecipient() {
+ mBinder.unlinkToDeath(this, 0);
+ }
+
+ // Returns false if the NetworkAgent was never notified.
+ boolean sendCmdRegisterCallback() {
+ final int exceptionType = mFilter.validate();
+ if (exceptionType != EX_TYPE_FILTER_NONE) {
+ try {
+ if (DBG) log("sendCmdRegisterCallback: filter validation failed");
+ mCallback.onError(exceptionType);
+ } catch (final RemoteException e) {
+ loge("sendCmdRegisterCallback:", e);
+ }
+ return false;
+ }
+
+ try {
+ mBinder.linkToDeath(this, 0);
+ } catch (final RemoteException e) {
+ loge("failed linking to death recipient", e);
+ return false;
+ }
+ mNetworkAgentInfo.onQosFilterCallbackRegistered(mAgentCallbackId, mFilter);
+ return true;
+ }
+
+ void sendCmdUnregisterCallback() {
+ if (DBG) log("sendCmdUnregisterCallback: unregistering");
+ mNetworkAgentInfo.onQosCallbackUnregistered(mAgentCallbackId);
+ }
+
+ void sendEventQosSessionAvailable(final QosSession session,
+ final EpsBearerQosSessionAttributes attributes) {
+ try {
+ if (DBG) log("sendEventQosSessionAvailable: sending...");
+ mCallback.onQosEpsBearerSessionAvailable(session, attributes);
+ } catch (final RemoteException e) {
+ loge("sendEventQosSessionAvailable: remote exception", e);
+ }
+ }
+
+ void sendEventQosSessionLost(@NonNull final QosSession session) {
+ try {
+ if (DBG) log("sendEventQosSessionLost: sending...");
+ mCallback.onQosSessionLost(session);
+ } catch (final RemoteException e) {
+ loge("sendEventQosSessionLost: remote exception", e);
+ }
+ }
+
+ void sendEventQosCallbackError(@QosCallbackException.ExceptionType final int exceptionType) {
+ try {
+ if (DBG) log("sendEventQosCallbackError: sending...");
+ mCallback.onError(exceptionType);
+ } catch (final RemoteException e) {
+ loge("sendEventQosCallbackError: remote exception", e);
+ }
+ }
+
+ private static void log(@NonNull final String msg) {
+ Slog.d(TAG, msg);
+ }
+
+ private static void logw(@NonNull final String msg) {
+ Slog.w(TAG, msg);
+ }
+
+ private static void loge(@NonNull final String msg, final Throwable t) {
+ Slog.e(TAG, msg, t);
+ }
+
+ private static void logwtf(@NonNull final String msg) {
+ Slog.wtf(TAG, msg);
+ }
+}
diff --git a/services/core/java/com/android/server/connectivity/QosCallbackTracker.java b/services/core/java/com/android/server/connectivity/QosCallbackTracker.java
new file mode 100644
index 0000000..87b4c16
--- /dev/null
+++ b/services/core/java/com/android/server/connectivity/QosCallbackTracker.java
@@ -0,0 +1,277 @@
+/*
+ * 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.connectivity;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.net.IQosCallback;
+import android.net.Network;
+import android.net.QosCallbackException;
+import android.net.QosFilter;
+import android.net.QosSession;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.IBinder;
+import android.telephony.data.EpsBearerQosSessionAttributes;
+import android.util.Slog;
+
+import com.android.internal.util.CollectionUtils;
+import com.android.server.ConnectivityService;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Tracks qos callbacks and handles the communication between the network agent and application.
+ * <p/>
+ * Any method prefixed by handle must be called from the
+ * {@link com.android.server.ConnectivityService} handler thread.
+ *
+ * @hide
+ */
+public class QosCallbackTracker {
+ private static final String TAG = QosCallbackTracker.class.getSimpleName();
+ private static final boolean DBG = true;
+
+ @NonNull
+ private final Handler mConnectivityServiceHandler;
+
+ @NonNull
+ private final ConnectivityService.PerUidCounter mNetworkRequestCounter;
+
+ /**
+ * Each agent gets a unique callback id that is used to proxy messages back to the original
+ * callback.
+ * <p/>
+ * Note: The fact that this is initialized to 0 is to ensure that the thread running
+ * {@link #handleRegisterCallback(IQosCallback, QosFilter, int, NetworkAgentInfo)} sees the
+ * initialized value. This would not necessarily be the case if the value was initialized to
+ * the non-default value.
+ * <p/>
+ * Note: The term previous does not apply to the first callback id that is assigned.
+ */
+ private int mPreviousAgentCallbackId = 0;
+
+ @NonNull
+ private final List<QosCallbackAgentConnection> mConnections = new ArrayList<>();
+
+ /**
+ *
+ * @param connectivityServiceHandler must be the same handler used with
+ * {@link com.android.server.ConnectivityService}
+ * @param networkRequestCounter keeps track of the number of open requests under a given
+ * uid
+ */
+ public QosCallbackTracker(@NonNull final Handler connectivityServiceHandler,
+ final ConnectivityService.PerUidCounter networkRequestCounter) {
+ mConnectivityServiceHandler = connectivityServiceHandler;
+ mNetworkRequestCounter = networkRequestCounter;
+ }
+
+ /**
+ * Registers the callback with the tracker
+ *
+ * @param callback the callback to register
+ * @param filter the filter being registered alongside the callback
+ */
+ public void registerCallback(@NonNull final IQosCallback callback,
+ @NonNull final QosFilter filter, @NonNull final NetworkAgentInfo networkAgentInfo) {
+ final int uid = Binder.getCallingUid();
+
+ // Enforce that the number of requests under this uid has exceeded the allowed number
+ mNetworkRequestCounter.incrementCountOrThrow(uid);
+
+ mConnectivityServiceHandler.post(
+ () -> handleRegisterCallback(callback, filter, uid, networkAgentInfo));
+ }
+
+ private void handleRegisterCallback(@NonNull final IQosCallback callback,
+ @NonNull final QosFilter filter, final int uid,
+ @NonNull final NetworkAgentInfo networkAgentInfo) {
+ final QosCallbackAgentConnection ac =
+ handleRegisterCallbackInternal(callback, filter, uid, networkAgentInfo);
+ if (ac != null) {
+ if (DBG) log("handleRegisterCallback: added callback " + ac.getAgentCallbackId());
+ mConnections.add(ac);
+ } else {
+ mNetworkRequestCounter.decrementCount(uid);
+ }
+ }
+
+ private QosCallbackAgentConnection handleRegisterCallbackInternal(
+ @NonNull final IQosCallback callback,
+ @NonNull final QosFilter filter, final int uid,
+ @NonNull final NetworkAgentInfo networkAgentInfo) {
+ final IBinder binder = callback.asBinder();
+ if (CollectionUtils.any(mConnections, c -> c.getBinder().equals(binder))) {
+ // A duplicate registration would have only made this far due to a programming error.
+ logwtf("handleRegisterCallback: Callbacks can only be register once.");
+ return null;
+ }
+
+ mPreviousAgentCallbackId = mPreviousAgentCallbackId + 1;
+ final int newCallbackId = mPreviousAgentCallbackId;
+
+ final QosCallbackAgentConnection ac =
+ new QosCallbackAgentConnection(this, newCallbackId, callback,
+ filter, uid, networkAgentInfo);
+
+ final int exceptionType = filter.validate();
+ if (exceptionType != QosCallbackException.EX_TYPE_FILTER_NONE) {
+ ac.sendEventQosCallbackError(exceptionType);
+ return null;
+ }
+
+ // Only add to the callback maps if the NetworkAgent successfully registered it
+ if (!ac.sendCmdRegisterCallback()) {
+ // There was an issue when registering the agent
+ if (DBG) log("handleRegisterCallback: error sending register callback");
+ mNetworkRequestCounter.decrementCount(uid);
+ return null;
+ }
+ return ac;
+ }
+
+ /**
+ * Unregisters callback
+ * @param callback callback to unregister
+ */
+ public void unregisterCallback(@NonNull final IQosCallback callback) {
+ mConnectivityServiceHandler.post(() -> handleUnregisterCallback(callback.asBinder(), true));
+ }
+
+ private void handleUnregisterCallback(@NonNull final IBinder binder,
+ final boolean sendToNetworkAgent) {
+ final QosCallbackAgentConnection agentConnection =
+ CollectionUtils.find(mConnections, c -> c.getBinder().equals(binder));
+ if (agentConnection == null) {
+ logw("handleUnregisterCallback: agentConnection is null");
+ return;
+ }
+
+ if (DBG) {
+ log("handleUnregisterCallback: unregister "
+ + agentConnection.getAgentCallbackId());
+ }
+
+ mNetworkRequestCounter.decrementCount(agentConnection.getUid());
+ mConnections.remove(agentConnection);
+
+ if (sendToNetworkAgent) {
+ agentConnection.sendCmdUnregisterCallback();
+ }
+ agentConnection.unlinkToDeathRecipient();
+ }
+
+ /**
+ * Called when the NetworkAgent sends the qos session available event
+ *
+ * @param qosCallbackId the callback id that the qos session is now available to
+ * @param session the qos session that is now available
+ * @param attributes the qos attributes that are now available on the qos session
+ */
+ public void sendEventQosSessionAvailable(final int qosCallbackId,
+ final QosSession session,
+ final EpsBearerQosSessionAttributes attributes) {
+ runOnAgentConnection(qosCallbackId, "sendEventQosSessionAvailable: ",
+ ac -> ac.sendEventQosSessionAvailable(session, attributes));
+ }
+
+ /**
+ * Called when the NetworkAgent sends the qos session lost event
+ *
+ * @param qosCallbackId the callback id that lost the qos session
+ * @param session the corresponding qos session
+ */
+ public void sendEventQosSessionLost(final int qosCallbackId,
+ final QosSession session) {
+ runOnAgentConnection(qosCallbackId, "sendEventQosSessionLost: ",
+ ac -> ac.sendEventQosSessionLost(session));
+ }
+
+ /**
+ * Called when the NetworkAgent sends the qos session on error event
+ *
+ * @param qosCallbackId the callback id that should receive the exception
+ * @param exceptionType the type of exception that caused the callback to error
+ */
+ public void sendEventQosCallbackError(final int qosCallbackId,
+ @QosCallbackException.ExceptionType final int exceptionType) {
+ runOnAgentConnection(qosCallbackId, "sendEventQosCallbackError: ",
+ ac -> {
+ ac.sendEventQosCallbackError(exceptionType);
+ handleUnregisterCallback(ac.getBinder(), false);
+ });
+ }
+
+ /**
+ * Unregisters all callbacks associated to this network agent
+ *
+ * Note: Must be called on the connectivity service handler thread
+ *
+ * @param network the network that was released
+ */
+ public void handleNetworkReleased(@Nullable final Network network) {
+ final List<QosCallbackAgentConnection> connections =
+ CollectionUtils.filter(mConnections, ac -> ac.getNetwork().equals(network));
+
+ for (final QosCallbackAgentConnection agentConnection : connections) {
+ agentConnection.sendEventQosCallbackError(
+ QosCallbackException.EX_TYPE_FILTER_NETWORK_RELEASED);
+
+ // Call unregister workflow w\o sending anything to agent since it is disconnected.
+ handleUnregisterCallback(agentConnection.getBinder(), false);
+ }
+ }
+
+ private interface AgentConnectionAction {
+ void execute(@NonNull QosCallbackAgentConnection agentConnection);
+ }
+
+ @Nullable
+ private void runOnAgentConnection(final int qosCallbackId,
+ @NonNull final String logPrefix,
+ @NonNull final AgentConnectionAction action) {
+ mConnectivityServiceHandler.post(() -> {
+ final QosCallbackAgentConnection ac =
+ CollectionUtils.find(mConnections,
+ c -> c.getAgentCallbackId() == qosCallbackId);
+ if (ac == null) {
+ loge(logPrefix + ": " + qosCallbackId + " missing callback id");
+ return;
+ }
+
+ action.execute(ac);
+ });
+ }
+
+ private static void log(final String msg) {
+ Slog.d(TAG, msg);
+ }
+
+ private static void logw(final String msg) {
+ Slog.w(TAG, msg);
+ }
+
+ private static void loge(final String msg) {
+ Slog.e(TAG, msg);
+ }
+
+ private static void logwtf(final String msg) {
+ Slog.wtf(TAG, msg);
+ }
+}
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index d003b89..c005af4 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.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 @@
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 f882c57..edc9d7c 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 @@
@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 85af346..ab38dca 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 @@
mLastDiscoveryPreference = discoveryPreference;
if (mConnectionReady) {
mActiveConnection.updateDiscoveryPreference(discoveryPreference);
- updateBinding();
}
+ updateBinding();
}
@Override
@@ -205,9 +205,11 @@
}
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 1114fe0..31edf43 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 @@
// 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 @@
@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 @@
}
}
+ 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 0e52a67..b6d6cc4 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 @@
// 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/NetworkPolicyManagerInternal.java b/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java
index 141fa6a..f92f3dc 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java
@@ -39,11 +39,6 @@
public abstract void resetUserState(int userId);
/**
- * @return true if the given uid is restricted from doing networking on metered networks.
- */
- public abstract boolean isUidRestrictedOnMeteredNetworks(int uid);
-
- /**
* Figure out if networking is blocked for a given set of conditions.
*
* This is used by ConnectivityService via passing stale copies of conditions, so it must not
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 1c41dc0..01d4faf 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -5361,7 +5361,7 @@
public boolean isUidNetworkingBlocked(int uid, boolean isNetworkMetered) {
final long startTime = mStatLogger.getTime();
- enforceAnyPermissionOf(OBSERVE_NETWORK_POLICY, PERMISSION_MAINLINE_NETWORK_STACK);
+ mContext.enforceCallingOrSelfPermission(OBSERVE_NETWORK_POLICY, TAG);
final int uidRules;
final boolean isBackgroundRestricted;
synchronized (mUidRulesFirstLock) {
@@ -5376,6 +5376,23 @@
return ret;
}
+ @Override
+ public boolean isUidRestrictedOnMeteredNetworks(int uid) {
+ mContext.enforceCallingOrSelfPermission(OBSERVE_NETWORK_POLICY, TAG);
+ final int uidRules;
+ final boolean isBackgroundRestricted;
+ synchronized (mUidRulesFirstLock) {
+ uidRules = mUidRules.get(uid, RULE_ALLOW_ALL);
+ isBackgroundRestricted = mRestrictBackground;
+ }
+ //TODO(b/177490332): The logic here might not be correct because it doesn't consider
+ // RULE_REJECT_METERED condition. And it could be replaced by
+ // isUidNetworkingBlockedInternal().
+ return isBackgroundRestricted
+ && !hasRule(uidRules, RULE_ALLOW_METERED)
+ && !hasRule(uidRules, RULE_TEMPORARY_ALLOW_METERED);
+ }
+
private static boolean isSystem(int uid) {
return uid < Process.FIRST_APPLICATION_UID;
}
@@ -5444,22 +5461,6 @@
}
}
- /**
- * @return true if the given uid is restricted from doing networking on metered networks.
- */
- @Override
- public boolean isUidRestrictedOnMeteredNetworks(int uid) {
- final int uidRules;
- final boolean isBackgroundRestricted;
- synchronized (mUidRulesFirstLock) {
- uidRules = mUidRules.get(uid, RULE_ALLOW_ALL);
- isBackgroundRestricted = mRestrictBackground;
- }
- return isBackgroundRestricted
- && !hasRule(uidRules, RULE_ALLOW_METERED)
- && !hasRule(uidRules, RULE_TEMPORARY_ALLOW_METERED);
- }
-
@Override
public void onTempPowerSaveWhitelistChange(int appId, boolean added) {
synchronized (mUidRulesFirstLock) {
diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java
index 0f8c9c7..fc56541 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_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.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.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 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.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 @@
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 @@
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 @@
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 @@
// 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
synchronized (mLock) {
targets = mImpl.updateOverlaysForUser(userId);
}
- updateOverlayPaths(userId, targets);
+ updatePackageManager(targets, userId);
} finally {
traceEnd(TRACE_TAG_RRO);
}
@@ -602,7 +652,13 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
@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 @@
}
};
- 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 @@
}
}
}
+
+ // 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 05a4a38..e60411bb 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.List;
import java.util.Map;
import java.util.Objects;
+import java.util.Optional;
import java.util.Set;
/**
@@ -71,7 +72,6 @@
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 @@
@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 @@
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 @@
}
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 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 @@
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 @@
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 @@
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 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 @@
}
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 @@
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 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 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 @@
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 @@
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 @@
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 0000000..5c38ba7
--- /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 01eeb31..4ff75fa 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.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.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 @@
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 @@
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 @@
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,12 +93,10 @@
}
@Override
- @RequiresPermission(android.Manifest.permission.DUMP)
+ @RequiresPermission(android.Manifest.permission.DUMP) // or carrier privileges
public void cancelBugreport(int callingUidUnused, String callingPackage) {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP,
- "cancelBugreport");
int callingUid = Binder.getCallingUid();
- mAppOps.checkPackage(callingUid, callingPackage);
+ enforcePermission(callingPackage, callingUid, true /* checkCarrierPrivileges */);
synchronized (mLock) {
IDumpstate ds = getDumpstateBinderServiceLocked();
@@ -134,6 +132,34 @@
}
}
+ 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.
*
@@ -310,6 +336,13 @@
@Override
public void binderDied() {
+ try {
+ // Allow a small amount of time for any error or finished callbacks to be made.
+ // This ensures that the listener does not receive an erroneous runtime error
+ // callback.
+ Thread.sleep(1000);
+ } catch (InterruptedException ignored) {
+ }
synchronized (mLock) {
if (!mDone) {
// If we have not gotten a "done" callback this must be a crash.
diff --git a/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java b/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java
index 5c01e43..fd2d8e1 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.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 @@
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 @@
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 @@
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 @@
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 f20d80d..ae71c1a 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 @@
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/security/OWNERS b/services/core/java/com/android/server/security/OWNERS
new file mode 100644
index 0000000..91b240b
--- /dev/null
+++ b/services/core/java/com/android/server/security/OWNERS
@@ -0,0 +1,4 @@
+# Bug component: 36824
+
+per-file FileIntegrityService.java = victorhsieh@google.com
+per-file VerityUtils.java = victorhsieh@google.com
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 0000000..9fa9b29
--- /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 25cd641..75277d1 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.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 @@
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 @@
mStrongAuthTracker = new StrongAuthTracker(context);
mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
mSettingsObserver = new SettingsObserver(mHandler);
+ mAuthorizationService = new Authorization();
}
@Override
@@ -696,11 +700,13 @@
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 @@
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/UnderlyingNetworkTracker.java b/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java
index e1feb5a..6427ae2 100644
--- a/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java
+++ b/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java
@@ -24,6 +24,9 @@
import android.os.Handler;
import android.os.ParcelUuid;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.annotations.VisibleForTesting.Visibility;
+
import java.util.Objects;
/**
@@ -72,7 +75,8 @@
@NonNull public final LinkProperties linkProperties;
public final boolean blocked;
- private UnderlyingNetworkRecord(
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ UnderlyingNetworkRecord(
@NonNull Network network,
@NonNull NetworkCapabilities networkCapabilities,
@NonNull LinkProperties linkProperties,
diff --git a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
index 7024e67..93cf470 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 @@
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 @@
*
* <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 @@
* <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 @@
* <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;
@@ -360,11 +360,25 @@
*/
private static final int EVENT_TEARDOWN_TIMEOUT_EXPIRED = 8;
- @NonNull private final DisconnectedState mDisconnectedState = new DisconnectedState();
- @NonNull private final DisconnectingState mDisconnectingState = new DisconnectingState();
- @NonNull private final ConnectingState mConnectingState = new ConnectingState();
- @NonNull private final ConnectedState mConnectedState = new ConnectedState();
- @NonNull private final RetryTimeoutState mRetryTimeoutState = new RetryTimeoutState();
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ @NonNull
+ final DisconnectedState mDisconnectedState = new DisconnectedState();
+
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ @NonNull
+ final DisconnectingState mDisconnectingState = new DisconnectingState();
+
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ @NonNull
+ final ConnectingState mConnectingState = new ConnectingState();
+
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ @NonNull
+ final ConnectedState mConnectedState = new ConnectedState();
+
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ @NonNull
+ final RetryTimeoutState mRetryTimeoutState = new RetryTimeoutState();
@NonNull private final VcnContext mVcnContext;
@NonNull private final ParcelUuid mSubscriptionGroup;
@@ -455,7 +469,8 @@
this(vcnContext, subscriptionGroup, connectionConfig, new Dependencies());
}
- private VcnGatewayConnection(
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ VcnGatewayConnection(
@NonNull VcnContext vcnContext,
@NonNull ParcelUuid subscriptionGroup,
@NonNull VcnGatewayConnectionConfig connectionConfig,
@@ -504,21 +519,23 @@
* <p>Once torn down, this VcnTunnel CANNOT be started again.
*/
public void teardownAsynchronously() {
- mUnderlyingNetworkTracker.teardown();
+ sendMessage(
+ EVENT_DISCONNECT_REQUESTED,
+ TOKEN_ALL,
+ new EventDisconnectRequestedInfo(DISCONNECT_REASON_TEARDOWN));
+ // TODO: Notify VcnInstance (via callbacks) of permanent teardown of this tunnel, since this
+ // 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();
}
- sendMessage(
- EVENT_DISCONNECT_REQUESTED,
- TOKEN_ANY,
- new EventDisconnectRequestedInfo(DISCONNECT_REASON_TEARDOWN));
- quit();
-
- // TODO: Notify VcnInstance (via callbacks) of permanent teardown of this tunnel, since this
- // is also called asynchronously when a NetworkAgent becomes unwanted
+ mUnderlyingNetworkTracker.teardown();
}
private class VcnUnderlyingNetworkTrackerCallback implements UnderlyingNetworkTrackerCallback {
@@ -530,26 +547,24 @@
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 +609,103 @@
}
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);
+ mIsRunning = false;
+
+ 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.
*
@@ -605,10 +713,62 @@
*/
private class DisconnectedState extends BaseState {
@Override
- protected void processStateMsg(Message msg) {}
+ protected void enterState() {
+ if (!mIsRunning) {
+ quitNow(); // Ignore all queued events; cleanup is complete.
+ }
+
+ if (mIkeSession != null || mNetworkAgent != null) {
+ Slog.wtf(TAG, "Active IKE Session or NetworkAgent in DisconnectedState");
+ }
+ }
+
+ @Override
+ protected void processStateMsg(Message msg) {
+ switch (msg.what) {
+ case EVENT_UNDERLYING_NETWORK_CHANGED:
+ // First network found; start tunnel
+ mUnderlying = ((EventUnderlyingNetworkChangedInfo) msg.obj).newUnderlying;
+
+ if (mUnderlying != null) {
+ transitionTo(mConnectingState);
+ }
+ break;
+ case EVENT_DISCONNECT_REQUESTED:
+ mIsRunning = false;
+
+ quitNow();
+ break;
+ default:
+ logUnhandledMessage(msg);
+ break;
+ }
+ }
}
- 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.
@@ -779,7 +939,32 @@
}
}
- /** External dependencies used by VcnGatewayConnection, for injection in tests. */
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ UnderlyingNetworkTrackerCallback getUnderlyingNetworkTrackerCallback() {
+ return mUnderlyingNetworkTrackerCallback;
+ }
+
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ UnderlyingNetworkRecord getUnderlyingNetwork() {
+ return mUnderlying;
+ }
+
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ void setUnderlyingNetwork(@Nullable UnderlyingNetworkRecord record) {
+ mUnderlying = record;
+ }
+
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ boolean isRunning() {
+ return mIsRunning;
+ }
+
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ void setIsRunning(boolean isRunning) {
+ mIsRunning = isRunning;
+ }
+
+ /** External dependencies used by VcnGatewayConnection, for injection in tests */
@VisibleForTesting(visibility = Visibility.PRIVATE)
public static class Dependencies {
/** Builds a new UnderlyingNetworkTracker. */
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 0542ef9..783037f 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 @@
}
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/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 6786f60..5d06da7 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -30,6 +30,7 @@
import static android.app.admin.DevicePolicyManager.WIPE_EUICC;
import static android.app.admin.PasswordMetrics.computeForPassword;
import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE;
+import static android.net.InetAddresses.parseNumericAddress;
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE;
import static com.android.internal.widget.LockPatternUtils.EscrowTokenStateChangeCallback;
@@ -65,6 +66,8 @@
import static org.mockito.hamcrest.MockitoHamcrest.argThat;
import static org.testng.Assert.assertThrows;
+import static java.util.Collections.emptyList;
+
import android.Manifest.permission;
import android.app.Activity;
import android.app.AppOpsManager;
@@ -118,6 +121,8 @@
import org.mockito.stubbing.Answer;
import java.io.File;
+import java.net.InetSocketAddress;
+import java.net.Proxy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -2246,6 +2251,48 @@
assertThat(actualAccounts).containsExactlyElementsIn(expectedAccounts);
}
+ public void testGetProxyParameters() throws Exception {
+ assertThat(dpm.getProxyParameters(inetAddrProxy("192.0.2.1", 1234), emptyList()))
+ .isEqualTo(new Pair<>("192.0.2.1:1234", ""));
+ assertThat(dpm.getProxyParameters(inetAddrProxy("192.0.2.1", 1234),
+ listOf("one.example.com ", " two.example.com ")))
+ .isEqualTo(new Pair<>("192.0.2.1:1234", "one.example.com,two.example.com"));
+ assertThat(dpm.getProxyParameters(hostnameProxy("proxy.example.com", 1234), emptyList()))
+ .isEqualTo(new Pair<>("proxy.example.com:1234", ""));
+ assertThat(dpm.getProxyParameters(hostnameProxy("proxy.example.com", 1234),
+ listOf("excluded.example.com")))
+ .isEqualTo(new Pair<>("proxy.example.com:1234", "excluded.example.com"));
+
+ assertThrows(IllegalArgumentException.class, () -> dpm.getProxyParameters(
+ inetAddrProxy("192.0.2.1", 0), emptyList()));
+ assertThrows(IllegalArgumentException.class, () -> dpm.getProxyParameters(
+ hostnameProxy("", 1234), emptyList()));
+ assertThrows(IllegalArgumentException.class, () -> dpm.getProxyParameters(
+ hostnameProxy("", 0), emptyList()));
+ assertThrows(IllegalArgumentException.class, () -> dpm.getProxyParameters(
+ hostnameProxy("invalid! hostname", 1234), emptyList()));
+ assertThrows(IllegalArgumentException.class, () -> dpm.getProxyParameters(
+ hostnameProxy("proxy.example.com", 1234), listOf("invalid exclusion")));
+ assertThrows(IllegalArgumentException.class, () -> dpm.getProxyParameters(
+ hostnameProxy("proxy.example.com", -1), emptyList()));
+ assertThrows(IllegalArgumentException.class, () -> dpm.getProxyParameters(
+ hostnameProxy("proxy.example.com", 0xFFFF + 1), emptyList()));
+ }
+
+ private static Proxy inetAddrProxy(String inetAddr, int port) {
+ return new Proxy(
+ Proxy.Type.HTTP, new InetSocketAddress(parseNumericAddress(inetAddr), port));
+ }
+
+ private static Proxy hostnameProxy(String hostname, int port) {
+ return new Proxy(
+ Proxy.Type.HTTP, InetSocketAddress.createUnresolved(hostname, port));
+ }
+
+ private static List<String> listOf(String... args) {
+ return Arrays.asList(args);
+ }
+
public void testSetKeyguardDisabledFeaturesWithDO() throws Exception {
mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
setupDeviceOwner();
@@ -5156,7 +5203,7 @@
// Attempt to set to empty list (which means no listener is allowlisted)
mContext.binder.callingUid = adminUid;
assertFalse(dpms.setPermittedCrossProfileNotificationListeners(
- admin1, Collections.emptyList()));
+ admin1, emptyList()));
assertNull(dpms.getPermittedCrossProfileNotificationListeners(admin1));
mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
@@ -5248,7 +5295,7 @@
// Setting an empty allowlist - only system listeners allowed
mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID;
assertTrue(dpms.setPermittedCrossProfileNotificationListeners(
- admin1, Collections.emptyList()));
+ admin1, emptyList()));
assertEquals(0, dpms.getPermittedCrossProfileNotificationListeners(admin1).size());
mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
@@ -5312,7 +5359,7 @@
// all allowed in primary profile
mContext.binder.callingUid = MANAGED_PROFILE_ADMIN_UID;
assertTrue(dpms.setPermittedCrossProfileNotificationListeners(
- admin1, Collections.emptyList()));
+ admin1, emptyList()));
assertEquals(0, dpms.getPermittedCrossProfileNotificationListeners(admin1).size());
mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
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 391611b..5468fba 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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 @@
}
@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 4f882ce..33dbcc0 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.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 java.util.List;
import java.util.Map;
+import java.util.Optional;
@RunWith(AndroidJUnit4.class)
public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTestsBase {
@@ -55,7 +59,7 @@
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 @@
}
@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 @@
}
@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 @@
}
@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 @@
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 @@
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 @@
}
@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;
+ installNewPackage(overlay(OVERLAY, TARGET), USER);
+ assertEquals(impl.setEnabled(OVERLAY, true, USER),
+ Optional.of(new PackageAndUser(TARGET, USER)));
- impl.setEnabled(OVERLAY, true, USER);
- assertEquals(1, listener.count);
- listener.count = 0;
-
- 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 @@
}
@Test
- public void testConfigSignaturePolicyCertNok() {
+ public void testConfigSignaturePolicyCertNok() throws Exception {
setConfigSignaturePackageName(CONFIG_SIGNATURE_REFERENCE_PKG);
reinitializeImpl();
@@ -247,7 +245,7 @@
}
@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 @@
}
@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 @@
}
@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 006dda0..2c477c8 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.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.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 @@
@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 @@
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 @@
*
* @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 @@
* {@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 @@
*
* @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 @@
}
}
}
-
- 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 b07b8fa..9b8a2a8 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 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 @@
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 @@
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 @@
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 131e4f3..0727e5a 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 @@
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 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 @@
|| 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 0000000..0471e29
--- /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 d012971..f6d18fc 100644
--- a/telephony/java/android/telephony/AccessNetworkConstants.java
+++ b/telephony/java/android/telephony/AccessNetworkConstants.java
@@ -18,10 +18,7 @@
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 @@
* 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 @@
* 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 @@
* 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 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 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 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 @@
BAND_18,
BAND_20,
BAND_25,
+ BAND_26,
BAND_28,
BAND_29,
BAND_30,
@@ -398,9 +776,11 @@
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 @@
BAND_93,
BAND_94,
BAND_95,
+ BAND_96,
BAND_257,
BAND_258,
BAND_260,
@@ -464,7 +845,8 @@
value = {
FREQUENCY_RANGE_GROUP_UNKNOWN,
FREQUENCY_RANGE_GROUP_1,
- FREQUENCY_RANGE_GROUP_2})
+ FREQUENCY_RANGE_GROUP_2
+ })
public @interface FrequencyRangeGroup {}
/**
@@ -489,6 +871,7 @@
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 @@
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 @@
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 @@
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 7661a32..f29f3bd 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_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 @@
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 @@
}
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 74b2aad..8841935 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -2774,6 +2774,30 @@
public static final String IMSI_KEY_DOWNLOAD_URL_STRING = "imsi_key_download_url_string";
/**
+ * String representation of a carrier's public key used for IMSI encryption for ePDG. If this
+ * is provided, the device will use it as a fallback when no key exists on device, but the key
+ * download will still initiate.
+ * Example string:
+ * "-----BEGIN CERTIFICATE-----\nabcde12345abcde12345abcde12345abcde1234
+ * 5abcde12345abcde12345\nabcde12345abcde12345abcde12345abcde12345a\n-----END CERTIFICATE-----"
+ * @hide
+ */
+ public static final String IMSI_CARRIER_PUBLIC_KEY_EPDG_STRING =
+ "imsi_carrier_public_key_epdg_string";
+
+ /**
+ * String representation of a carrier's public key used for IMSI encryption for WLAN. If this
+ * is provided, the device will use it as a fallback when no key exists on device, but the key
+ * download will still initiate.
+ * Example string:
+ * "-----BEGIN CERTIFICATE-----\nabcde12345abcde12345abcde12345abcde1234
+ * 5abcde12345abcde12345\nabcde12345abcde12345abcde12345abcde12345a\n-----END CERTIFICATE-----"
+ * @hide
+ */
+ public static final String IMSI_CARRIER_PUBLIC_KEY_WLAN_STRING =
+ "imsi_carrier_public_key_wlan_string";
+
+ /**
* Identifies if the key is available for WLAN or EPDG or both. The value is a bitmask.
* 0 indicates that neither EPDG or WLAN is enabled.
* 1 indicates that key type TelephonyManager#KEY_TYPE_EPDG is enabled.
@@ -4077,6 +4101,24 @@
"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 whether RTT is supported while roaming.
+ */
+ public static final String KEY_RTT_SUPPORTED_WHILE_ROAMING_BOOL =
+ "rtt_supported_while_roaming";
+
+ /**
* Indicates if auto-configuration server is used for the RCS config
* Reference: GSMA RCC.14
*/
@@ -4433,6 +4475,8 @@
sDefaults.putBoolean(KEY_DISABLE_VOICE_BARRING_NOTIFICATION_BOOL, false);
sDefaults.putInt(IMSI_KEY_AVAILABILITY_INT, 0);
sDefaults.putString(IMSI_KEY_DOWNLOAD_URL_STRING, null);
+ sDefaults.putString(IMSI_CARRIER_PUBLIC_KEY_EPDG_STRING, null);
+ sDefaults.putString(IMSI_CARRIER_PUBLIC_KEY_WLAN_STRING, null);
sDefaults.putBoolean(KEY_CONVERT_CDMA_CALLER_ID_MMI_CODES_WHILE_ROAMING_ON_3GPP_BOOL,
false);
sDefaults.putStringArray(KEY_NON_ROAMING_OPERATOR_STRING_ARRAY, null);
@@ -4441,6 +4485,7 @@
sDefaults.putBoolean(KEY_RTT_SUPPORTED_BOOL, false);
sDefaults.putBoolean(KEY_TTY_SUPPORTED_BOOL, true);
sDefaults.putBoolean(KEY_HIDE_TTY_HCO_VCO_WITH_RTT_BOOL, false);
+ sDefaults.putBoolean(KEY_RTT_SUPPORTED_WHILE_ROAMING_BOOL, false);
sDefaults.putBoolean(KEY_DISABLE_CHARGE_INDICATION_BOOL, false);
sDefaults.putBoolean(KEY_SUPPORT_NO_REPLY_TIMER_FOR_CFNRY_BOOL, true);
sDefaults.putStringArray(KEY_FEATURE_ACCESS_CODES_STRING_ARRAY, null);
@@ -4628,6 +4673,7 @@
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/ImsiEncryptionInfo.java b/telephony/java/android/telephony/ImsiEncryptionInfo.java
index 75a79d6..4978692 100644
--- a/telephony/java/android/telephony/ImsiEncryptionInfo.java
+++ b/telephony/java/android/telephony/ImsiEncryptionInfo.java
@@ -163,8 +163,8 @@
public String toString(){
return "[ImsiEncryptionInfo "
+ "mcc=" + mcc
- + "mnc=" + mnc
- + "publicKey=" + publicKey
+ + " mnc=" + mnc
+ + " publicKey=" + publicKey
+ ", keyIdentifier=" + keyIdentifier
+ ", keyType=" + keyType
+ ", expirationTime=" + expirationTime
diff --git a/telephony/java/android/telephony/PhysicalChannelConfig.java b/telephony/java/android/telephony/PhysicalChannelConfig.java
index 327d631..9fb098e 100644
--- a/telephony/java/android/telephony/PhysicalChannelConfig.java
+++ b/telephony/java/android/telephony/PhysicalChannelConfig.java
@@ -55,6 +55,18 @@
/** 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 @@
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 @@
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 @@
*/
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 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 @@
}
/**
- * @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 @@
}
/**
- * @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 @@
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 @@
* @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 @@
}
}
+ 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 @@
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 @@
.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 @@
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 @@
* @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/PreciseDisconnectCause.java b/telephony/java/android/telephony/PreciseDisconnectCause.java
index 250d9e8..3b4cf75 100644
--- a/telephony/java/android/telephony/PreciseDisconnectCause.java
+++ b/telephony/java/android/telephony/PreciseDisconnectCause.java
@@ -121,7 +121,7 @@
public static final int BEARER_CAPABILITY_NOT_AUTHORIZED = 57;
/** The requested bearer capability is not available at this time. */
public static final int BEARER_NOT_AVAIL = 58;
- /** The service option is not availble at this time. */
+ /** The service option is not available at this time. */
public static final int SERVICE_OPTION_NOT_AVAILABLE = 63;
/** The equipment sending this cause does not support the bearer capability requested. */
public static final int BEARER_SERVICE_NOT_IMPLEMENTED = 65;
diff --git a/telephony/java/android/telephony/RadioInterfaceCapabilities.java b/telephony/java/android/telephony/RadioInterfaceCapabilities.java
new file mode 100644
index 0000000..7c7eb9f
--- /dev/null
+++ b/telephony/java/android/telephony/RadioInterfaceCapabilities.java
@@ -0,0 +1,53 @@
+/*
+ * 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.util.ArraySet;
+
+/**
+ * Contains the set of supported capabilities that the Radio Interface supports on this device.
+ *
+ * @hide
+ */
+public class RadioInterfaceCapabilities {
+
+ private final ArraySet<String> mSupportedCapabilities;
+
+
+ public RadioInterfaceCapabilities() {
+ mSupportedCapabilities = new ArraySet<>();
+ }
+
+ /**
+ * Marks a capability as supported
+ *
+ * @param capabilityName the name of the capability
+ */
+ public void addSupportedCapability(
+ @TelephonyManager.RadioInterfaceCapability String capabilityName) {
+ mSupportedCapabilities.add(capabilityName);
+ }
+
+ /**
+ * Whether the capability is supported
+ *
+ * @param capabilityName the name of the capability
+ */
+ public boolean isSupported(String capabilityName) {
+ return mSupportedCapabilities.contains(capabilityName);
+ }
+}
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index dedb1af..f110dae 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -2111,4 +2111,23 @@
}
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 0000000..a45de2e
--- /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
index 2a16402..af67ed2 100644
--- a/telephony/java/android/telephony/SignalStrengthUpdateRequest.java
+++ b/telephony/java/android/telephony/SignalStrengthUpdateRequest.java
@@ -17,6 +17,8 @@
package android.telephony;
import android.annotation.NonNull;
+import android.os.Binder;
+import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
@@ -56,6 +58,11 @@
*/
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,
@@ -66,6 +73,7 @@
mIsReportingRequestedWhileIdle = isReportingRequestedWhileIdle;
mIsSystemThresholdReportingRequestedWhileIdle =
isSystemThresholdReportingRequestedWhileIdle;
+ mLiveToken = new Binder();
}
/**
@@ -148,6 +156,7 @@
mSignalThresholdInfos = in.createTypedArrayList(SignalThresholdInfo.CREATOR);
mIsReportingRequestedWhileIdle = in.readBoolean();
mIsSystemThresholdReportingRequestedWhileIdle = in.readBoolean();
+ mLiveToken = in.readStrongBinder();
}
/**
@@ -178,6 +187,15 @@
return mIsSystemThresholdReportingRequestedWhileIdle;
}
+ /*
+ * @return the live token of the request
+ *
+ * @hide
+ */
+ public @NonNull IBinder getLiveToken() {
+ return mLiveToken;
+ }
+
@Override
public int describeContents() {
return 0;
@@ -188,6 +206,7 @@
dest.writeTypedList(mSignalThresholdInfos);
dest.writeBoolean(mIsReportingRequestedWhileIdle);
dest.writeBoolean(mIsSystemThresholdReportingRequestedWhileIdle);
+ dest.writeStrongBinder(mLiveToken);
}
@Override
@@ -199,10 +218,10 @@
}
SignalStrengthUpdateRequest request = (SignalStrengthUpdateRequest) other;
- return request.mSignalThresholdInfos.equals(mSignalThresholdInfos)
- && request.mIsReportingRequestedWhileIdle == mIsReportingRequestedWhileIdle
- && request.mIsSystemThresholdReportingRequestedWhileIdle
- == mIsSystemThresholdReportingRequestedWhileIdle;
+ return mSignalThresholdInfos.equals(request.mSignalThresholdInfos)
+ && mIsReportingRequestedWhileIdle == request.mIsReportingRequestedWhileIdle
+ && mIsSystemThresholdReportingRequestedWhileIdle
+ == request.mIsSystemThresholdReportingRequestedWhileIdle;
}
@Override
@@ -233,6 +252,8 @@
.append(mIsReportingRequestedWhileIdle)
.append(" mIsSystemThresholdReportingRequestedWhileIdle=")
.append(mIsSystemThresholdReportingRequestedWhileIdle)
+ .append(" mLiveToken")
+ .append(mLiveToken)
.append("}").toString();
}
diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java
index bcc2c67..b958bff 100644
--- a/telephony/java/android/telephony/SmsManager.java
+++ b/telephony/java/android/telephony/SmsManager.java
@@ -345,7 +345,6 @@
* 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 @@
* <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 @@
* <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 @@
* 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 @@
* 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 @@
* 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 @@
* 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 @@
* <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 3d5c6aa..1fcb504 100644
--- a/telephony/java/android/telephony/TelephonyDisplayInfo.java
+++ b/telephony/java/android/telephony/TelephonyDisplayInfo.java
@@ -29,6 +29,10 @@
* 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 f39ee09..646744d 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -120,6 +120,7 @@
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 @@
}
/**
- * 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 Registration state
+ * @param registered whether ims is registered
+ *
* @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 @@
* @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 @@
@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);
}
@@ -14331,6 +14344,40 @@
return Collections.emptyList();
}
+ /** @hide */
+ @IntDef(prefix = {"RADIO_INTERFACE_CAPABILITY_"},
+ value = {})
+ public @interface RadioInterfaceCapability {}
+
+ /**
+ * Whether the device supports a given capability on the radio interface.
+ *
+ * If the capability is not in the set of radio interface capabilities, false is returned.
+ *
+ * @param capability the name of the capability to check for
+ * @return the availability of the capability
+ *
+ * @hide
+ */
+ public boolean isRadioInterfaceCapabilitySupported(
+ @NonNull @RadioInterfaceCapability String capability) {
+ try {
+ if (capability == null) return false;
+
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ return telephony.isRadioInterfaceCapabilitySupported(capability);
+ } else {
+ throw new IllegalStateException("telephony service is null.");
+ }
+ } catch (RemoteException ex) {
+ if (!isSystemProcess()) {
+ ex.rethrowAsRuntimeException();
+ }
+ }
+ return false;
+ }
+
/**
* Indicates that the thermal mitigation request was completed successfully.
*
@@ -14668,4 +14715,98 @@
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/data/EpsBearerQosSessionAttributes.aidl b/telephony/java/android/telephony/data/EpsBearerQosSessionAttributes.aidl
new file mode 100644
index 0000000..da31f98
--- /dev/null
+++ b/telephony/java/android/telephony/data/EpsBearerQosSessionAttributes.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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.data;
+
+ parcelable EpsBearerQosSessionAttributes;
\ No newline at end of file
diff --git a/telephony/java/android/telephony/data/EpsBearerQosSessionAttributes.java b/telephony/java/android/telephony/data/EpsBearerQosSessionAttributes.java
new file mode 100644
index 0000000..041edc0
--- /dev/null
+++ b/telephony/java/android/telephony/data/EpsBearerQosSessionAttributes.java
@@ -0,0 +1,234 @@
+/*
+ * 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.data;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.net.QosSessionAttributes;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Provides Qos attributes of an EPS bearer.
+ *
+ * {@hide}
+ */
+@SystemApi
+public final class EpsBearerQosSessionAttributes implements Parcelable, QosSessionAttributes {
+ private static final String TAG = EpsBearerQosSessionAttributes.class.getSimpleName();
+ private final int mQci;
+ private final long mMaxUplinkBitRate;
+ private final long mMaxDownlinkBitRate;
+ private final long mGuaranteedUplinkBitRate;
+ private final long mGuaranteedDownlinkBitRate;
+ @NonNull private final List<InetSocketAddress> mRemoteAddresses;
+
+ /**
+ * Quality of Service Class Identifier (QCI), see 3GPP TS 23.203 and 29.212.
+ * The allowed values are standard values(1-9, 65-68, 69-70, 75, 79-80, 82-85)
+ * defined in the spec and operator specific values in the range 128-254.
+ *
+ * @return the qci of the session
+ */
+ public int getQci() {
+ return mQci;
+ }
+
+ /**
+ * Minimum bit rate in kbps that is guaranteed to be provided by the network on the uplink.
+ *
+ * see 3GPP TS 23.107 section 6.4.3.1
+ *
+ * Note: The Qos Session may be shared with OTHER applications besides yours.
+ *
+ * @return the guaranteed bit rate in kbps
+ */
+ public long getGuaranteedUplinkBitRate() {
+ return mGuaranteedUplinkBitRate;
+ }
+
+ /**
+ * Minimum bit rate in kbps that is guaranteed to be provided by the network on the downlink.
+ *
+ * see 3GPP TS 23.107 section 6.4.3.1
+ *
+ * Note: The Qos Session may be shared with OTHER applications besides yours.
+ *
+ * @return the guaranteed bit rate in kbps
+ */
+ public long getGuaranteedDownlinkBitRate() {
+ return mGuaranteedDownlinkBitRate;
+ }
+
+ /**
+ * The maximum kbps that the network will accept.
+ *
+ * see 3GPP TS 23.107 section 6.4.3.1
+ *
+ * Note: The Qos Session may be shared with OTHER applications besides yours.
+ *
+ * @return the max uplink bit rate in kbps
+ */
+ public long getMaxUplinkBitRate() {
+ return mMaxUplinkBitRate;
+ }
+
+ /**
+ * The maximum kbps that the network can provide.
+ *
+ * see 3GPP TS 23.107 section 6.4.3.1
+ *
+ * Note: The Qos Session may be shared with OTHER applications besides yours.
+ *
+ * @return the max downlink bit rate in kbps
+ */
+ public long getMaxDownlinkBitRate() {
+ return mMaxDownlinkBitRate;
+ }
+
+ /**
+ * List of remote addresses associated with the Qos Session. The given uplink bit rates apply
+ * to this given list of remote addresses.
+ *
+ * Note: In the event that the list is empty, it is assumed that the uplink bit rates apply to
+ * all remote addresses that are not contained in a different set of attributes.
+ *
+ * @return list of remote socket addresses that the attributes apply to
+ */
+ @NonNull
+ public List<InetSocketAddress> getRemoteAddresses() {
+ return mRemoteAddresses;
+ }
+
+ /**
+ * ..ctor for attributes
+ *
+ * @param qci quality class indicator
+ * @param maxDownlinkBitRate the max downlink bit rate in kbps
+ * @param maxUplinkBitRate the max uplink bit rate in kbps
+ * @param guaranteedDownlinkBitRate the guaranteed downlink bit rate in kbps
+ * @param guaranteedUplinkBitRate the guaranteed uplink bit rate in kbps
+ * @param remoteAddresses the remote addresses that the uplink bit rates apply to
+ *
+ * @hide
+ */
+ public EpsBearerQosSessionAttributes(final int qci,
+ final long maxDownlinkBitRate, final long maxUplinkBitRate,
+ final long guaranteedDownlinkBitRate, final long guaranteedUplinkBitRate,
+ @NonNull final List<InetSocketAddress> remoteAddresses) {
+ Objects.requireNonNull(remoteAddresses, "remoteAddress must be non-null");
+ mQci = qci;
+ mMaxDownlinkBitRate = maxDownlinkBitRate;
+ mMaxUplinkBitRate = maxUplinkBitRate;
+ mGuaranteedDownlinkBitRate = guaranteedDownlinkBitRate;
+ mGuaranteedUplinkBitRate = guaranteedUplinkBitRate;
+
+ final List<InetSocketAddress> remoteAddressesTemp = copySocketAddresses(remoteAddresses);
+ mRemoteAddresses = Collections.unmodifiableList(remoteAddressesTemp);
+ }
+
+ private static List<InetSocketAddress> copySocketAddresses(
+ @NonNull final List<InetSocketAddress> remoteAddresses) {
+ final List<InetSocketAddress> remoteAddressesTemp = new ArrayList<>();
+ for (final InetSocketAddress socketAddress : remoteAddresses) {
+ if (socketAddress != null && socketAddress.getAddress() != null) {
+ remoteAddressesTemp.add(socketAddress);
+ }
+ }
+ return remoteAddressesTemp;
+ }
+
+ private EpsBearerQosSessionAttributes(@NonNull final Parcel in) {
+ mQci = in.readInt();
+ mMaxDownlinkBitRate = in.readLong();
+ mMaxUplinkBitRate = in.readLong();
+ mGuaranteedDownlinkBitRate = in.readLong();
+ mGuaranteedUplinkBitRate = in.readLong();
+
+ final int size = in.readInt();
+ final List<InetSocketAddress> remoteAddresses = new ArrayList<>(size);
+ for (int i = 0; i < size; i++) {
+ final byte[] addressBytes = in.createByteArray();
+ final int port = in.readInt();
+ try {
+ remoteAddresses.add(
+ new InetSocketAddress(InetAddress.getByAddress(addressBytes), port));
+ } catch (final UnknownHostException e) {
+ // Impossible case since we filter out null values in the ..ctor
+ Log.e(TAG, "unable to unparcel remote address at index: " + i, e);
+ }
+ }
+ mRemoteAddresses = Collections.unmodifiableList(remoteAddresses);
+ }
+
+ /**
+ * Creates attributes based off of a parcel
+ * @param in the parcel
+ * @return the attributes
+ */
+ @NonNull
+ public static EpsBearerQosSessionAttributes create(@NonNull final Parcel in) {
+ return new EpsBearerQosSessionAttributes(in);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull final Parcel dest, final int flags) {
+ dest.writeInt(mQci);
+ dest.writeLong(mMaxDownlinkBitRate);
+ dest.writeLong(mMaxUplinkBitRate);
+ dest.writeLong(mGuaranteedDownlinkBitRate);
+ dest.writeLong(mGuaranteedUplinkBitRate);
+
+ final int size = mRemoteAddresses.size();
+ dest.writeInt(size);
+ for (int i = 0; i < size; i++) {
+ final InetSocketAddress address = mRemoteAddresses.get(i);
+ dest.writeByteArray(address.getAddress().getAddress());
+ dest.writeInt(address.getPort());
+ }
+ }
+
+ @NonNull
+ public static final Creator<EpsBearerQosSessionAttributes> CREATOR =
+ new Creator<EpsBearerQosSessionAttributes>() {
+ @NonNull
+ @Override
+ public EpsBearerQosSessionAttributes createFromParcel(@NonNull final Parcel in) {
+ return new EpsBearerQosSessionAttributes(in);
+ }
+
+ @NonNull
+ @Override
+ public EpsBearerQosSessionAttributes[] newArray(final int size) {
+ return new EpsBearerQosSessionAttributes[size];
+ }
+ };
+}
diff --git a/telephony/java/android/telephony/ims/RegistrationManager.java b/telephony/java/android/telephony/ims/RegistrationManager.java
index e085dec..2c75368 100644
--- a/telephony/java/android/telephony/ims/RegistrationManager.java
+++ b/telephony/java/android/telephony/ims/RegistrationManager.java
@@ -25,6 +25,7 @@
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 @@
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/android/telephony/ims/SipMessage.java b/telephony/java/android/telephony/ims/SipMessage.java
index 006cca8..9cfa640 100644
--- a/telephony/java/android/telephony/ims/SipMessage.java
+++ b/telephony/java/android/telephony/ims/SipMessage.java
@@ -16,6 +16,8 @@
package android.telephony.ims;
+import static java.nio.charset.StandardCharsets.UTF_8;
+
import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.os.Build;
@@ -39,6 +41,7 @@
public final class SipMessage implements Parcelable {
// Should not be set to true for production!
private static final boolean IS_DEBUGGING = Build.IS_ENG;
+ private static final String CRLF = "\r\n";
private final String mStartLine;
private final String mHeaderSection;
@@ -165,4 +168,19 @@
result = 31 * result + Arrays.hashCode(mContent);
return result;
}
+
+ /**
+ * @return the UTF-8 encoded SIP message.
+ */
+ public @NonNull byte[] getEncodedMessage() {
+ byte[] header = new StringBuilder()
+ .append(mStartLine)
+ .append(mHeaderSection)
+ .append(CRLF)
+ .toString().getBytes(UTF_8);
+ byte[] sipMessage = new byte[header.length + mContent.length];
+ System.arraycopy(header, 0, sipMessage, 0, header.length);
+ System.arraycopy(mContent, 0, sipMessage, header.length, mContent.length);
+ return sipMessage;
+ }
}
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 541ec04..e556664 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.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;
@@ -2279,6 +2280,14 @@
CarrierBandwidth getCarrierBandwidth(int subId);
/**
+ * Checks whether the device supports the given capability on the radio interface.
+ *
+ * @param capability the name of the capability
+ * @return the availability of the capability
+ */
+ boolean isRadioInterfaceCapabilitySupported(String capability);
+
+ /**
* Thermal mitigation request to control functionalities at modem.
*
* @param subId the id of the subscription
@@ -2358,6 +2367,11 @@
boolean setCarrierSingleRegistrationEnabledOverride(int subId, String enabled);
/**
+ * Sends a device to device message; only for use through shell.
+ */
+ void sendDeviceToDeviceMessage(int message, int value);
+
+ /**
* Gets the config of RCS VoLTE single registration enabled for the carrier/subscription.
*/
boolean getCarrierSingleRegistrationEnabled(int subId);
@@ -2367,4 +2381,17 @@
* 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/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index 52f263f..76243a5 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -520,6 +520,7 @@
int RIL_REQUEST_START_HANDOVER = 217;
int RIL_REQUEST_CANCEL_HANDOVER = 218;
int RIL_REQUEST_GET_SYSTEM_SELECTION_CHANNELS = 219;
+ int RIL_REQUEST_GET_HAL_DEVICE_CAPABILITIES = 220;
int RIL_REQUEST_SET_DATA_THROTTLING = 221;
int RIL_REQUEST_SET_ALLOWED_NETWORK_TYPE_BITMAP = 222;
int RIL_REQUEST_GET_ALLOWED_NETWORK_TYPE_BITMAP = 223;
diff --git a/test-mock/api/current.txt b/test-mock/api/current.txt
index 1110790..d1a68d4 100644
--- a/test-mock/api/current.txt
+++ b/test-mock/api/current.txt
@@ -117,6 +117,7 @@
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 cf3b03c..6046d78 100644
--- a/test-mock/src/android/test/mock/MockContext.java
+++ b/test-mock/src/android/test/mock/MockContext.java
@@ -493,6 +493,11 @@
}
@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 2cb16d3372..b2bcfeb 100644
--- a/tests/net/common/java/android/net/CaptivePortalDataTest.kt
+++ b/tests/net/common/java/android/net/CaptivePortalDataTest.kt
@@ -58,7 +58,8 @@
@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/integration/util/com/android/server/NetworkAgentWrapper.java b/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java
index 3d4dc4d..dc9e587 100644
--- a/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java
+++ b/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java
@@ -31,6 +31,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
+import android.annotation.NonNull;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.LinkProperties;
@@ -40,6 +41,7 @@
import android.net.NetworkCapabilities;
import android.net.NetworkProvider;
import android.net.NetworkSpecifier;
+import android.net.QosFilter;
import android.net.SocketKeepalive;
import android.net.UidRange;
import android.os.ConditionVariable;
@@ -47,10 +49,12 @@
import android.os.Message;
import android.util.Log;
+import com.android.net.module.util.ArrayTrackRecord;
import com.android.server.connectivity.ConnectivityConstants;
import com.android.testutils.HandlerUtils;
import com.android.testutils.TestableNetworkCallback;
+import java.util.Objects;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -71,6 +75,8 @@
// start/stop. Useful when simulate KeepaliveTracker is waiting for response from modem.
private long mKeepaliveResponseDelay = 0L;
private Integer mExpectedKeepaliveSlot = null;
+ private final ArrayTrackRecord<CallbackType>.ReadHead mCallbackHistory =
+ new ArrayTrackRecord<CallbackType>().newReadHead();
public NetworkAgentWrapper(int transport, LinkProperties linkProperties,
NetworkCapabilities ncTemplate, Context context) throws Exception {
@@ -157,6 +163,20 @@
}
@Override
+ public void onQosCallbackRegistered(final int qosCallbackId,
+ final @NonNull QosFilter filter) {
+ Log.i(mWrapper.mLogTag, "onQosCallbackRegistered");
+ mWrapper.mCallbackHistory.add(
+ new CallbackType.OnQosCallbackRegister(qosCallbackId, filter));
+ }
+
+ @Override
+ public void onQosCallbackUnregistered(final int qosCallbackId) {
+ Log.i(mWrapper.mLogTag, "onQosCallbackUnregistered");
+ mWrapper.mCallbackHistory.add(new CallbackType.OnQosCallbackUnregister(qosCallbackId));
+ }
+
+ @Override
protected void preventAutomaticReconnect() {
mWrapper.mPreventReconnectReceived.open();
}
@@ -279,7 +299,60 @@
return mNetworkCapabilities;
}
+ public @NonNull ArrayTrackRecord<CallbackType>.ReadHead getCallbackHistory() {
+ return mCallbackHistory;
+ }
+
public void waitForIdle(long timeoutMs) {
HandlerUtils.waitForIdle(mHandlerThread, timeoutMs);
}
+
+ abstract static class CallbackType {
+ final int mQosCallbackId;
+
+ protected CallbackType(final int qosCallbackId) {
+ mQosCallbackId = qosCallbackId;
+ }
+
+ static class OnQosCallbackRegister extends CallbackType {
+ final QosFilter mFilter;
+ OnQosCallbackRegister(final int qosCallbackId, final QosFilter filter) {
+ super(qosCallbackId);
+ mFilter = filter;
+ }
+
+ @Override
+ public boolean equals(final Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ final OnQosCallbackRegister that = (OnQosCallbackRegister) o;
+ return mQosCallbackId == that.mQosCallbackId
+ && Objects.equals(mFilter, that.mFilter);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mQosCallbackId, mFilter);
+ }
+ }
+
+ static class OnQosCallbackUnregister extends CallbackType {
+ OnQosCallbackUnregister(final int qosCallbackId) {
+ super(qosCallbackId);
+ }
+
+ @Override
+ public boolean equals(final Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ final OnQosCallbackUnregister that = (OnQosCallbackUnregister) o;
+ return mQosCallbackId == that.mQosCallbackId;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mQosCallbackId);
+ }
+ }
+ }
}
diff --git a/tests/net/java/android/net/QosSocketFilterTest.java b/tests/net/java/android/net/QosSocketFilterTest.java
new file mode 100644
index 0000000..ad58960
--- /dev/null
+++ b/tests/net/java/android/net/QosSocketFilterTest.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+
+@RunWith(AndroidJUnit4.class)
+@androidx.test.filters.SmallTest
+public class QosSocketFilterTest {
+
+ @Test
+ public void testPortExactMatch() {
+ final InetAddress addressA = InetAddresses.parseNumericAddress("1.2.3.4");
+ final InetAddress addressB = InetAddresses.parseNumericAddress("1.2.3.4");
+ assertTrue(QosSocketFilter.matchesLocalAddress(
+ new InetSocketAddress(addressA, 10), addressB, 10, 10));
+
+ }
+
+ @Test
+ public void testPortLessThanStart() {
+ final InetAddress addressA = InetAddresses.parseNumericAddress("1.2.3.4");
+ final InetAddress addressB = InetAddresses.parseNumericAddress("1.2.3.4");
+ assertFalse(QosSocketFilter.matchesLocalAddress(
+ new InetSocketAddress(addressA, 8), addressB, 10, 10));
+ }
+
+ @Test
+ public void testPortGreaterThanEnd() {
+ final InetAddress addressA = InetAddresses.parseNumericAddress("1.2.3.4");
+ final InetAddress addressB = InetAddresses.parseNumericAddress("1.2.3.4");
+ assertFalse(QosSocketFilter.matchesLocalAddress(
+ new InetSocketAddress(addressA, 18), addressB, 10, 10));
+ }
+
+ @Test
+ public void testPortBetweenStartAndEnd() {
+ final InetAddress addressA = InetAddresses.parseNumericAddress("1.2.3.4");
+ final InetAddress addressB = InetAddresses.parseNumericAddress("1.2.3.4");
+ assertTrue(QosSocketFilter.matchesLocalAddress(
+ new InetSocketAddress(addressA, 10), addressB, 8, 18));
+ }
+
+ @Test
+ public void testAddressesDontMatch() {
+ final InetAddress addressA = InetAddresses.parseNumericAddress("1.2.3.4");
+ final InetAddress addressB = InetAddresses.parseNumericAddress("1.2.3.5");
+ assertFalse(QosSocketFilter.matchesLocalAddress(
+ new InetSocketAddress(addressA, 10), addressB, 10, 10));
+ }
+}
+
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 5a375d2..f893e9e 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -167,6 +167,7 @@
import android.net.INetworkMonitorCallbacks;
import android.net.INetworkPolicyListener;
import android.net.INetworkStatsService;
+import android.net.IQosCallback;
import android.net.InetAddresses;
import android.net.InterfaceConfigurationParcel;
import android.net.IpPrefix;
@@ -190,6 +191,9 @@
import android.net.NetworkState;
import android.net.NetworkTestResultParcelable;
import android.net.ProxyInfo;
+import android.net.QosCallbackException;
+import android.net.QosFilter;
+import android.net.QosSession;
import android.net.ResolverParamsParcel;
import android.net.RouteInfo;
import android.net.RouteInfoParcel;
@@ -218,6 +222,7 @@
import android.os.Parcelable;
import android.os.Process;
import android.os.RemoteException;
+import android.os.ServiceSpecificException;
import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserManager;
@@ -226,10 +231,12 @@
import android.security.KeyStore;
import android.system.Os;
import android.telephony.TelephonyManager;
+import android.telephony.data.EpsBearerQosSessionAttributes;
import android.test.mock.MockContentResolver;
import android.text.TextUtils;
import android.util.ArraySet;
import android.util.Log;
+import android.util.Pair;
import android.util.SparseArray;
import androidx.test.InstrumentationRegistry;
@@ -251,6 +258,7 @@
import com.android.server.connectivity.NetworkAgentInfo;
import com.android.server.connectivity.NetworkNotificationManager.NotificationType;
import com.android.server.connectivity.ProxyTracker;
+import com.android.server.connectivity.QosCallbackTracker;
import com.android.server.connectivity.Vpn;
import com.android.server.net.NetworkPinner;
import com.android.server.net.NetworkPolicyManagerInternal;
@@ -368,6 +376,8 @@
private WrappedMultinetworkPolicyTracker mPolicyTracker;
private HandlerThread mAlarmManagerThread;
private TestNetIdManager mNetIdManager;
+ private QosCallbackMockHelper mQosCallbackMockHelper;
+ private QosCallbackTracker mQosCallbackTracker;
@Mock DeviceIdleInternal mDeviceIdleInternal;
@Mock INetworkManagementService mNetworkManagementService;
@@ -1389,15 +1399,13 @@
verify(mNetworkPolicyManager).registerListener(policyListenerCaptor.capture());
mPolicyListener = policyListenerCaptor.getValue();
- mServiceContext.setPermission(
- Manifest.permission.CONTROL_VPN, PERMISSION_GRANTED);
-
// Create local CM before sending system ready so that we can answer
// getSystemService() correctly.
mCm = new WrappedConnectivityManager(InstrumentationRegistry.getContext(), mService);
mService.systemReadyInternal();
mockVpn(Process.myUid());
mCm.bindProcessToNetwork(null);
+ mQosCallbackTracker = mock(QosCallbackTracker.class);
// Ensure that the default setting for Captive Portals is used for most tests
setCaptivePortalMode(Settings.Global.CAPTIVE_PORTAL_MODE_PROMPT);
@@ -1473,6 +1481,11 @@
mEthernetNetworkAgent.disconnect();
mEthernetNetworkAgent = null;
}
+
+ if (mQosCallbackMockHelper != null) {
+ mQosCallbackMockHelper.tearDown();
+ mQosCallbackMockHelper = null;
+ }
mMockVpn.disconnect();
waitForIdle();
@@ -1588,6 +1601,7 @@
}
public void expectNoBroadcast(int timeoutMs) throws Exception {
+ waitForIdle();
try {
final Intent intent = get(timeoutMs, TimeUnit.MILLISECONDS);
fail("Unexpected broadcast: " + intent.getAction() + " " + intent.getExtras());
@@ -4381,7 +4395,7 @@
}
private Network connectKeepaliveNetwork(LinkProperties lp) throws Exception {
- // Ensure the network is disconnected before we do anything.
+ // Ensure the network is disconnected before anything else occurs
if (mWiFiNetworkAgent != null) {
assertNull(mCm.getNetworkCapabilities(mWiFiNetworkAgent.getNetwork()));
}
@@ -5894,6 +5908,131 @@
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();
@@ -6450,9 +6589,13 @@
@Test
public void testLockdownVpnWithRestrictedProfiles() throws Exception {
- // NETWORK_SETTINGS is necessary to see the UID ranges in NetworkCapabilities.
+ // 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);
@@ -7015,6 +7158,9 @@
@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);
@@ -7132,11 +7278,14 @@
mMockVpn.expectStopVpnRunnerPrivileged();
mMockVpn.expectStartLegacyVpnRunner();
- // TODO: why is wifi not blocked? Is this because something calls prepare()?
+ // 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));
- defaultCallback.expectCapabilitiesThat(mMockVpn, (nc) -> nc.hasTransport(TRANSPORT_WIFI));
+ 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);
@@ -7179,7 +7328,7 @@
mWiFiNetworkAgent.disconnect();
callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
b1.expectBroadcast();
- callback.expectCapabilitiesThat(mMockVpn, (nc) -> !nc.hasTransport(TRANSPORT_WIFI));
+ callback.expectCapabilitiesThat(mMockVpn, nc -> !nc.hasTransport(TRANSPORT_WIFI));
b2 = expectConnectivityAction(TYPE_VPN, DetailedState.DISCONNECTED);
mMockVpn.expectStopVpnRunnerPrivileged();
callback.expectCallback(CallbackEntry.LOST, mMockVpn);
@@ -8379,7 +8528,7 @@
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);
+ 0, INVALID_UID, mQosCallbackTracker);
}
@Test
@@ -8757,7 +8906,7 @@
@Test
public void testInvalidRequestTypes() {
- final int[] invalidReqTypeInts = new int[] {-1, NetworkRequest.Type.NONE.ordinal(),
+ final int[] invalidReqTypeInts = new int[]{-1, NetworkRequest.Type.NONE.ordinal(),
NetworkRequest.Type.LISTEN.ordinal(), NetworkRequest.Type.values().length};
final NetworkCapabilities nc = new NetworkCapabilities().addTransportType(TRANSPORT_WIFI);
@@ -8770,4 +8919,151 @@
);
}
}
+
+ private class QosCallbackMockHelper {
+ @NonNull public final QosFilter mFilter;
+ @NonNull public final IQosCallback mCallback;
+ @NonNull public final TestNetworkAgentWrapper mAgentWrapper;
+ @NonNull private final List<IQosCallback> mCallbacks = new ArrayList();
+
+ QosCallbackMockHelper() throws Exception {
+ Log.d(TAG, "QosCallbackMockHelper: ");
+ mFilter = mock(QosFilter.class);
+
+ // Ensure the network is disconnected before anything else occurs
+ assertNull(mCellNetworkAgent);
+
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
+ mCellNetworkAgent.connect(true);
+
+ verifyActiveNetwork(TRANSPORT_CELLULAR);
+ waitForIdle();
+ final Network network = mCellNetworkAgent.getNetwork();
+
+ final Pair<IQosCallback, IBinder> pair = createQosCallback();
+ mCallback = pair.first;
+
+ when(mFilter.getNetwork()).thenReturn(network);
+ when(mFilter.validate()).thenReturn(QosCallbackException.EX_TYPE_FILTER_NONE);
+ mAgentWrapper = mCellNetworkAgent;
+ }
+
+ void registerQosCallback(@NonNull final QosFilter filter,
+ @NonNull final IQosCallback callback) {
+ mCallbacks.add(callback);
+ final NetworkAgentInfo nai =
+ mService.getNetworkAgentInfoForNetwork(filter.getNetwork());
+ mService.registerQosCallbackInternal(filter, callback, nai);
+ }
+
+ void tearDown() {
+ for (int i = 0; i < mCallbacks.size(); i++) {
+ mService.unregisterQosCallback(mCallbacks.get(i));
+ }
+ }
+ }
+
+ private Pair<IQosCallback, IBinder> createQosCallback() {
+ final IQosCallback callback = mock(IQosCallback.class);
+ final IBinder binder = mock(Binder.class);
+ when(callback.asBinder()).thenReturn(binder);
+ when(binder.isBinderAlive()).thenReturn(true);
+ return new Pair<>(callback, binder);
+ }
+
+
+ @Test
+ public void testQosCallbackRegistration() throws Exception {
+ mQosCallbackMockHelper = new QosCallbackMockHelper();
+ final NetworkAgentWrapper wrapper = mQosCallbackMockHelper.mAgentWrapper;
+
+ when(mQosCallbackMockHelper.mFilter.validate())
+ .thenReturn(QosCallbackException.EX_TYPE_FILTER_NONE);
+ mQosCallbackMockHelper.registerQosCallback(
+ mQosCallbackMockHelper.mFilter, mQosCallbackMockHelper.mCallback);
+
+ final NetworkAgentWrapper.CallbackType.OnQosCallbackRegister cbRegister1 =
+ (NetworkAgentWrapper.CallbackType.OnQosCallbackRegister)
+ wrapper.getCallbackHistory().poll(1000, x -> true);
+ assertNotNull(cbRegister1);
+
+ final int registerCallbackId = cbRegister1.mQosCallbackId;
+ mService.unregisterQosCallback(mQosCallbackMockHelper.mCallback);
+ final NetworkAgentWrapper.CallbackType.OnQosCallbackUnregister cbUnregister;
+ cbUnregister = (NetworkAgentWrapper.CallbackType.OnQosCallbackUnregister)
+ wrapper.getCallbackHistory().poll(1000, x -> true);
+ assertNotNull(cbUnregister);
+ assertEquals(registerCallbackId, cbUnregister.mQosCallbackId);
+ assertNull(wrapper.getCallbackHistory().poll(200, x -> true));
+ }
+
+ @Test
+ public void testQosCallbackNoRegistrationOnValidationError() throws Exception {
+ mQosCallbackMockHelper = new QosCallbackMockHelper();
+
+ when(mQosCallbackMockHelper.mFilter.validate())
+ .thenReturn(QosCallbackException.EX_TYPE_FILTER_NETWORK_RELEASED);
+ mQosCallbackMockHelper.registerQosCallback(
+ mQosCallbackMockHelper.mFilter, mQosCallbackMockHelper.mCallback);
+ waitForIdle();
+ verify(mQosCallbackMockHelper.mCallback)
+ .onError(eq(QosCallbackException.EX_TYPE_FILTER_NETWORK_RELEASED));
+ }
+
+ @Test
+ public void testQosCallbackAvailableAndLost() throws Exception {
+ mQosCallbackMockHelper = new QosCallbackMockHelper();
+ final int sessionId = 10;
+ final int qosCallbackId = 1;
+
+ when(mQosCallbackMockHelper.mFilter.validate())
+ .thenReturn(QosCallbackException.EX_TYPE_FILTER_NONE);
+ mQosCallbackMockHelper.registerQosCallback(
+ mQosCallbackMockHelper.mFilter, mQosCallbackMockHelper.mCallback);
+ waitForIdle();
+
+ final EpsBearerQosSessionAttributes attributes = new EpsBearerQosSessionAttributes(
+ 1, 2, 3, 4, 5, new ArrayList<>());
+ mQosCallbackMockHelper.mAgentWrapper.getNetworkAgent()
+ .sendQosSessionAvailable(qosCallbackId, sessionId, attributes);
+ waitForIdle();
+
+ verify(mQosCallbackMockHelper.mCallback).onQosEpsBearerSessionAvailable(argThat(session ->
+ session.getSessionId() == sessionId
+ && session.getSessionType() == QosSession.TYPE_EPS_BEARER), eq(attributes));
+
+ mQosCallbackMockHelper.mAgentWrapper.getNetworkAgent()
+ .sendQosSessionLost(qosCallbackId, sessionId);
+ waitForIdle();
+ verify(mQosCallbackMockHelper.mCallback).onQosSessionLost(argThat(session ->
+ session.getSessionId() == sessionId
+ && session.getSessionType() == QosSession.TYPE_EPS_BEARER));
+ }
+
+ @Test
+ public void testQosCallbackTooManyRequests() throws Exception {
+ mQosCallbackMockHelper = new QosCallbackMockHelper();
+
+ when(mQosCallbackMockHelper.mFilter.validate())
+ .thenReturn(QosCallbackException.EX_TYPE_FILTER_NONE);
+ for (int i = 0; i < 100; i++) {
+ final Pair<IQosCallback, IBinder> pair = createQosCallback();
+
+ try {
+ mQosCallbackMockHelper.registerQosCallback(
+ mQosCallbackMockHelper.mFilter, pair.first);
+ } catch (ServiceSpecificException e) {
+ assertEquals(e.errorCode, ConnectivityManager.Errors.TOO_MANY_REQUESTS);
+ if (i < 50) {
+ fail("TOO_MANY_REQUESTS thrown too early, the count is " + i);
+ }
+
+ // As long as there is at least 50 requests, it is safe to assume it works.
+ // Note: The count isn't being tested precisely against 100 because the counter
+ // is shared with request network.
+ return;
+ }
+ }
+ fail("TOO_MANY_REQUESTS never thrown");
+ }
}
diff --git a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
index 4d151af..52cb836 100644
--- a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
@@ -78,6 +78,7 @@
@Mock Context mCtx;
@Mock NetworkNotificationManager mNotifier;
@Mock Resources mResources;
+ @Mock QosCallbackTracker mQosCallbackTracker;
@Before
public void setUp() {
@@ -358,7 +359,7 @@
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());
+ Binder.getCallingUid(), mQosCallbackTracker);
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 25bd7c0..1102624 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.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 @@
}
@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 3c08d34..c04ddd7 100644
--- a/tests/vcn/Android.bp
+++ b/tests/vcn/Android.bp
@@ -16,6 +16,7 @@
"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 0000000..9c6b719
--- /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 0000000..3ba0a1f
--- /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);
+ }
+}
diff --git a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
index 696110f..f0cdde3 100644
--- a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
+++ b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
@@ -18,15 +18,21 @@
import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionTrackerCallback;
+import static com.android.server.vcn.VcnTestUtils.setupSystemService;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.argThat;
import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -35,8 +41,10 @@
import android.app.AppOpsManager;
import android.content.Context;
import android.net.ConnectivityManager;
+import android.net.vcn.IVcnUnderlyingNetworkPolicyListener;
import android.net.vcn.VcnConfig;
import android.net.vcn.VcnConfigTest;
+import android.os.IBinder;
import android.os.ParcelUuid;
import android.os.PersistableBundle;
import android.os.Process;
@@ -126,12 +134,21 @@
private final VcnManagementService mVcnMgmtSvc;
+ private final IVcnUnderlyingNetworkPolicyListener mMockPolicyListener =
+ mock(IVcnUnderlyingNetworkPolicyListener.class);
+ private final IBinder mMockIBinder = mock(IBinder.class);
+
public VcnManagementServiceTest() throws Exception {
- setupSystemService(mConnMgr, Context.CONNECTIVITY_SERVICE, ConnectivityManager.class);
- setupSystemService(mTelMgr, Context.TELEPHONY_SERVICE, TelephonyManager.class);
setupSystemService(
- mSubMgr, Context.TELEPHONY_SUBSCRIPTION_SERVICE, SubscriptionManager.class);
- setupSystemService(mAppOpsMgr, Context.APP_OPS_SERVICE, AppOpsManager.class);
+ mMockContext, mConnMgr, Context.CONNECTIVITY_SERVICE, ConnectivityManager.class);
+ setupSystemService(
+ mMockContext, mTelMgr, Context.TELEPHONY_SERVICE, TelephonyManager.class);
+ setupSystemService(
+ mMockContext,
+ mSubMgr,
+ Context.TELEPHONY_SUBSCRIPTION_SERVICE,
+ SubscriptionManager.class);
+ setupSystemService(mMockContext, mAppOpsMgr, Context.APP_OPS_SERVICE, AppOpsManager.class);
doReturn(TEST_PACKAGE_NAME).when(mMockContext).getOpPackageName();
@@ -169,15 +186,12 @@
setupMockedCarrierPrivilege(true);
mVcnMgmtSvc = new VcnManagementService(mMockContext, mMockDeps);
+ doReturn(mMockIBinder).when(mMockPolicyListener).asBinder();
+
// Make sure the profiles are loaded.
mTestLooper.dispatchAll();
}
- private void setupSystemService(Object service, String name, Class<?> serviceClass) {
- doReturn(name).when(mMockContext).getSystemServiceName(serviceClass);
- doReturn(service).when(mMockContext).getSystemService(name);
- }
-
private void setupMockedCarrierPrivilege(boolean isPrivileged) {
doReturn(Collections.singletonList(TEST_SUBSCRIPTION_INFO))
.when(mSubMgr)
@@ -438,4 +452,40 @@
mVcnMgmtSvc.clearVcnConfig(TEST_UUID_2);
verify(vcnInstance).teardownAsynchronously();
}
+
+ @Test
+ public void testAddVcnUnderlyingNetworkPolicyListener() throws Exception {
+ doNothing()
+ .when(mMockContext)
+ .enforceCallingPermission(eq(android.Manifest.permission.NETWORK_FACTORY), any());
+
+ mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
+
+ verify(mMockIBinder).linkToDeath(any(), anyInt());
+ }
+
+ @Test(expected = SecurityException.class)
+ public void testAddVcnUnderlyingNetworkPolicyListenerInvalidPermission() {
+ doThrow(new SecurityException())
+ .when(mMockContext)
+ .enforceCallingPermission(eq(android.Manifest.permission.NETWORK_FACTORY), any());
+
+ mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
+ }
+
+ @Test
+ public void testRemoveVcnUnderlyingNetworkPolicyListener() {
+ // verify listener added
+ doNothing()
+ .when(mMockContext)
+ .enforceCallingPermission(eq(android.Manifest.permission.NETWORK_FACTORY), any());
+ mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
+
+ mVcnMgmtSvc.removeVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
+ }
+
+ @Test
+ public void testRemoveVcnUnderlyingNetworkPolicyListenerNeverRegistered() {
+ mVcnMgmtSvc.removeVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
+ }
}
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java
new file mode 100644
index 0000000..4ecd215
--- /dev/null
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java
@@ -0,0 +1,84 @@
+/*
+ * 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.vcn;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/** Tests for VcnGatewayConnection.DisconnectedState */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class VcnGatewayConnectionDisconnectedStateTest extends VcnGatewayConnectionTestBase {
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+
+ mGatewayConnection.transitionTo(mGatewayConnection.mDisconnectedState);
+ mTestLooper.dispatchAll();
+ }
+
+ @Test
+ public void testEnterWhileNotRunningTriggersQuit() throws Exception {
+ final VcnGatewayConnection vgc =
+ new VcnGatewayConnection(mVcnContext, TEST_SUB_GRP, mConfig, mDeps);
+
+ vgc.setIsRunning(false);
+ vgc.transitionTo(vgc.mDisconnectedState);
+ mTestLooper.dispatchAll();
+
+ assertNull(vgc.getCurrentState());
+ }
+
+ @Test
+ public void testNetworkChangesTriggerStateTransitions() throws Exception {
+ mGatewayConnection
+ .getUnderlyingNetworkTrackerCallback()
+ .onSelectedUnderlyingNetworkChanged(TEST_UNDERLYING_NETWORK_RECORD_1);
+ mTestLooper.dispatchAll();
+
+ assertEquals(mGatewayConnection.mConnectingState, mGatewayConnection.getCurrentState());
+ }
+
+ @Test
+ public void testNullNetworkDoesNotTriggerStateTransition() throws Exception {
+ mGatewayConnection
+ .getUnderlyingNetworkTrackerCallback()
+ .onSelectedUnderlyingNetworkChanged(null);
+ mTestLooper.dispatchAll();
+
+ assertEquals(mGatewayConnection.mDisconnectedState, mGatewayConnection.getCurrentState());
+ }
+
+ @Test
+ public void testTeardown() throws Exception {
+ mGatewayConnection.teardownAsynchronously();
+ mTestLooper.dispatchAll();
+
+ assertNull(mGatewayConnection.getCurrentState());
+ verify(mIpSecSvc).deleteTunnelInterface(eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), any());
+ }
+}
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
new file mode 100644
index 0000000..1725dd9
--- /dev/null
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.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 com.android.server.vcn;
+
+import static com.android.server.vcn.UnderlyingNetworkTracker.UnderlyingNetworkRecord;
+import static com.android.server.vcn.VcnTestUtils.setupIpSecManager;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.net.IpSecManager;
+import android.net.IpSecTunnelInterfaceResponse;
+import android.net.LinkProperties;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.net.vcn.VcnGatewayConnectionConfig;
+import android.net.vcn.VcnGatewayConnectionConfigTest;
+import android.os.ParcelUuid;
+import android.os.test.TestLooper;
+
+import com.android.server.IpSecService;
+
+import org.junit.Before;
+
+import java.util.UUID;
+
+public class VcnGatewayConnectionTestBase {
+ protected static final ParcelUuid TEST_SUB_GRP = new ParcelUuid(UUID.randomUUID());
+ protected static final int TEST_IPSEC_TUNNEL_RESOURCE_ID = 1;
+ protected static final String TEST_IPSEC_TUNNEL_IFACE = "IPSEC_IFACE";
+ protected static final UnderlyingNetworkRecord TEST_UNDERLYING_NETWORK_RECORD_1 =
+ new UnderlyingNetworkRecord(
+ new Network(0),
+ new NetworkCapabilities(),
+ new LinkProperties(),
+ false /* blocked */);
+ protected static final UnderlyingNetworkRecord TEST_UNDERLYING_NETWORK_RECORD_2 =
+ new UnderlyingNetworkRecord(
+ new Network(1),
+ new NetworkCapabilities(),
+ new LinkProperties(),
+ false /* blocked */);
+
+ @NonNull protected final Context mContext;
+ @NonNull protected final TestLooper mTestLooper;
+ @NonNull protected final VcnNetworkProvider mVcnNetworkProvider;
+ @NonNull protected final VcnContext mVcnContext;
+ @NonNull protected final VcnGatewayConnectionConfig mConfig;
+ @NonNull protected final VcnGatewayConnection.Dependencies mDeps;
+ @NonNull protected final UnderlyingNetworkTracker mUnderlyingNetworkTracker;
+
+ @NonNull protected final IpSecService mIpSecSvc;
+
+ protected VcnGatewayConnection mGatewayConnection;
+
+ public VcnGatewayConnectionTestBase() {
+ mContext = mock(Context.class);
+ mTestLooper = new TestLooper();
+ mVcnNetworkProvider = mock(VcnNetworkProvider.class);
+ mVcnContext = mock(VcnContext.class);
+ mConfig = VcnGatewayConnectionConfigTest.buildTestConfig();
+ mDeps = mock(VcnGatewayConnection.Dependencies.class);
+ mUnderlyingNetworkTracker = mock(UnderlyingNetworkTracker.class);
+
+ mIpSecSvc = mock(IpSecService.class);
+ setupIpSecManager(mContext, mIpSecSvc);
+
+ doReturn(mContext).when(mVcnContext).getContext();
+ doReturn(mTestLooper.getLooper()).when(mVcnContext).getLooper();
+ doReturn(mVcnNetworkProvider).when(mVcnContext).getVcnNetworkProvider();
+
+ doReturn(mUnderlyingNetworkTracker)
+ .when(mDeps)
+ .newUnderlyingNetworkTracker(any(), any(), any());
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ IpSecTunnelInterfaceResponse resp =
+ new IpSecTunnelInterfaceResponse(
+ IpSecManager.Status.OK,
+ TEST_IPSEC_TUNNEL_RESOURCE_ID,
+ TEST_IPSEC_TUNNEL_IFACE);
+ doReturn(resp).when(mIpSecSvc).createTunnelInterface(any(), any(), any(), any(), any());
+
+ mGatewayConnection = new VcnGatewayConnection(mVcnContext, TEST_SUB_GRP, mConfig, mDeps);
+ }
+}
diff --git a/tests/vcn/java/com/android/server/vcn/VcnTestUtils.java b/tests/vcn/java/com/android/server/vcn/VcnTestUtils.java
new file mode 100644
index 0000000..2b10806
--- /dev/null
+++ b/tests/vcn/java/com/android/server/vcn/VcnTestUtils.java
@@ -0,0 +1,44 @@
+/*
+ * 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.vcn;
+
+import static org.mockito.Mockito.doReturn;
+
+import android.content.Context;
+import android.net.IpSecManager;
+
+import com.android.server.IpSecService;
+
+public class VcnTestUtils {
+ /** Mock system services by directly mocking the *Manager interface. */
+ public static void setupSystemService(
+ Context mockContext, Object service, String name, Class<?> serviceClass) {
+ doReturn(name).when(mockContext).getSystemServiceName(serviceClass);
+ doReturn(service).when(mockContext).getSystemService(name);
+ }
+
+ /** Mock IpSecService by mocking the underlying service binder. */
+ public static IpSecManager setupIpSecManager(Context mockContext, IpSecService service) {
+ doReturn(Context.IPSEC_SERVICE).when(mockContext).getSystemServiceName(IpSecManager.class);
+
+ final IpSecManager ipSecMgr = new IpSecManager(mockContext, service);
+ doReturn(ipSecMgr).when(mockContext).getSystemService(Context.IPSEC_SERVICE);
+
+ // Return to ensure this doesn't get reaped.
+ return ipSecMgr;
+ }
+}
diff --git a/tools/stringslint/stringslint.py b/tools/stringslint/stringslint.py
index afe91cd..15088fc 100644
--- a/tools/stringslint/stringslint.py
+++ b/tools/stringslint/stringslint.py
@@ -1,4 +1,5 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
+#-*- coding: utf-8 -*-
# Copyright (C) 2018 The Android Open Source Project
#
@@ -33,9 +34,6 @@
import re, sys, codecs
import lxml.etree as ET
-reload(sys)
-sys.setdefaultencoding('utf8')
-
BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = range(8)
def format(fg=None, bg=None, bright=False, bold=False, dim=False, reset=False):
@@ -118,7 +116,7 @@
raw = f.read()
if len(raw.strip()) == 0:
return warnings
- tree = ET.fromstring(raw)
+ tree = ET.fromstring(bytes(raw, encoding='utf-8'))
root = tree #tree.getroot()
last_comment = None
@@ -231,6 +229,6 @@
if len(after) > 0:
for a in sorted(after.keys()):
- print after[a]
- print
+ print(after[a])
+ print()
sys.exit(1)
diff --git a/tools/stringslint/stringslint_sha.sh b/tools/stringslint/stringslint_sha.sh
index bd80bb4..bd05698 100755
--- a/tools/stringslint/stringslint_sha.sh
+++ b/tools/stringslint/stringslint_sha.sh
@@ -1,5 +1,5 @@
#!/bin/bash
LOCAL_DIR="$( dirname ${BASH_SOURCE} )"
git show --name-only --pretty=format: $1 | grep values/strings.xml | while read file; do
- python $LOCAL_DIR/stringslint.py <(git show $1:$file) <(git show $1^:$file)
+ python3 $LOCAL_DIR/stringslint.py <(git show $1:$file) <(git show $1^:$file)
done