summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp3
-rw-r--r--StubLibraries.bp3
-rw-r--r--api/Android.bp7
-rw-r--r--cmds/idmap2/Android.bp15
-rw-r--r--cmds/idmap2/AndroidTest.xml26
-rw-r--r--core/api/current.txt33
-rw-r--r--core/api/module-lib-current.txt9
-rw-r--r--core/api/system-current.txt135
-rw-r--r--core/api/test-current.txt7
-rw-r--r--core/api/test-lint-baseline.txt2
-rw-r--r--core/java/android/accounts/OWNERS1
-rw-r--r--core/java/android/app/AppOpsManager.java24
-rw-r--r--core/java/android/app/SystemServiceRegistry.java11
-rw-r--r--core/java/android/app/compat/CompatChanges.java29
-rw-r--r--core/java/android/app/compat/OWNERS1
-rw-r--r--core/java/android/app/compat/PackageOverride.java211
-rw-r--r--core/java/android/content/ContentResolver.java4
-rw-r--r--core/java/android/content/pm/permission/OWNERS1
-rw-r--r--core/java/android/hardware/location/OWNERS3
-rw-r--r--core/java/android/hardware/usb/OWNERS1
-rw-r--r--core/java/android/net/IIpSecService.aidl3
-rw-r--r--core/java/android/net/IOnSetOemNetworkPreferenceListener.aidl23
-rw-r--r--core/java/android/net/IVpnManager.aidl62
-rw-r--r--core/java/android/net/IpSecManager.java36
-rw-r--r--core/java/android/net/LocalSocketImpl.java12
-rw-r--r--core/java/android/net/NetworkPolicyManager.java11
-rw-r--r--core/java/android/net/OemNetworkPreferences.java24
-rw-r--r--core/java/android/net/VpnManager.java (renamed from packages/Connectivity/framework/src/android/net/VpnManager.java)151
-rw-r--r--core/java/android/net/VpnService.java (renamed from packages/Connectivity/framework/src/android/net/VpnService.java)17
-rw-r--r--core/java/android/net/vcn/VcnManager.java17
-rw-r--r--core/java/android/os/Debug.java30
-rw-r--r--core/java/android/os/ISystemConfig.aidl5
-rw-r--r--core/java/android/os/SystemConfigManager.java18
-rw-r--r--core/java/android/permission/OWNERS1
-rw-r--r--core/java/android/permissionpresenterservice/OWNERS1
-rw-r--r--core/java/android/print/OWNERS1
-rw-r--r--core/java/android/print/pdf/OWNERS1
-rw-r--r--core/java/android/printservice/OWNERS1
-rw-r--r--core/java/android/printservice/recommendation/OWNERS1
-rw-r--r--core/java/com/android/internal/compat/CompatibilityOverrideConfig.aidl19
-rw-r--r--core/java/com/android/internal/compat/CompatibilityOverrideConfig.java75
-rw-r--r--core/java/com/android/internal/compat/IPlatformCompat.aidl12
-rw-r--r--core/jni/Android.bp1
-rw-r--r--core/jni/android_os_Debug.cpp86
-rw-r--r--core/proto/android/net/networkrequest.proto3
-rw-r--r--core/res/AndroidManifest.xml11
-rw-r--r--core/res/res/values/config.xml2
-rw-r--r--core/tests/coretests/src/android/provider/OWNERS1
-rw-r--r--core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java2
-rw-r--r--core/tests/coretests/src/com/android/internal/widget/OWNERS3
-rw-r--r--data/etc/OWNERS1
-rw-r--r--graphics/java/android/graphics/pdf/OWNERS1
-rw-r--r--keystore/java/android/security/AppUriAuthenticationPolicy.aidl (renamed from tools/hiddenapi/Android.bp)17
-rw-r--r--keystore/java/android/security/AppUriAuthenticationPolicy.java241
-rw-r--r--keystore/java/android/security/CredentialManagementApp.java123
-rw-r--r--keystore/java/android/security/Credentials.java2
-rw-r--r--keystore/java/android/security/IKeyChainService.aidl9
-rw-r--r--keystore/java/android/security/KeyChain.java38
-rw-r--r--keystore/java/android/security/KeyStoreSecurityLevel.java2
-rw-r--r--keystore/java/android/security/UrisToAliases.java138
-rw-r--r--keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java70
-rw-r--r--keystore/java/android/security/keystore/AndroidKeyStoreProvider.java12
-rw-r--r--keystore/java/android/security/keystore/ArrayUtils.java8
-rw-r--r--keystore/java/android/security/keystore/KeyGenParameterSpec.java45
-rw-r--r--keystore/java/android/security/keystore/ParcelableKeyGenParameterSpec.java3
-rw-r--r--keystore/java/android/security/keystore/Utils.java4
-rw-r--r--keystore/java/android/security/keystore2/AndroidKeyStoreHmacSpi.java3
-rw-r--r--keystore/java/android/security/keystore2/AndroidKeyStoreKey.java10
-rw-r--r--keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java75
-rw-r--r--keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java3
-rw-r--r--packages/Connectivity/framework/src/android/net/CaptivePortalData.java88
-rw-r--r--packages/Connectivity/framework/src/android/net/ConnectivityFrameworkInitializer.java11
-rw-r--r--packages/Connectivity/framework/src/android/net/ConnectivityManager.java301
-rw-r--r--packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl42
-rw-r--r--packages/Connectivity/framework/src/android/net/NetworkCapabilities.java16
-rw-r--r--packages/Connectivity/framework/src/android/net/NetworkRequest.java91
-rw-r--r--packages/Connectivity/framework/src/android/net/VpnTransportInfo.java89
-rw-r--r--packages/Connectivity/service/Android.bp1
-rw-r--r--packages/Connectivity/service/jni/onload.cpp6
-rw-r--r--packages/PackageInstaller/OWNERS1
-rw-r--r--packages/Shell/AndroidManifest.xml2
-rw-r--r--packages/Shell/OWNERS1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java34
-rw-r--r--services/core/Android.bp4
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java1315
-rw-r--r--services/core/java/com/android/server/EntropyMixer.java51
-rw-r--r--services/core/java/com/android/server/IpSecService.java54
-rw-r--r--services/core/java/com/android/server/VcnManagementService.java17
-rw-r--r--services/core/java/com/android/server/VpnManagerService.java918
-rw-r--r--services/core/java/com/android/server/accounts/OWNERS1
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java123
-rw-r--r--services/core/java/com/android/server/compat/CompatChange.java223
-rw-r--r--services/core/java/com/android/server/compat/CompatConfig.java91
-rw-r--r--services/core/java/com/android/server/compat/PlatformCompat.java30
-rw-r--r--services/core/java/com/android/server/connectivity/IpConnectivityEventBuilder.java34
-rw-r--r--services/core/java/com/android/server/connectivity/NetworkAgentInfo.java3
-rw-r--r--services/core/java/com/android/server/connectivity/NetworkNotificationManager.java27
-rw-r--r--services/core/java/com/android/server/connectivity/QosCallbackTracker.java10
-rw-r--r--services/core/java/com/android/server/connectivity/TcpKeepaliveController.java11
-rw-r--r--services/core/java/com/android/server/connectivity/Vpn.java55
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiControlService.java2
-rw-r--r--services/core/java/com/android/server/locksettings/LockSettingsService.java18
-rw-r--r--services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java34
-rw-r--r--services/core/java/com/android/server/locksettings/RebootEscrowData.java42
-rw-r--r--services/core/java/com/android/server/locksettings/RebootEscrowManager.java83
-rw-r--r--services/core/java/com/android/server/locksettings/RebootEscrowProviderHalImpl.java2
-rw-r--r--services/core/java/com/android/server/locksettings/RebootEscrowProviderInterface.java7
-rw-r--r--services/core/java/com/android/server/locksettings/RebootEscrowProviderServerBasedImpl.java22
-rw-r--r--services/core/java/com/android/server/locksettings/ResumeOnRebootServiceProvider.java21
-rw-r--r--services/core/java/com/android/server/net/LockdownVpnTracker.java192
-rw-r--r--services/core/java/com/android/server/pm/BackgroundDexOptService.java2
-rw-r--r--services/core/java/com/android/server/pm/PackageDexOptimizer.java3
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java30
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java3
-rw-r--r--services/core/java/com/android/server/pm/dex/ArtManagerService.java7
-rw-r--r--services/core/java/com/android/server/pm/parsing/library/AndroidNetIpSecIkeUpdater.java35
-rw-r--r--services/core/java/com/android/server/pm/parsing/library/PackageBackwardCompatibility.java3
-rw-r--r--services/core/java/com/android/server/pm/permission/OWNERS2
-rw-r--r--services/core/java/com/android/server/role/OWNERS1
-rw-r--r--services/core/java/com/android/server/vcn/VcnGatewayConnection.java40
-rw-r--r--services/core/jni/Android.bp1
-rw-r--r--services/core/jni/com_android_server_connectivity_Vpn.cpp (renamed from packages/Connectivity/service/jni/com_android_server_connectivity_Vpn.cpp)0
-rw-r--r--services/core/jni/onload.cpp2
-rw-r--r--services/core/xsd/platform-compat/overrides/platform-compat-overrides.xsd14
-rw-r--r--services/core/xsd/platform-compat/overrides/schema/current.txt19
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java2
-rw-r--r--services/java/com/android/server/SystemConfigService.java20
-rw-r--r--services/java/com/android/server/SystemServer.java20
-rw-r--r--services/tests/servicestests/src/com/android/server/EntropyMixerTest.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/compat/ApplicationInfoBuilder.java7
-rw-r--r--services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java196
-rw-r--r--services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java29
-rw-r--r--services/tests/servicestests/src/com/android/server/locksettings/LockSettingsShellCommandTest.java4
-rw-r--r--services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowDataTest.java47
-rw-r--r--services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java20
-rw-r--r--services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowProviderServerBasedImplTests.java4
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/dex/DexoptOptionsTests.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/parsing/library/AndroidNetIpSecIkeUpdaterTest.java90
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/parsing/library/PackageBackwardCompatibilityTest.java17
-rw-r--r--services/tests/servicestests/test-apps/ConnTestApp/OWNERS1
-rw-r--r--services/usb/OWNERS1
-rwxr-xr-xtelecomm/java/android/telecom/ConnectionService.java2
-rw-r--r--telephony/java/android/telephony/data/IQualifiedNetworksService.aidl4
-rw-r--r--telephony/java/android/telephony/data/QualifiedNetworksService.java12
-rw-r--r--telephony/java/android/telephony/data/ThrottleStatus.aidl (renamed from telephony/java/android/telephony/data/ApnThrottleStatus.aidl)2
-rw-r--r--telephony/java/android/telephony/data/ThrottleStatus.java (renamed from telephony/java/android/telephony/data/ApnThrottleStatus.java)62
-rw-r--r--telephony/java/android/telephony/ims/ImsRcsManager.java275
-rw-r--r--telephony/java/android/telephony/ims/ImsRegistrationAttributes.aidl19
-rw-r--r--telephony/java/android/telephony/ims/ImsRegistrationAttributes.java219
-rw-r--r--telephony/java/android/telephony/ims/RegistrationManager.java68
-rw-r--r--telephony/java/android/telephony/ims/aidl/IImsRcsController.aidl2
-rw-r--r--telephony/java/android/telephony/ims/aidl/IImsRegistrationCallback.aidl5
-rw-r--r--telephony/java/android/telephony/ims/feature/CapabilityChangeRequest.java30
-rw-r--r--telephony/java/android/telephony/ims/feature/RcsFeature.java33
-rw-r--r--telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java82
-rw-r--r--tests/ApkVerityTest/OWNERS3
-rw-r--r--tests/PlatformCompatGating/src/com/android/tests/gating/PlatformCompatCommandNotInstalledTest.kt4
-rw-r--r--tests/net/AndroidManifest.xml1
-rw-r--r--tests/net/common/java/android/net/CaptivePortalDataTest.kt53
-rw-r--r--tests/net/common/java/android/net/OemNetworkPreferencesTest.java6
-rw-r--r--tests/net/integration/util/com/android/server/NetworkAgentWrapper.java2
-rw-r--r--tests/net/java/android/net/ConnectivityManagerTest.java11
-rw-r--r--tests/net/java/android/net/VpnManagerTest.java22
-rw-r--r--tests/net/java/android/net/VpnTransportInfoTest.java49
-rw-r--r--tests/net/java/com/android/server/ConnectivityServiceTest.java342
-rw-r--r--tests/net/java/com/android/server/IpSecServiceParameterizedTest.java152
-rw-r--r--tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java9
-rw-r--r--tests/net/java/com/android/server/connectivity/VpnTest.java15
-rw-r--r--tests/utils/testutils/java/com/android/internal/util/test/BroadcastInterceptingContext.java38
-rw-r--r--tests/vcn/java/android/net/vcn/VcnManagerTest.java6
-rw-r--r--tests/vcn/java/com/android/server/VcnManagementServiceTest.java121
-rw-r--r--tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java11
-rwxr-xr-xtools/hiddenapi/generate_hiddenapi_lists.py383
-rwxr-xr-xtools/hiddenapi/generate_hiddenapi_lists_test.py104
-rwxr-xr-xtools/hiddenapi/merge_csv.py69
175 files changed, 6179 insertions, 2695 deletions
diff --git a/Android.bp b/Android.bp
index 82915b5e753a..2ab33aced0e7 100644
--- a/Android.bp
+++ b/Android.bp
@@ -363,6 +363,7 @@ filegroup {
":framework-statsd-sources",
":framework-tethering-srcs",
":framework-wifi-updatable-sources",
+ ":ike-srcs",
":updatable-media-srcs",
],
visibility: ["//visibility:private"],
@@ -371,6 +372,7 @@ filegroup {
java_library {
name: "framework-updatable-stubs-module_libs_api",
static_libs: [
+ "android.net.ipsec.ike.stubs.module_lib",
"framework-media.stubs.module_lib",
"framework-mediaprovider.stubs.module_lib",
"framework-permission.stubs.module_lib",
@@ -387,6 +389,7 @@ java_library {
name: "framework-all",
installable: false,
static_libs: [
+ "android.net.ipsec.ike.impl",
"framework-minus-apex",
"framework-mediaprovider.impl",
"framework-permission.impl",
diff --git a/StubLibraries.bp b/StubLibraries.bp
index 367b427d8207..6cece60c484c 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -303,6 +303,7 @@ java_library_static {
name: "android_stubs_current",
srcs: [ ":api-stubs-docs-non-updatable" ],
static_libs: [
+ "android.net.ipsec.ike.stubs",
"art.module.public.api.stubs",
"conscrypt.module.public.api.stubs",
"framework-media.stubs",
@@ -322,6 +323,7 @@ java_library_static {
name: "android_system_stubs_current",
srcs: [ ":system-api-stubs-docs-non-updatable" ],
static_libs: [
+ "android.net.ipsec.ike.stubs.system",
"art.module.public.api.stubs",
"conscrypt.module.public.api.stubs",
"framework-media.stubs.system",
@@ -357,6 +359,7 @@ java_library_static {
static_libs: [
// Modules do not have test APIs, but we want to include their SystemApis, like we include
// the SystemApi of framework-non-updatable-sources.
+ "android.net.ipsec.ike.stubs.system",
"art.module.public.api.stubs",
"conscrypt.module.public.api.stubs",
"framework-media.stubs.system",
diff --git a/api/Android.bp b/api/Android.bp
index fdfef4cb8a74..74e021108577 100644
--- a/api/Android.bp
+++ b/api/Android.bp
@@ -28,6 +28,7 @@ genrule {
genrule {
name: "frameworks-base-api-current.txt",
srcs: [
+ ":android.net.ipsec.ike{.public.api.txt}",
":art.module.public.api{.public.api.txt}",
":conscrypt.module.public.api{.public.api.txt}",
":framework-media{.public.api.txt}",
@@ -61,6 +62,7 @@ genrule {
genrule {
name: "frameworks-base-api-current.srcjar",
srcs: [
+ ":android.net.ipsec.ike{.public.stubs.source}",
":api-stubs-docs-non-updatable",
":art.module.public.api{.public.stubs.source}",
":conscrypt.module.public.api{.public.stubs.source}",
@@ -82,6 +84,7 @@ genrule {
genrule {
name: "frameworks-base-api-removed.txt",
srcs: [
+ ":android.net.ipsec.ike{.public.removed-api.txt}",
":art.module.public.api{.public.removed-api.txt}",
":conscrypt.module.public.api{.public.removed-api.txt}",
":framework-media{.public.removed-api.txt}",
@@ -114,6 +117,7 @@ genrule {
genrule {
name: "frameworks-base-api-system-current.txt",
srcs: [
+ ":android.net.ipsec.ike{.system.api.txt}",
":framework-media{.system.api.txt}",
":framework-mediaprovider{.system.api.txt}",
":framework-permission{.system.api.txt}",
@@ -144,6 +148,7 @@ genrule {
genrule {
name: "frameworks-base-api-system-removed.txt",
srcs: [
+ ":android.net.ipsec.ike{.system.removed-api.txt}",
":framework-media{.system.removed-api.txt}",
":framework-mediaprovider{.system.removed-api.txt}",
":framework-permission{.system.removed-api.txt}",
@@ -174,6 +179,7 @@ genrule {
genrule {
name: "frameworks-base-api-module-lib-current.txt",
srcs: [
+ ":android.net.ipsec.ike{.module-lib.api.txt}",
":framework-media{.module-lib.api.txt}",
":framework-mediaprovider{.module-lib.api.txt}",
":framework-permission{.module-lib.api.txt}",
@@ -203,6 +209,7 @@ genrule {
genrule {
name: "frameworks-base-api-module-lib-removed.txt",
srcs: [
+ ":android.net.ipsec.ike{.module-lib.removed-api.txt}",
":framework-media{.module-lib.removed-api.txt}",
":framework-mediaprovider{.module-lib.removed-api.txt}",
":framework-permission{.module-lib.removed-api.txt}",
diff --git a/cmds/idmap2/Android.bp b/cmds/idmap2/Android.bp
index e21a6b288fb3..50f400122fe1 100644
--- a/cmds/idmap2/Android.bp
+++ b/cmds/idmap2/Android.bp
@@ -132,9 +132,6 @@ cc_test {
"tests/XmlParserTests.cpp",
"tests/ZipFileTests.cpp",
],
- required: [
- "idmap2",
- ],
static_libs: ["libgmock"],
target: {
android: {
@@ -163,9 +160,19 @@ cc_test {
shared_libs: [
"libz",
],
+ data: [
+ ":libz",
+ ":idmap2",
+ ],
},
},
- data: ["tests/data/**/*.apk"],
+ data: [
+ "tests/data/**/*.apk",
+ ],
+ compile_multilib: "first",
+ test_options: {
+ unit_test: true,
+ },
}
cc_binary {
diff --git a/cmds/idmap2/AndroidTest.xml b/cmds/idmap2/AndroidTest.xml
deleted file mode 100644
index 5147f4e6cb4c..000000000000
--- a/cmds/idmap2/AndroidTest.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2018 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<configuration description="Config for idmap2_tests">
- <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
- <option name="cleanup" value="true" />
- <option name="push" value="idmap2_tests->/data/local/tmp/idmap2_tests" />
- </target_preparer>
- <option name="test-suite-tag" value="idmap2_tests" />
- <test class="com.android.tradefed.testtype.GTest" >
- <option name="native-test-device-path" value="/data/local/tmp" />
- <option name="module-name" value="idmap2_tests" />
- </test>
-</configuration>
diff --git a/core/api/current.txt b/core/api/current.txt
index 976ec5608d5a..f6164af55889 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -35970,6 +35970,19 @@ package android.se.omapi {
package android.security {
+ public final class AppUriAuthenticationPolicy implements android.os.Parcelable {
+ method public int describeContents();
+ method @NonNull public java.util.Map<java.lang.String,java.util.Map<android.net.Uri,java.lang.String>> getAppAndUriMappings();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.security.AppUriAuthenticationPolicy> CREATOR;
+ }
+
+ public static final class AppUriAuthenticationPolicy.Builder {
+ ctor public AppUriAuthenticationPolicy.Builder();
+ method @NonNull public android.security.AppUriAuthenticationPolicy.Builder addAppAndUriMapping(@NonNull String, @NonNull android.net.Uri, @NonNull String);
+ method @NonNull public android.security.AppUriAuthenticationPolicy build();
+ }
+
public final class AttestedKeyPair {
ctor public AttestedKeyPair(@Nullable java.security.KeyPair, @NonNull java.util.List<java.security.cert.Certificate>);
method @NonNull public java.util.List<java.security.cert.Certificate> getAttestationRecord();
@@ -36017,6 +36030,7 @@ package android.security {
method public static void choosePrivateKeyAlias(@NonNull android.app.Activity, @NonNull android.security.KeyChainAliasCallback, @Nullable String[], @Nullable java.security.Principal[], @Nullable String, int, @Nullable String);
method public static void choosePrivateKeyAlias(@NonNull android.app.Activity, @NonNull android.security.KeyChainAliasCallback, @Nullable String[], @Nullable java.security.Principal[], @Nullable android.net.Uri, @Nullable String);
method @NonNull public static android.content.Intent createInstallIntent();
+ method @NonNull public static android.content.Intent createManageCredentialsIntent(@NonNull android.security.AppUriAuthenticationPolicy);
method @Nullable @WorkerThread public static java.security.cert.X509Certificate[] getCertificateChain(@NonNull android.content.Context, @NonNull String) throws java.lang.InterruptedException, android.security.KeyChainException;
method @Nullable @WorkerThread public static java.security.PrivateKey getPrivateKey(@NonNull android.content.Context, @NonNull String) throws java.lang.InterruptedException, android.security.KeyChainException;
method @Deprecated public static boolean isBoundKeyAlgorithm(@NonNull String);
@@ -41974,7 +41988,11 @@ package android.telephony.ims {
}
public class ImsRcsManager {
+ method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void getRegistrationState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
+ method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void getRegistrationTransportType(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
method @NonNull public android.telephony.ims.RcsUceAdapter getUceAdapter();
+ method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void registerImsRegistrationCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.RegistrationManager.RegistrationCallback) throws android.telephony.ims.ImsException;
+ method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void unregisterImsRegistrationCallback(@NonNull android.telephony.ims.RegistrationManager.RegistrationCallback);
field public static final String ACTION_SHOW_CAPABILITY_DISCOVERY_OPT_IN = "android.telephony.ims.action.SHOW_CAPABILITY_DISCOVERY_OPT_IN";
}
@@ -42162,6 +42180,15 @@ package android.telephony.ims {
field public static final int EXTRA_CODE_CALL_RETRY_SILENT_REDIAL = 2; // 0x2
}
+ public final class ImsRegistrationAttributes implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getAttributeFlags();
+ method @NonNull public java.util.Set<java.lang.String> getFeatureTags();
+ method public int getTransportType();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.ImsRegistrationAttributes> CREATOR;
+ }
+
public class RcsUceAdapter {
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public boolean isUceSettingEnabled() throws android.telephony.ims.ImsException;
}
@@ -42178,8 +42205,10 @@ package android.telephony.ims {
public static class RegistrationManager.RegistrationCallback {
ctor public RegistrationManager.RegistrationCallback();
- method public void onRegistered(int);
- method public void onRegistering(int);
+ method @Deprecated public void onRegistered(int);
+ method public void onRegistered(@NonNull android.telephony.ims.ImsRegistrationAttributes);
+ method @Deprecated public void onRegistering(int);
+ method public void onRegistering(@NonNull android.telephony.ims.ImsRegistrationAttributes);
method public void onTechnologyChangeFailed(int, @NonNull android.telephony.ims.ImsReasonInfo);
method public void onUnregistered(@NonNull android.telephony.ims.ImsReasonInfo);
}
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index ab9799ff6272..1fb5de3170db 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -15,6 +15,7 @@ package android.net {
}
public class ConnectivityManager {
+ method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public void registerSystemDefaultNetworkCallback(@NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler);
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void requestBackgroundNetwork(@NonNull android.net.NetworkRequest, @Nullable android.os.Handler, @NonNull android.net.ConnectivityManager.NetworkCallback);
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);
}
@@ -71,6 +72,14 @@ package android.net {
field @NonNull public final java.util.List<java.lang.String> underlyingIfaces;
}
+ public final class VpnTransportInfo implements android.os.Parcelable android.net.TransportInfo {
+ ctor public VpnTransportInfo(int);
+ method public int describeContents();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.VpnTransportInfo> CREATOR;
+ field public final int type;
+ }
+
}
package android.os {
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 5fb898a282a8..84d04fceaaba 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -74,6 +74,7 @@ package android {
field public static final String CONTROL_DISPLAY_SATURATION = "android.permission.CONTROL_DISPLAY_SATURATION";
field public static final String CONTROL_INCALL_EXPERIENCE = "android.permission.CONTROL_INCALL_EXPERIENCE";
field public static final String CONTROL_KEYGUARD_SECURE_NOTIFICATIONS = "android.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS";
+ field public static final String CONTROL_OEM_PAID_NETWORK_PREFERENCE = "android.permission.CONTROL_OEM_PAID_NETWORK_PREFERENCE";
field public static final String CONTROL_VPN = "android.permission.CONTROL_VPN";
field public static final String CREATE_USERS = "android.permission.CREATE_USERS";
field public static final String CRYPT_KEEPER = "android.permission.CRYPT_KEEPER";
@@ -6006,11 +6007,15 @@ package android.net {
method public long getExpiryTimeMillis();
method public long getRefreshTimeMillis();
method @Nullable public android.net.Uri getUserPortalUrl();
+ method public int getUserPortalUrlSource();
method @Nullable public String getVenueFriendlyName();
method @Nullable public android.net.Uri getVenueInfoUrl();
+ method public int getVenueInfoUrlSource();
method public boolean isCaptive();
method public boolean isSessionExtendable();
method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field public static final int CAPTIVE_PORTAL_DATA_SOURCE_OTHER = 0; // 0x0
+ field public static final int CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT = 1; // 0x1
field @NonNull public static final android.os.Parcelable.Creator<android.net.CaptivePortalData> CREATOR;
}
@@ -6024,8 +6029,10 @@ package android.net {
method @NonNull public android.net.CaptivePortalData.Builder setRefreshTime(long);
method @NonNull public android.net.CaptivePortalData.Builder setSessionExtendable(boolean);
method @NonNull public android.net.CaptivePortalData.Builder setUserPortalUrl(@Nullable android.net.Uri);
+ method @NonNull public android.net.CaptivePortalData.Builder setUserPortalUrl(@Nullable android.net.Uri, int);
method @NonNull public android.net.CaptivePortalData.Builder setVenueFriendlyName(@Nullable String);
method @NonNull public android.net.CaptivePortalData.Builder setVenueInfoUrl(@Nullable android.net.Uri);
+ method @NonNull public android.net.CaptivePortalData.Builder setVenueInfoUrl(@Nullable android.net.Uri, int);
}
public class ConnectivityManager {
@@ -6039,6 +6046,7 @@ package android.net {
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);
+ method @RequiresPermission(android.Manifest.permission.CONTROL_OEM_PAID_NETWORK_PREFERENCE) public void setOemNetworkPreference(@NonNull android.net.OemNetworkPreferences, @Nullable java.util.concurrent.Executor, @Nullable android.net.ConnectivityManager.OnSetOemNetworkPreferenceListener);
method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public boolean shouldAvoidBadWifi();
method @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public void startCaptivePortalApp(@NonNull android.net.Network, @NonNull android.os.Bundle);
method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void startTethering(int, boolean, android.net.ConnectivityManager.OnStartTetheringCallback);
@@ -6060,6 +6068,10 @@ package android.net {
field @Deprecated public static final int TYPE_WIFI_P2P = 13; // 0xd
}
+ public static interface ConnectivityManager.OnSetOemNetworkPreferenceListener {
+ method public void onComplete();
+ }
+
@Deprecated public abstract static class ConnectivityManager.OnStartTetheringCallback {
ctor @Deprecated public ConnectivityManager.OnStartTetheringCallback();
method @Deprecated public void onTetheringFailed();
@@ -6144,6 +6156,7 @@ package android.net {
method public void close();
method @NonNull public String getInterfaceName();
method @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public void removeAddress(@NonNull java.net.InetAddress, int) throws java.io.IOException;
+ method @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public void setUnderlyingNetwork(@NonNull android.net.Network) throws java.io.IOException;
}
public static class IpSecTransform.Builder {
@@ -6287,6 +6300,7 @@ package android.net {
method @NonNull public int[] getAdministratorUids();
method @Nullable public String getSsid();
method @NonNull public int[] getTransportTypes();
+ method public boolean isPrivateDnsBroken();
method public boolean satisfiedByNetworkCapabilities(@Nullable android.net.NetworkCapabilities);
field public static final int NET_CAPABILITY_NOT_VCN_MANAGED = 28; // 0x1c
field public static final int NET_CAPABILITY_OEM_PAID = 22; // 0x16
@@ -6301,6 +6315,7 @@ package android.net {
method @NonNull public android.net.NetworkCapabilities.Builder addCapability(int);
method @NonNull public android.net.NetworkCapabilities.Builder addTransportType(int);
method @NonNull public android.net.NetworkCapabilities build();
+ method @NonNull public android.net.NetworkCapabilities.Builder clearAll();
method @NonNull public android.net.NetworkCapabilities.Builder removeCapability(int);
method @NonNull public android.net.NetworkCapabilities.Builder removeTransportType(int);
method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setAdministratorUids(@NonNull int[]);
@@ -6416,6 +6431,26 @@ package android.net {
ctor public NetworkStats.Entry(@Nullable String, int, int, int, int, int, int, long, long, long, long, long);
}
+ public final class OemNetworkPreferences implements android.os.Parcelable {
+ method public int describeContents();
+ method @NonNull public java.util.Map<java.lang.String,java.lang.Integer> getNetworkPreferences();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.OemNetworkPreferences> CREATOR;
+ field public static final int OEM_NETWORK_PREFERENCE_OEM_PAID = 1; // 0x1
+ field public static final int OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK = 2; // 0x2
+ field public static final int OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY = 3; // 0x3
+ field public static final int OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY = 4; // 0x4
+ field public static final int OEM_NETWORK_PREFERENCE_UNINITIALIZED = 0; // 0x0
+ }
+
+ public static final class OemNetworkPreferences.Builder {
+ ctor public OemNetworkPreferences.Builder();
+ ctor public OemNetworkPreferences.Builder(@NonNull android.net.OemNetworkPreferences);
+ method @NonNull public android.net.OemNetworkPreferences.Builder addNetworkPreference(@NonNull String, int);
+ method @NonNull public android.net.OemNetworkPreferences build();
+ method @NonNull public android.net.OemNetworkPreferences.Builder clearNetworkPreference(@NonNull String);
+ }
+
public abstract class QosCallback {
ctor public QosCallback();
method public void onError(@NonNull android.net.QosCallbackException);
@@ -7504,6 +7539,7 @@ package android.os {
public class SystemConfigManager {
method @NonNull @RequiresPermission(android.Manifest.permission.READ_CARRIER_APP_INFO) public java.util.Set<java.lang.String> getDisabledUntilUsedPreinstalledCarrierApps();
method @NonNull @RequiresPermission(android.Manifest.permission.READ_CARRIER_APP_INFO) public java.util.Map<java.lang.String,java.util.List<java.lang.String>> getDisabledUntilUsedPreinstalledCarrierAssociatedApps();
+ method @NonNull @RequiresPermission(android.Manifest.permission.GET_RUNTIME_PERMISSIONS) public int[] getSystemPermissionUids(@NonNull String);
}
public class SystemProperties {
@@ -8429,10 +8465,12 @@ package android.security.keystore {
}
public final class KeyGenParameterSpec implements java.security.spec.AlgorithmParameterSpec {
+ method @Nullable public int[] getAttestationIds();
method public int getNamespace();
}
public static final class KeyGenParameterSpec.Builder {
+ method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setAttestationIds(@NonNull int[]);
method @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setNamespace(int);
method @Deprecated @NonNull public android.security.keystore.KeyGenParameterSpec.Builder setUid(int);
}
@@ -10730,35 +10768,6 @@ package android.telephony.cdma {
package android.telephony.data {
- public final class ApnThrottleStatus implements android.os.Parcelable {
- method public int describeContents();
- method public int getApnType();
- method public int getRetryType();
- method public int getSlotIndex();
- method public long getThrottleExpiryTimeMillis();
- method public int getThrottleType();
- method public int getTransportType();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.telephony.data.ApnThrottleStatus> CREATOR;
- field public static final int RETRY_TYPE_HANDOVER = 3; // 0x3
- field public static final int RETRY_TYPE_NEW_CONNECTION = 2; // 0x2
- field public static final int RETRY_TYPE_NONE = 1; // 0x1
- field public static final int THROTTLE_TYPE_ELAPSED_TIME = 2; // 0x2
- field public static final int THROTTLE_TYPE_NONE = 1; // 0x1
- }
-
- public static final class ApnThrottleStatus.Builder {
- ctor public ApnThrottleStatus.Builder();
- method @NonNull public android.telephony.data.ApnThrottleStatus build();
- method @NonNull public android.telephony.data.ApnThrottleStatus.Builder setApnType(int);
- method @NonNull public android.telephony.data.ApnThrottleStatus.Builder setNoThrottle();
- method @NonNull public android.telephony.data.ApnThrottleStatus.Builder setRetryType(int);
- method @NonNull public android.telephony.data.ApnThrottleStatus.Builder setSlotIndex(int);
- method @NonNull public android.telephony.data.ApnThrottleStatus.Builder setThrottleExpiryTimeMillis(long);
- method @NonNull public android.telephony.data.ApnThrottleStatus.Builder setTransportType(int);
- field public static final long NO_THROTTLE_EXPIRY_TIME = -1L; // 0xffffffffffffffffL
- }
-
public final class DataCallResponse implements android.os.Parcelable {
method public int describeContents();
method @NonNull public java.util.List<android.net.LinkAddress> getAddresses();
@@ -10928,7 +10937,7 @@ package android.telephony.data {
ctor public QualifiedNetworksService.NetworkAvailabilityProvider(int);
method public abstract void close();
method public final int getSlotIndex();
- method public void reportApnThrottleStatusChanged(@NonNull java.util.List<android.telephony.data.ApnThrottleStatus>);
+ method public void reportThrottleStatusChanged(@NonNull java.util.List<android.telephony.data.ThrottleStatus>);
method public final void updateQualifiedNetworkTypes(int, @NonNull java.util.List<java.lang.Integer>);
}
@@ -10958,6 +10967,34 @@ package android.telephony.data {
method @NonNull public android.telephony.data.SliceInfo.Builder setSliceServiceType(int);
}
+ public final class ThrottleStatus implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getApnType();
+ method public int getRetryType();
+ method public int getSlotIndex();
+ method public long getThrottleExpiryTimeMillis();
+ method public int getThrottleType();
+ method public int getTransportType();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.telephony.data.ThrottleStatus> CREATOR;
+ field public static final int RETRY_TYPE_HANDOVER = 3; // 0x3
+ field public static final int RETRY_TYPE_NEW_CONNECTION = 2; // 0x2
+ field public static final int RETRY_TYPE_NONE = 1; // 0x1
+ field public static final int THROTTLE_TYPE_ELAPSED_TIME = 2; // 0x2
+ field public static final int THROTTLE_TYPE_NONE = 1; // 0x1
+ }
+
+ public static final class ThrottleStatus.Builder {
+ ctor public ThrottleStatus.Builder();
+ method @NonNull public android.telephony.data.ThrottleStatus build();
+ method @NonNull public android.telephony.data.ThrottleStatus.Builder setApnType(int);
+ method @NonNull public android.telephony.data.ThrottleStatus.Builder setNoThrottle();
+ method @NonNull public android.telephony.data.ThrottleStatus.Builder setRetryType(int);
+ method @NonNull public android.telephony.data.ThrottleStatus.Builder setSlotIndex(int);
+ method @NonNull public android.telephony.data.ThrottleStatus.Builder setThrottleExpiryTimeMillis(long);
+ method @NonNull public android.telephony.data.ThrottleStatus.Builder setTransportType(int);
+ }
+
}
package android.telephony.euicc {
@@ -11545,12 +11582,35 @@ package android.telephony.ims {
@Deprecated public static class ImsMmTelManager.RegistrationCallback extends android.telephony.ims.RegistrationManager.RegistrationCallback {
ctor @Deprecated public ImsMmTelManager.RegistrationCallback();
+ method @Deprecated public void onRegistered(int);
+ method @Deprecated public void onRegistering(int);
+ }
+
+ public class ImsRcsManager {
+ method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void addOnAvailabilityChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.ImsRcsManager.OnAvailabilityChangedListener) throws android.telephony.ims.ImsException;
+ method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isAvailable(int, int) throws android.telephony.ims.ImsException;
+ method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isCapable(int, int) throws android.telephony.ims.ImsException;
+ method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void removeOnAvailabilityChangedListener(@NonNull android.telephony.ims.ImsRcsManager.OnAvailabilityChangedListener);
+ }
+
+ public static interface ImsRcsManager.OnAvailabilityChangedListener {
+ method public void onAvailabilityChanged(int);
}
public final class ImsReasonInfo implements android.os.Parcelable {
field public static final String EXTRA_MSG_SERVICE_NOT_AUTHORIZED = "Forbidden. Not Authorized for Service";
}
+ public final class ImsRegistrationAttributes implements android.os.Parcelable {
+ method public int getRegistrationTechnology();
+ }
+
+ public static final class ImsRegistrationAttributes.Builder {
+ ctor public ImsRegistrationAttributes.Builder(int);
+ method @NonNull public android.telephony.ims.ImsRegistrationAttributes build();
+ method @NonNull public android.telephony.ims.ImsRegistrationAttributes.Builder setFeatureTags(@NonNull java.util.Set<java.lang.String>);
+ }
+
public class ImsService extends android.app.Service {
ctor public ImsService();
method public android.telephony.ims.feature.MmTelFeature createMmTelFeature(int);
@@ -12187,11 +12247,24 @@ package android.telephony.ims.feature {
ctor public RcsFeature(@NonNull java.util.concurrent.Executor);
method public void changeEnabledCapabilities(@NonNull android.telephony.ims.feature.CapabilityChangeRequest, @NonNull android.telephony.ims.feature.ImsFeature.CapabilityCallbackProxy);
method @NonNull public android.telephony.ims.stub.RcsCapabilityExchangeImplBase createCapabilityExchangeImpl(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.stub.CapabilityExchangeEventListener);
+ method public final void notifyCapabilitiesStatusChanged(@NonNull android.telephony.ims.feature.RcsFeature.RcsImsCapabilities);
method public void onFeatureReady();
method public void onFeatureRemoved();
+ method public boolean queryCapabilityConfiguration(int, int);
+ method @NonNull public final android.telephony.ims.feature.RcsFeature.RcsImsCapabilities queryCapabilityStatus();
method public void removeCapabilityExchangeImpl(@NonNull android.telephony.ims.stub.RcsCapabilityExchangeImplBase);
}
+ public static class RcsFeature.RcsImsCapabilities extends android.telephony.ims.feature.ImsFeature.Capabilities {
+ ctor public RcsFeature.RcsImsCapabilities(int);
+ method public void addCapabilities(int);
+ method public boolean isCapable(int);
+ method public void removeCapabilities(int);
+ field public static final int CAPABILITY_TYPE_NONE = 0; // 0x0
+ field public static final int CAPABILITY_TYPE_OPTIONS_UCE = 1; // 0x1
+ field public static final int CAPABILITY_TYPE_PRESENCE_UCE = 2; // 0x2
+ }
+
}
package android.telephony.ims.stub {
@@ -12321,7 +12394,9 @@ package android.telephony.ims.stub {
ctor public ImsRegistrationImplBase();
method public final void onDeregistered(android.telephony.ims.ImsReasonInfo);
method public final void onRegistered(int);
+ method public final void onRegistered(@NonNull android.telephony.ims.ImsRegistrationAttributes);
method public final void onRegistering(int);
+ method public final void onRegistering(@NonNull android.telephony.ims.ImsRegistrationAttributes);
method public final void onSubscriberAssociatedUriChanged(android.net.Uri[]);
method public final void onTechnologyChangeFailed(int, android.telephony.ims.ImsReasonInfo);
method public void triggerFullNetworkRegistration(@IntRange(from=100, to=699) int, @Nullable String);
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 668b5883cbfb..68721418b407 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -12,6 +12,7 @@ package android {
field public static final String CONFIGURE_DISPLAY_BRIGHTNESS = "android.permission.CONFIGURE_DISPLAY_BRIGHTNESS";
field public static final String CONTROL_DEVICE_LIGHTS = "android.permission.CONTROL_DEVICE_LIGHTS";
field public static final String FORCE_STOP_PACKAGES = "android.permission.FORCE_STOP_PACKAGES";
+ field public static final String KEEP_UNINSTALLED_PACKAGES = "android.permission.KEEP_UNINSTALLED_PACKAGES";
field public static final String MANAGE_ACTIVITY_STACKS = "android.permission.MANAGE_ACTIVITY_STACKS";
field public static final String MANAGE_CRATES = "android.permission.MANAGE_CRATES";
field public static final String MANAGE_ROLLBACKS = "android.permission.MANAGE_ROLLBACKS";
@@ -989,6 +990,12 @@ package android.net {
field public static final int INVALID_SECURITY_PARAMETER_INDEX = 0; // 0x0
}
+ public class NetworkPolicyManager {
+ method public boolean getRestrictBackground();
+ method @NonNull public static String resolveNetworkId(@NonNull android.net.wifi.WifiConfiguration);
+ method public void setRestrictBackground(boolean);
+ }
+
public class NetworkStack {
method public static void setServiceForTest(@Nullable android.os.IBinder);
}
diff --git a/core/api/test-lint-baseline.txt b/core/api/test-lint-baseline.txt
index f5ab40abdf37..b3636b9b765d 100644
--- a/core/api/test-lint-baseline.txt
+++ b/core/api/test-lint-baseline.txt
@@ -483,6 +483,8 @@ GetterSetterNames: android.location.LocationRequest#isLocationSettingsIgnored():
GetterSetterNames: android.location.LocationRequest#isLowPowerMode():
+GetterSetterNames: android.net.NetworkPolicyManager#getRestrictBackground():
+ Symmetric method for `setRestrictBackground` must be named `isRestrictBackground`; was `getRestrictBackground`
GetterSetterNames: android.os.IncidentReportArgs#isAll():
GetterSetterNames: android.service.notification.NotificationStats#setDirectReplied():
diff --git a/core/java/android/accounts/OWNERS b/core/java/android/accounts/OWNERS
index ea5fd36702f9..8dcc04a27af6 100644
--- a/core/java/android/accounts/OWNERS
+++ b/core/java/android/accounts/OWNERS
@@ -3,7 +3,6 @@ dementyev@google.com
sandrakwan@google.com
hackbod@google.com
svetoslavganov@google.com
-moltmann@google.com
fkupolov@google.com
yamasani@google.com
omakoto@google.com
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 31ab2248236d..797253af394b 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -1136,9 +1136,16 @@ public class AppOpsManager {
// TODO: Add as AppProtoEnums
public static final int OP_RECORD_AUDIO_HOTWORD = 102;
+ /**
+ * Manage credentials in the system KeyChain.
+ *
+ * @hide
+ */
+ public static final int OP_MANAGE_CREDENTIALS = AppProtoEnums.APP_OP_MANAGE_CREDENTIALS;
+
/** @hide */
@UnsupportedAppUsage
- public static final int _NUM_OP = 104;
+ public static final int _NUM_OP = 105;
/** Access to coarse location information. */
public static final String OPSTR_COARSE_LOCATION = "android:coarse_location";
@@ -1485,6 +1492,13 @@ public class AppOpsManager {
*/
public static final String OPSTR_RECORD_AUDIO_HOTWORD = "android:record_audio_hotword";
+ /**
+ * Manage credentials in the system KeyChain.
+ *
+ * @hide
+ */
+ public static final String OPSTR_MANAGE_CREDENTIALS = "android:manage_credentials";
+
/** {@link #sAppOpsToNote} not initialized yet for this op */
private static final byte SHOULD_COLLECT_NOTE_OP_NOT_INITIALIZED = 0;
/** Should not collect noting of this app-op in {@link #sAppOpsToNote} */
@@ -1679,6 +1693,7 @@ public class AppOpsManager {
OP_PHONE_CALL_CAMERA, // OP_PHONE_CALL_CAMERA
OP_RECORD_AUDIO_HOTWORD, // RECORD_AUDIO_HOTWORD
OP_MANAGE_ONGOING_CALLS, // MANAGE_ONGOING_CALLS
+ OP_MANAGE_CREDENTIALS, // MANAGE_CREDENTIALS
};
/**
@@ -1789,6 +1804,7 @@ public class AppOpsManager {
OPSTR_PHONE_CALL_CAMERA,
OPSTR_RECORD_AUDIO_HOTWORD,
OPSTR_MANAGE_ONGOING_CALLS,
+ OPSTR_MANAGE_CREDENTIALS,
};
/**
@@ -1900,6 +1916,7 @@ public class AppOpsManager {
"PHONE_CALL_CAMERA",
"RECORD_AUDIO_HOTWORD",
"MANAGE_ONGOING_CALLS",
+ "MANAGE_CREDENTIALS",
};
/**
@@ -2012,6 +2029,7 @@ public class AppOpsManager {
null, // no permission for OP_PHONE_CALL_CAMERA
null, // no permission for OP_RECORD_AUDIO_HOTWORD
Manifest.permission.MANAGE_ONGOING_CALLS,
+ null, // no permission for OP_MANAGE_CREDENTIALS
};
/**
@@ -2124,6 +2142,7 @@ public class AppOpsManager {
null, // PHONE_CALL_MICROPHONE
null, // RECORD_AUDIO_HOTWORD
null, // MANAGE_ONGOING_CALLS
+ null, // MANAGE_CREDENTIALS
};
/**
@@ -2235,6 +2254,7 @@ public class AppOpsManager {
null, // PHONE_CALL_CAMERA
null, // RECORD_AUDIO_HOTWORD
null, // MANAGE_ONGOING_CALLS
+ null, // MANAGE_CREDENTIALS
};
/**
@@ -2345,6 +2365,7 @@ public class AppOpsManager {
AppOpsManager.MODE_ALLOWED, // PHONE_CALL_CAMERA
AppOpsManager.MODE_ALLOWED, // OP_RECORD_AUDIO_HOTWORD
AppOpsManager.MODE_DEFAULT, // MANAGE_ONGOING_CALLS
+ AppOpsManager.MODE_DEFAULT, // MANAGE_CREDENTIALS
};
/**
@@ -2459,6 +2480,7 @@ public class AppOpsManager {
false, // PHONE_CALL_CAMERA
false, // RECORD_AUDIO_HOTWORD
true, // MANAGE_ONGOING_CALLS
+ false, // MANAGE_CREDENTIALS
};
/**
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index d151526612f0..d7eded201740 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -116,11 +116,13 @@ import android.net.EthernetManager;
import android.net.IEthernetManager;
import android.net.IIpSecService;
import android.net.INetworkPolicyManager;
+import android.net.IVpnManager;
import android.net.IpSecManager;
import android.net.NetworkPolicyManager;
import android.net.NetworkScoreManager;
import android.net.NetworkWatchlistManager;
import android.net.TetheringManager;
+import android.net.VpnManager;
import android.net.lowpan.ILowpanManager;
import android.net.lowpan.LowpanManager;
import android.net.nsd.INsdManager;
@@ -358,6 +360,15 @@ public final class SystemServiceRegistry {
ctx, () -> ServiceManager.getService(Context.TETHERING_SERVICE));
}});
+ registerService(Context.VPN_MANAGEMENT_SERVICE, VpnManager.class,
+ new CachedServiceFetcher<VpnManager>() {
+ @Override
+ public VpnManager createService(ContextImpl ctx) throws ServiceNotFoundException {
+ IBinder b = ServiceManager.getService(Context.VPN_MANAGEMENT_SERVICE);
+ IVpnManager service = IVpnManager.Stub.asInterface(b);
+ return new VpnManager(ctx, service);
+ }});
+
registerService(Context.VCN_MANAGEMENT_SERVICE, VcnManager.class,
new CachedServiceFetcher<VcnManager>() {
@Override
diff --git a/core/java/android/app/compat/CompatChanges.java b/core/java/android/app/compat/CompatChanges.java
index 28b73406b877..ab38832458d6 100644
--- a/core/java/android/app/compat/CompatChanges.java
+++ b/core/java/android/app/compat/CompatChanges.java
@@ -20,8 +20,16 @@ import android.annotation.NonNull;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.compat.Compatibility;
+import android.content.Context;
+import android.os.RemoteException;
+import android.os.ServiceManager;
import android.os.UserHandle;
+import com.android.internal.compat.CompatibilityOverrideConfig;
+import com.android.internal.compat.IPlatformCompat;
+
+import java.util.Map;
+
/**
* CompatChanges APIs - to be used by platform code only (including mainline
* modules).
@@ -89,4 +97,25 @@ public final class CompatChanges {
return QUERY_CACHE.query(ChangeIdStateQuery.byUid(changeId, uid));
}
+ /**
+ * Set an app compat override for a given package. This will check whether the caller is allowed
+ * to perform this operation on the given apk and build. Only the installer package is allowed
+ * to set overrides on a non-debuggable final build and a non-test apk.
+ *
+ * @param packageName The package name of the app in question.
+ * @param overrides A map from changeId to the override applied for this change id.
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG)
+ public static void setPackageOverride(String packageName,
+ Map<Long, PackageOverride> overrides) {
+ IPlatformCompat platformCompat = IPlatformCompat.Stub.asInterface(
+ ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));
+ CompatibilityOverrideConfig config = new CompatibilityOverrideConfig(overrides);
+ try {
+ platformCompat.setOverridesFromInstaller(config, packageName);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/core/java/android/app/compat/OWNERS b/core/java/android/app/compat/OWNERS
new file mode 100644
index 000000000000..f8c3520e9fa8
--- /dev/null
+++ b/core/java/android/app/compat/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/compat/OWNERS
diff --git a/core/java/android/app/compat/PackageOverride.java b/core/java/android/app/compat/PackageOverride.java
new file mode 100644
index 000000000000..9f97cd41128a
--- /dev/null
+++ b/core/java/android/app/compat/PackageOverride.java
@@ -0,0 +1,211 @@
+/*
+ * 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.app.compat;
+
+import android.annotation.IntDef;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * An app compat override applied to a given package and change id pairing.
+ *
+ * A package override contains a list of version ranges with the desired boolean value of
+ * the override for the app in this version range. Ranges can be open ended in either direction.
+ * An instance of PackageOverride gets created via {@link Builder} and is immutable once created.
+ *
+ * @hide
+ */
+public class PackageOverride implements Parcelable {
+
+ @IntDef({
+ VALUE_UNDEFINED,
+ VALUE_ENABLED,
+ VALUE_DISABLED
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ /** @hide */
+ public @interface EvaluatedOverride {
+ }
+
+ /**
+ * Return value of {@link #evaluate(long)} and {@link #evaluateForAllVersions()} indicating that
+ * this PackageOverride does not define the value of the override for the given version.
+ * @hide
+ */
+ public static final int VALUE_UNDEFINED = 0;
+ /**
+ * Return value of {@link #evaluate(long)} and {@link #evaluateForAllVersions()} indicating that
+ * the override evaluates to {@code true} for the given version.
+ * @hide
+ */
+ public static final int VALUE_ENABLED = 1;
+ /**
+ * Return value of {@link #evaluate(long)} and {@link #evaluateForAllVersions()} indicating that
+ * the override evaluates to {@code fakse} for the given version.
+ * @hide
+ */
+ public static final int VALUE_DISABLED = 2;
+
+ private final long mMinVersionCode;
+ private final long mMaxVersionCode;
+ private final boolean mEnabled;
+
+ private PackageOverride(long minVersionCode,
+ long maxVersionCode,
+ boolean enabled) {
+ this.mMinVersionCode = minVersionCode;
+ this.mMaxVersionCode = maxVersionCode;
+ this.mEnabled = enabled;
+ }
+
+ private PackageOverride(Parcel in) {
+ this(in.readLong(), in.readLong(), in.readBoolean());
+ }
+
+ /**
+ * Evaluate the override for the given {@code versionCode}. If no override is defined for
+ * the specified version code, {@link #VALUE_UNDEFINED} is returned.
+ * @hide
+ */
+ public @EvaluatedOverride int evaluate(long versionCode) {
+ if (versionCode >= mMinVersionCode && versionCode <= mMaxVersionCode) {
+ return mEnabled ? VALUE_ENABLED : VALUE_DISABLED;
+ }
+ return VALUE_UNDEFINED;
+ }
+
+ /**
+ * Evaluate the override independent of version code, i.e. only return an evaluated value if
+ * this range covers all versions, otherwise {@link #VALUE_UNDEFINED} is returned.
+ * @hide
+ */
+ public int evaluateForAllVersions() {
+ if (mMinVersionCode == Long.MIN_VALUE && mMaxVersionCode == Long.MAX_VALUE) {
+ return mEnabled ? VALUE_ENABLED : VALUE_DISABLED;
+ }
+ return VALUE_UNDEFINED;
+ }
+
+ /** Returns the minimum version code the override applies to. */
+ public long getMinVersionCode() {
+ return mMinVersionCode;
+ }
+
+ /** Returns the minimum version code the override applies from. */
+ public long getMaxVersionCode() {
+ return mMaxVersionCode;
+ }
+
+ /** Returns the enabled value for the override. */
+ public boolean getEnabled() {
+ return mEnabled;
+ }
+
+ /** @hide */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /** @hide */
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeLong(mMinVersionCode);
+ dest.writeLong(mMaxVersionCode);
+ dest.writeBoolean(mEnabled);
+ }
+
+ /** @hide */
+ @Override
+ public String toString() {
+ if (mMinVersionCode == Long.MIN_VALUE && mMaxVersionCode == Long.MAX_VALUE) {
+ return Boolean.toString(mEnabled);
+ }
+ return String.format("[%d,%d,%b]", mMinVersionCode, mMaxVersionCode, mEnabled);
+ }
+
+ /** @hide */
+ public static final Creator<PackageOverride> CREATOR =
+ new Creator<PackageOverride>() {
+
+ @Override
+ public PackageOverride createFromParcel(Parcel in) {
+ return new PackageOverride(in);
+ }
+
+ @Override
+ public PackageOverride[] newArray(int size) {
+ return new PackageOverride[size];
+ }
+ };
+
+ /**
+ * Builder to construct a PackageOverride.
+ */
+ public static class Builder {
+ private long mMinVersionCode = Long.MIN_VALUE;
+ private long mMaxVersionCode = Long.MAX_VALUE;
+ private boolean mEnabled;
+
+ /**
+ * Sets the minimum version code the override should apply from.
+ *
+ * default value: {@code Long.MIN_VALUE}.
+ */
+ public Builder setMinVersionCode(long minVersionCode) {
+ mMinVersionCode = minVersionCode;
+ return this;
+ }
+
+ /**
+ * Sets the maximum version code the override should apply to.
+ *
+ * default value: {@code Long.MAX_VALUE}.
+ */
+ public Builder setMaxVersionCode(long maxVersionCode) {
+ mMaxVersionCode = maxVersionCode;
+ return this;
+ }
+
+ /**
+ * Sets whether the override should be enabled for the given version range.
+ *
+ * default value: {@code false}.
+ */
+ public Builder setEnabled(boolean enabled) {
+ mEnabled = enabled;
+ return this;
+ }
+
+ /**
+ * Build the {@link PackageOverride}.
+ *
+ * @throws IllegalArgumentException if {@code minVersionCode} is larger than
+ * {@code maxVersionCode}.
+ */
+ public PackageOverride build() {
+ if (mMinVersionCode > mMaxVersionCode) {
+ throw new IllegalArgumentException("minVersionCode must not be larger than "
+ + "maxVersionCode");
+ }
+ return new PackageOverride(mMinVersionCode, mMaxVersionCode, mEnabled);
+ }
+ };
+}
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index a6089c31b140..32aa0377cd5f 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -64,7 +64,7 @@ import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.UserHandle;
import android.os.storage.StorageManager;
-import android.system.Int32Ref;
+import android.system.Int64Ref;
import android.text.TextUtils;
import android.util.EventLog;
import android.util.Log;
@@ -4040,7 +4040,7 @@ public abstract class ContentResolver implements ContentInterface {
// Convert to Point, since that's what the API is defined as
final Bundle opts = new Bundle();
opts.putParcelable(EXTRA_SIZE, Point.convert(size));
- final Int32Ref orientation = new Int32Ref(0);
+ final Int64Ref orientation = new Int64Ref(0);
Bitmap bitmap = ImageDecoder.decodeBitmap(ImageDecoder.createSource(() -> {
final AssetFileDescriptor afd = content.openTypedAssetFile(uri, "image/*", opts,
diff --git a/core/java/android/content/pm/permission/OWNERS b/core/java/android/content/pm/permission/OWNERS
index cde7b2ac1898..d302b0ae1ea8 100644
--- a/core/java/android/content/pm/permission/OWNERS
+++ b/core/java/android/content/pm/permission/OWNERS
@@ -3,7 +3,6 @@
toddke@android.com
toddke@google.com
patb@google.com
-moltmann@google.com
svetoslavganov@android.com
svetoslavganov@google.com
zhanghai@google.com
diff --git a/core/java/android/hardware/location/OWNERS b/core/java/android/hardware/location/OWNERS
index 383321bc3d69..bd40409f71c6 100644
--- a/core/java/android/hardware/location/OWNERS
+++ b/core/java/android/hardware/location/OWNERS
@@ -4,3 +4,6 @@ mstogaitis@google.com
wyattriley@google.com
etn@google.com
weiwa@google.com
+
+# ContextHub team
+per-file *ContextHub*,*NanoApp* = file:platform/system/chre:/OWNERS
diff --git a/core/java/android/hardware/usb/OWNERS b/core/java/android/hardware/usb/OWNERS
index 8f2b39da4f63..8f5c2a025672 100644
--- a/core/java/android/hardware/usb/OWNERS
+++ b/core/java/android/hardware/usb/OWNERS
@@ -1,4 +1,3 @@
# Bug component: 175220
-moltmann@google.com
badhri@google.com
diff --git a/core/java/android/net/IIpSecService.aidl b/core/java/android/net/IIpSecService.aidl
index d6774d47b49e..933256a3b475 100644
--- a/core/java/android/net/IIpSecService.aidl
+++ b/core/java/android/net/IIpSecService.aidl
@@ -58,6 +58,9 @@ interface IIpSecService
in LinkAddress localAddr,
in String callingPackage);
+ void setNetworkForTunnelInterface(
+ int tunnelResourceId, in Network underlyingNetwork, in String callingPackage);
+
void deleteTunnelInterface(int resourceId, in String callingPackage);
IpSecTransformResponse createTransform(
diff --git a/core/java/android/net/IOnSetOemNetworkPreferenceListener.aidl b/core/java/android/net/IOnSetOemNetworkPreferenceListener.aidl
new file mode 100644
index 000000000000..7979afc54f90
--- /dev/null
+++ b/core/java/android/net/IOnSetOemNetworkPreferenceListener.aidl
@@ -0,0 +1,23 @@
+/**
+ *
+ * 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;
+
+/** @hide */
+oneway interface IOnSetOemNetworkPreferenceListener {
+ void onComplete();
+}
diff --git a/core/java/android/net/IVpnManager.aidl b/core/java/android/net/IVpnManager.aidl
new file mode 100644
index 000000000000..271efe41a9ef
--- /dev/null
+++ b/core/java/android/net/IVpnManager.aidl
@@ -0,0 +1,62 @@
+/**
+ * Copyright (c) 2020, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.net.Network;
+
+import com.android.internal.net.LegacyVpnInfo;
+import com.android.internal.net.VpnConfig;
+import com.android.internal.net.VpnProfile;
+
+/**
+ * Interface that manages VPNs.
+ */
+/** {@hide} */
+interface IVpnManager {
+ /** VpnService APIs */
+ boolean prepareVpn(String oldPackage, String newPackage, int userId);
+ void setVpnPackageAuthorization(String packageName, int userId, int vpnType);
+ ParcelFileDescriptor establishVpn(in VpnConfig config);
+ boolean addVpnAddress(String address, int prefixLength);
+ boolean removeVpnAddress(String address, int prefixLength);
+ boolean setUnderlyingNetworksForVpn(in Network[] networks);
+
+ /** VpnManager APIs */
+ boolean provisionVpnProfile(in VpnProfile profile, String packageName);
+ void deleteVpnProfile(String packageName);
+ void startVpnProfile(String packageName);
+ void stopVpnProfile(String packageName);
+
+ /** Always-on VPN APIs */
+ boolean isAlwaysOnVpnPackageSupported(int userId, String packageName);
+ boolean setAlwaysOnVpnPackage(int userId, String packageName, boolean lockdown,
+ in List<String> lockdownAllowlist);
+ String getAlwaysOnVpnPackage(int userId);
+ boolean isVpnLockdownEnabled(int userId);
+ List<String> getVpnLockdownAllowlist(int userId);
+ boolean isCallerCurrentAlwaysOnVpnApp();
+ boolean isCallerCurrentAlwaysOnVpnLockdownApp();
+
+ /** Legacy VPN APIs */
+ void startLegacyVpn(in VpnProfile profile);
+ LegacyVpnInfo getLegacyVpnInfo(int userId);
+ boolean updateLockdownVpn();
+
+ /** General system APIs */
+ VpnConfig getVpnConfig(int userId);
+ void factoryReset();
+}
diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java
index 70bca3019818..98acd98cc465 100644
--- a/core/java/android/net/IpSecManager.java
+++ b/core/java/android/net/IpSecManager.java
@@ -782,6 +782,42 @@ public final class IpSecManager {
}
}
+ /**
+ * Update the underlying network for this IpSecTunnelInterface.
+ *
+ * <p>This new underlying network will be used for all transforms applied AFTER this call is
+ * complete. Before new {@link IpSecTransform}(s) with matching addresses are applied to
+ * this tunnel interface, traffic will still use the old SA, and be routed on the old
+ * underlying network.
+ *
+ * <p>To migrate IPsec tunnel mode traffic, a caller should:
+ *
+ * <ol>
+ * <li>Update the IpSecTunnelInterface’s underlying network.
+ * <li>Apply {@link IpSecTransform}(s) with matching addresses to this
+ * IpSecTunnelInterface.
+ * </ol>
+ *
+ * @param underlyingNetwork the new {@link Network} that will carry traffic for this tunnel.
+ * This network MUST never be the network exposing this IpSecTunnelInterface, otherwise
+ * this method will throw an {@link IllegalArgumentException}.
+ */
+ // TODO: b/169171001 Update the documentation when transform migration is supported.
+ // The purpose of making updating network and applying transforms separate is to leave open
+ // the possibility to support lossless migration procedures. To do that, Android platform
+ // will need to support multiple inbound tunnel mode transforms, just like it can support
+ // multiple transport mode transforms.
+ @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS)
+ @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS)
+ public void setUnderlyingNetwork(@NonNull Network underlyingNetwork) throws IOException {
+ try {
+ mService.setNetworkForTunnelInterface(
+ mResourceId, underlyingNetwork, mOpPackageName);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
private IpSecTunnelInterface(@NonNull Context ctx, @NonNull IIpSecService service,
@NonNull InetAddress localAddress, @NonNull InetAddress remoteAddress,
@NonNull Network underlyingNetwork)
diff --git a/core/java/android/net/LocalSocketImpl.java b/core/java/android/net/LocalSocketImpl.java
index e01e5aecc7e6..f7c1c4bb6d96 100644
--- a/core/java/android/net/LocalSocketImpl.java
+++ b/core/java/android/net/LocalSocketImpl.java
@@ -19,7 +19,6 @@ package android.net;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Build;
import android.system.ErrnoException;
-import android.system.Int32Ref;
import android.system.Os;
import android.system.OsConstants;
import android.system.StructLinger;
@@ -65,14 +64,11 @@ class LocalSocketImpl
public int available() throws IOException {
FileDescriptor myFd = fd;
if (myFd == null) throw new IOException("socket closed");
-
- Int32Ref avail = new Int32Ref(0);
try {
- Os.ioctlInt(myFd, OsConstants.FIONREAD, avail);
+ return Os.ioctlInt(myFd, OsConstants.FIONREAD);
} catch (ErrnoException e) {
throw e.rethrowAsIOException();
}
- return avail.value;
}
/** {@inheritDoc} */
@@ -134,7 +130,7 @@ class LocalSocketImpl
public void write (byte[] b) throws IOException {
write(b, 0, b.length);
}
-
+
/** {@inheritDoc} */
@Override
public void write (byte[] b, int off, int len) throws IOException {
@@ -255,7 +251,7 @@ class LocalSocketImpl
/** note timeout presently ignored */
protected void connect(LocalSocketAddress address, int timeout)
throws IOException
- {
+ {
if (fd == null) {
throw new IOException("socket not created");
}
@@ -339,7 +335,7 @@ class LocalSocketImpl
* @throws IOException if socket has been closed or cannot be created.
*/
protected OutputStream getOutputStream() throws IOException
- {
+ {
if (fd == null) {
throw new IOException("socket not created");
}
diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java
index 11146bd45fe4..b1bca6efa02b 100644
--- a/core/java/android/net/NetworkPolicyManager.java
+++ b/core/java/android/net/NetworkPolicyManager.java
@@ -22,6 +22,7 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
import android.annotation.SystemService;
+import android.annotation.TestApi;
import android.app.ActivityManager;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
@@ -55,6 +56,7 @@ import java.util.concurrent.ConcurrentHashMap;
*
* @hide
*/
+@TestApi
@SystemService(Context.NETWORK_POLICY_SERVICE)
public class NetworkPolicyManager {
@@ -125,6 +127,7 @@ public class NetworkPolicyManager {
public static final int RULE_REJECT_ALL = 1 << 6;
/**
* Reject traffic on all networks for restricted networking mode.
+ * @hide
*/
public static final int RULE_REJECT_RESTRICTED_MODE = 1 << 10;
@@ -351,6 +354,7 @@ public class NetworkPolicyManager {
}
/** @hide */
+ @TestApi
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public void setRestrictBackground(boolean restrictBackground) {
try {
@@ -361,6 +365,7 @@ public class NetworkPolicyManager {
}
/** @hide */
+ @TestApi
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public boolean getRestrictBackground() {
try {
@@ -506,6 +511,8 @@ public class NetworkPolicyManager {
/**
* Get multipath preference for the given network.
+ *
+ * @hide
*/
public int getMultipathPreference(Network network) {
try {
@@ -624,7 +631,9 @@ public class NetworkPolicyManager {
}
/** @hide */
- public static String resolveNetworkId(WifiConfiguration config) {
+ @TestApi
+ @NonNull
+ public static String resolveNetworkId(@NonNull WifiConfiguration config) {
return WifiInfo.sanitizeSsid(config.isPasspoint()
? config.providerFriendlyName : config.SSID);
}
diff --git a/core/java/android/net/OemNetworkPreferences.java b/core/java/android/net/OemNetworkPreferences.java
index 5e56164cc82c..b4034556f66e 100644
--- a/core/java/android/net/OemNetworkPreferences.java
+++ b/core/java/android/net/OemNetworkPreferences.java
@@ -18,6 +18,7 @@ package android.net;
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.SystemApi;
import android.os.Bundle;
import android.os.Parcelable;
@@ -29,11 +30,12 @@ import java.util.Map;
import java.util.Objects;
/** @hide */
+@SystemApi
public final class OemNetworkPreferences implements Parcelable {
/**
- * Use default behavior requesting networks. Equivalent to not setting any preference at all.
+ * Default in case this value is not set. Using it will result in an error.
*/
- public static final int OEM_NETWORK_PREFERENCE_DEFAULT = 0;
+ public static final int OEM_NETWORK_PREFERENCE_UNINITIALIZED = 0;
/**
* If an unmetered network is available, use it.
@@ -45,17 +47,17 @@ public final class OemNetworkPreferences implements Parcelable {
/**
* If an unmetered network is available, use it.
* Otherwise, if a network with the OEM_PAID capability is available, use it.
- * Otherwise, the app doesn't get a network.
+ * Otherwise, the app doesn't get a default network.
*/
public static final int OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK = 2;
/**
- * Prefer only NET_CAPABILITY_OEM_PAID networks.
+ * Use only NET_CAPABILITY_OEM_PAID networks.
*/
public static final int OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY = 3;
/**
- * Prefer only NET_CAPABILITY_OEM_PRIVATE networks.
+ * Use only NET_CAPABILITY_OEM_PRIVATE networks.
*/
public static final int OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY = 4;
@@ -95,8 +97,6 @@ public final class OemNetworkPreferences implements Parcelable {
/**
* Builder used to create {@link OemNetworkPreferences} objects. Specify the preferred Network
* to package name mappings.
- *
- * @hide
*/
public static final class Builder {
private final Bundle mNetworkMappings;
@@ -135,7 +135,7 @@ public final class OemNetworkPreferences implements Parcelable {
* @return The builder to facilitate chaining.
*/
@NonNull
- public Builder removeNetworkPreference(@NonNull final String packageName) {
+ public Builder clearNetworkPreference(@NonNull final String packageName) {
Objects.requireNonNull(packageName);
mNetworkMappings.remove(packageName);
return this;
@@ -160,7 +160,7 @@ public final class OemNetworkPreferences implements Parcelable {
/** @hide */
@IntDef(prefix = "OEM_NETWORK_PREFERENCE_", value = {
- OEM_NETWORK_PREFERENCE_DEFAULT,
+ OEM_NETWORK_PREFERENCE_UNINITIALIZED,
OEM_NETWORK_PREFERENCE_OEM_PAID,
OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK,
OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY,
@@ -174,12 +174,14 @@ public final class OemNetworkPreferences implements Parcelable {
*
* @param value int value of OemNetworkPreference
* @return string version of OemNetworkPreference
+ *
+ * @hide
*/
@NonNull
public static String oemNetworkPreferenceToString(@OemNetworkPreference int value) {
switch (value) {
- case OEM_NETWORK_PREFERENCE_DEFAULT:
- return "OEM_NETWORK_PREFERENCE_DEFAULT";
+ case OEM_NETWORK_PREFERENCE_UNINITIALIZED:
+ return "OEM_NETWORK_PREFERENCE_UNINITIALIZED";
case OEM_NETWORK_PREFERENCE_OEM_PAID:
return "OEM_NETWORK_PREFERENCE_OEM_PAID";
case OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK:
diff --git a/packages/Connectivity/framework/src/android/net/VpnManager.java b/core/java/android/net/VpnManager.java
index 1812509ba6d2..f472ed4381d1 100644
--- a/packages/Connectivity/framework/src/android/net/VpnManager.java
+++ b/core/java/android/net/VpnManager.java
@@ -21,6 +21,7 @@ import static com.android.internal.util.Preconditions.checkNotNull;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
import android.annotation.UserIdInt;
import android.app.Activity;
import android.content.ComponentName;
@@ -37,6 +38,7 @@ import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.security.GeneralSecurityException;
+import java.util.List;
/**
* This class provides an interface for apps to manage platform VPN profiles
@@ -55,18 +57,40 @@ import java.security.GeneralSecurityException;
public class VpnManager {
/** Type representing a lack of VPN @hide */
public static final int TYPE_VPN_NONE = -1;
- /** VPN service type code @hide */
+
+ /**
+ * A VPN created by an app using the {@link VpnService} API.
+ * @hide
+ */
public static final int TYPE_VPN_SERVICE = 1;
- /** Platform VPN type code @hide */
+
+ /**
+ * A VPN created using a {@link VpnManager} API such as {@link #startProvisionedVpnProfile}.
+ * @hide
+ */
public static final int TYPE_VPN_PLATFORM = 2;
+ /**
+ * An IPsec VPN created by the built-in LegacyVpnRunner.
+ * @deprecated new Android devices should use VPN_TYPE_PLATFORM instead.
+ * @hide
+ */
+ @Deprecated
+ public static final int TYPE_VPN_LEGACY = 3;
+
+ /**
+ * Channel for VPN notifications.
+ * @hide
+ */
+ public static final String NOTIFICATION_CHANNEL_VPN = "VPN";
+
/** @hide */
- @IntDef(value = {TYPE_VPN_NONE, TYPE_VPN_SERVICE, TYPE_VPN_PLATFORM})
+ @IntDef(value = {TYPE_VPN_NONE, TYPE_VPN_SERVICE, TYPE_VPN_PLATFORM, TYPE_VPN_LEGACY})
@Retention(RetentionPolicy.SOURCE)
public @interface VpnType {}
@NonNull private final Context mContext;
- @NonNull private final IConnectivityManager mService;
+ @NonNull private final IVpnManager mService;
private static Intent getIntentForConfirmation() {
final Intent intent = new Intent();
@@ -85,9 +109,9 @@ public class VpnManager {
*
* @hide
*/
- public VpnManager(@NonNull Context ctx, @NonNull IConnectivityManager service) {
+ public VpnManager(@NonNull Context ctx, @NonNull IVpnManager service) {
mContext = checkNotNull(ctx, "missing Context");
- mService = checkNotNull(service, "missing IConnectivityManager");
+ mService = checkNotNull(service, "missing IVpnManager");
}
/**
@@ -179,6 +203,19 @@ public class VpnManager {
}
/**
+ * Resets all VPN settings back to factory defaults.
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
+ public void factoryReset() {
+ try {
+ mService.factoryReset();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Prepare for a VPN application.
* VPN permissions are checked in the {@link Vpn} class. If the caller is not {@code userId},
* {@link android.Manifest.permission.INTERACT_ACROSS_USERS_FULL} permission is required.
@@ -224,6 +261,108 @@ public class VpnManager {
}
/**
+ * Checks if a VPN app supports always-on mode.
+ *
+ * In order to support the always-on feature, an app has to
+ * <ul>
+ * <li>target {@link VERSION_CODES#N API 24} or above, and
+ * <li>not opt out through the {@link VpnService#SERVICE_META_DATA_SUPPORTS_ALWAYS_ON}
+ * meta-data field.
+ * </ul>
+ *
+ * @param userId The identifier of the user for whom the VPN app is installed.
+ * @param vpnPackage The canonical package name of the VPN app.
+ * @return {@code true} if and only if the VPN app exists and supports always-on mode.
+ * @hide
+ */
+ public boolean isAlwaysOnVpnPackageSupportedForUser(int userId, @Nullable String vpnPackage) {
+ try {
+ return mService.isAlwaysOnVpnPackageSupported(userId, vpnPackage);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Configures an always-on VPN connection through a specific application.
+ * This connection is automatically granted and persisted after a reboot.
+ *
+ * <p>The designated package should declare a {@link VpnService} in its
+ * manifest guarded by {@link android.Manifest.permission.BIND_VPN_SERVICE},
+ * otherwise the call will fail.
+ *
+ * @param userId The identifier of the user to set an always-on VPN for.
+ * @param vpnPackage The package name for an installed VPN app on the device, or {@code null}
+ * to remove an existing always-on VPN configuration.
+ * @param lockdownEnabled {@code true} to disallow networking when the VPN is not connected or
+ * {@code false} otherwise.
+ * @param lockdownAllowlist The list of packages that are allowed to access network directly
+ * when VPN is in lockdown mode but is not running. Non-existent packages are ignored so
+ * this method must be called when a package that should be allowed is installed or
+ * uninstalled.
+ * @return {@code true} if the package is set as always-on VPN controller;
+ * {@code false} otherwise.
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.CONTROL_ALWAYS_ON_VPN)
+ public boolean setAlwaysOnVpnPackageForUser(int userId, @Nullable String vpnPackage,
+ boolean lockdownEnabled, @Nullable List<String> lockdownAllowlist) {
+ try {
+ return mService.setAlwaysOnVpnPackage(
+ userId, vpnPackage, lockdownEnabled, lockdownAllowlist);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Returns the package name of the currently set always-on VPN application.
+ * If there is no always-on VPN set, or the VPN is provided by the system instead
+ * of by an app, {@code null} will be returned.
+ *
+ * @return Package name of VPN controller responsible for always-on VPN,
+ * or {@code null} if none is set.
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.CONTROL_ALWAYS_ON_VPN)
+ public String getAlwaysOnVpnPackageForUser(int userId) {
+ try {
+ return mService.getAlwaysOnVpnPackage(userId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * @return whether always-on VPN is in lockdown mode.
+ *
+ * @hide
+ **/
+ @RequiresPermission(android.Manifest.permission.CONTROL_ALWAYS_ON_VPN)
+ public boolean isVpnLockdownEnabled(int userId) {
+ try {
+ return mService.isVpnLockdownEnabled(userId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * @return the list of packages that are allowed to access network when always-on VPN is in
+ * lockdown mode but not connected. Returns {@code null} when VPN lockdown is not active.
+ *
+ * @hide
+ **/
+ @RequiresPermission(android.Manifest.permission.CONTROL_ALWAYS_ON_VPN)
+ public List<String> getVpnLockdownAllowlist(int userId) {
+ try {
+ return mService.getVpnLockdownAllowlist(userId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Return the legacy VPN information for the specified user ID.
* @hide
*/
diff --git a/packages/Connectivity/framework/src/android/net/VpnService.java b/core/java/android/net/VpnService.java
index 8e90a119fe21..e43b0b6fa635 100644
--- a/packages/Connectivity/framework/src/android/net/VpnService.java
+++ b/core/java/android/net/VpnService.java
@@ -170,12 +170,11 @@ public class VpnService extends Service {
"android.net.VpnService.SUPPORTS_ALWAYS_ON";
/**
- * Use IConnectivityManager since those methods are hidden and not
- * available in ConnectivityManager.
+ * Use IVpnManager since those methods are hidden and not available in VpnManager.
*/
- private static IConnectivityManager getService() {
- return IConnectivityManager.Stub.asInterface(
- ServiceManager.getService(Context.CONNECTIVITY_SERVICE));
+ private static IVpnManager getService() {
+ return IVpnManager.Stub.asInterface(
+ ServiceManager.getService(Context.VPN_MANAGEMENT_SERVICE));
}
/**
@@ -226,15 +225,15 @@ public class VpnService extends Service {
@SystemApi
@RequiresPermission(android.Manifest.permission.CONTROL_VPN)
public static void prepareAndAuthorize(Context context) {
- IConnectivityManager cm = getService();
+ IVpnManager vm = getService();
String packageName = context.getPackageName();
try {
// Only prepare if we're not already prepared.
int userId = context.getUserId();
- if (!cm.prepareVpn(packageName, null, userId)) {
- cm.prepareVpn(null, packageName, userId);
+ if (!vm.prepareVpn(packageName, null, userId)) {
+ vm.prepareVpn(null, packageName, userId);
}
- cm.setVpnPackageAuthorization(packageName, userId, VpnManager.TYPE_VPN_SERVICE);
+ vm.setVpnPackageAuthorization(packageName, userId, VpnManager.TYPE_VPN_SERVICE);
} catch (RemoteException e) {
// ignore
}
diff --git a/core/java/android/net/vcn/VcnManager.java b/core/java/android/net/vcn/VcnManager.java
index fa090f59a8b9..1a38338c26aa 100644
--- a/core/java/android/net/vcn/VcnManager.java
+++ b/core/java/android/net/vcn/VcnManager.java
@@ -28,8 +28,10 @@ import android.os.RemoteException;
import android.os.ServiceSpecificException;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.annotations.VisibleForTesting.Visibility;
import java.io.IOException;
+import java.util.Collections;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
@@ -67,8 +69,7 @@ import java.util.concurrent.Executor;
public class VcnManager {
@NonNull private static final String TAG = VcnManager.class.getSimpleName();
- @VisibleForTesting
- public static final Map<
+ private static final Map<
VcnUnderlyingNetworkPolicyListener, VcnUnderlyingNetworkPolicyListenerBinder>
REGISTERED_POLICY_LISTENERS = new ConcurrentHashMap<>();
@@ -88,6 +89,18 @@ public class VcnManager {
mService = requireNonNull(service, "missing service");
}
+ /**
+ * Get all currently registered VcnUnderlyingNetworkPolicyListeners for testing purposes.
+ *
+ * @hide
+ */
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ @NonNull
+ public static Map<VcnUnderlyingNetworkPolicyListener, VcnUnderlyingNetworkPolicyListenerBinder>
+ getAllPolicyListeners() {
+ return Collections.unmodifiableMap(REGISTERED_POLICY_LISTENERS);
+ }
+
// TODO: Make setVcnConfig(), clearVcnConfig() Public API
/**
* Sets the VCN configuration for a given subscription group.
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index 27dc6e0ada43..ea282afb8b8e 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -1902,7 +1902,8 @@ public final class Debug
* Retrieves the PSS memory used by the process as given by the smaps. Optionally supply a long
* array of up to 3 entries to also receive (up to 3 values in order): the Uss and SwapPss and
* Rss (only filled in as of {@link android.os.Build.VERSION_CODES#P}) of the process, and
- * another array to also retrieve the separate memtrack size.
+ * another array to also retrieve the separate memtrack sizes (up to 4 values in order): the
+ * total memtrack reported size, memtrack graphics, memtrack gl and memtrack other.
*
* @return The PSS memory usage, or 0 if failed to retrieve (i.e., given pid has gone).
* @hide
@@ -2551,6 +2552,14 @@ public final class Debug
public static native long getZramFreeKb();
/**
+ * Return total memory size in kilobytes for exported DMA-BUFs or -1 if
+ * the DMA-BUF sysfs stats at /sys/kernel/dmabuf/buffers could not be read.
+ *
+ * @hide
+ */
+ public static native long getDmabufTotalExportedKb();
+
+ /**
* Return memory size in kilobytes allocated for ION heaps or -1 if
* /sys/kernel/ion/total_heaps_kb could not be read.
*
@@ -2559,6 +2568,14 @@ public final class Debug
public static native long getIonHeapsSizeKb();
/**
+ * Return memory size in kilobytes allocated for DMA-BUF heap pools or -1 if
+ * /sys/kernel/dma_heap/total_pools_kb could not be read.
+ *
+ * @hide
+ */
+ public static native long getDmabufHeapPoolsSizeKb();
+
+ /**
* Return memory size in kilobytes allocated for ION pools or -1 if
* /sys/kernel/ion/total_pools_kb could not be read.
*
@@ -2567,13 +2584,20 @@ public final class Debug
public static native long getIonPoolsSizeKb();
/**
- * Return ION memory mapped by processes in kB.
+ * Return GPU DMA buffer usage in kB or -1 on error.
+ *
+ * @hide
+ */
+ public static native long getGpuDmaBufUsageKb();
+
+ /**
+ * Return DMA-BUF memory mapped by processes in kB.
* Notes:
* * Warning: Might impact performance as it reads /proc/<pid>/maps files for each process.
*
* @hide
*/
- public static native long getIonMappedSizeKb();
+ public static native long getDmabufMappedSizeKb();
/**
* Return memory size in kilobytes used by GPU.
diff --git a/core/java/android/os/ISystemConfig.aidl b/core/java/android/os/ISystemConfig.aidl
index 52f0ce1f054f..4d160da22ff8 100644
--- a/core/java/android/os/ISystemConfig.aidl
+++ b/core/java/android/os/ISystemConfig.aidl
@@ -35,4 +35,9 @@ interface ISystemConfig {
* @see SystemConfigManager#getDisabledUntilUsedPreinstalledCarrierAssociatedAppEntries
*/
Map getDisabledUntilUsedPreinstalledCarrierAssociatedAppEntries();
+
+ /**
+ * @see SystemConfigManager#getSystemPermissionUids
+ */
+ int[] getSystemPermissionUids(String permissionName);
}
diff --git a/core/java/android/os/SystemConfigManager.java b/core/java/android/os/SystemConfigManager.java
index 3f0632be90d1..9bfa8adc8571 100644
--- a/core/java/android/os/SystemConfigManager.java
+++ b/core/java/android/os/SystemConfigManager.java
@@ -111,4 +111,22 @@ public class SystemConfigManager {
return Collections.emptyMap();
}
}
+
+ /**
+ * Get uids which have been granted given permission in system configuration.
+ *
+ * The uids and assigning permissions are defined on data/etc/platform.xml
+ *
+ * @param permissionName The target permission.
+ * @return The uids have been granted given permission in system configuration.
+ */
+ @RequiresPermission(Manifest.permission.GET_RUNTIME_PERMISSIONS)
+ @NonNull
+ public int[] getSystemPermissionUids(@NonNull String permissionName) {
+ try {
+ return mInterface.getSystemPermissionUids(permissionName);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/core/java/android/permission/OWNERS b/core/java/android/permission/OWNERS
index d09f351bdfd1..b32346848a69 100644
--- a/core/java/android/permission/OWNERS
+++ b/core/java/android/permission/OWNERS
@@ -1,6 +1,5 @@
# Bug component: 137825
-moltmann@google.com
evanseverson@google.com
ntmyren@google.com
zhanghai@google.com
diff --git a/core/java/android/permissionpresenterservice/OWNERS b/core/java/android/permissionpresenterservice/OWNERS
index d09f351bdfd1..b32346848a69 100644
--- a/core/java/android/permissionpresenterservice/OWNERS
+++ b/core/java/android/permissionpresenterservice/OWNERS
@@ -1,6 +1,5 @@
# Bug component: 137825
-moltmann@google.com
evanseverson@google.com
ntmyren@google.com
zhanghai@google.com
diff --git a/core/java/android/print/OWNERS b/core/java/android/print/OWNERS
index 72f09832becf..28a242037f6a 100644
--- a/core/java/android/print/OWNERS
+++ b/core/java/android/print/OWNERS
@@ -1,5 +1,4 @@
# Bug component: 47273
-moltmann@google.com
svetoslavganov@android.com
svetoslavganov@google.com
diff --git a/core/java/android/print/pdf/OWNERS b/core/java/android/print/pdf/OWNERS
index 72f09832becf..28a242037f6a 100644
--- a/core/java/android/print/pdf/OWNERS
+++ b/core/java/android/print/pdf/OWNERS
@@ -1,5 +1,4 @@
# Bug component: 47273
-moltmann@google.com
svetoslavganov@android.com
svetoslavganov@google.com
diff --git a/core/java/android/printservice/OWNERS b/core/java/android/printservice/OWNERS
index 72f09832becf..28a242037f6a 100644
--- a/core/java/android/printservice/OWNERS
+++ b/core/java/android/printservice/OWNERS
@@ -1,5 +1,4 @@
# Bug component: 47273
-moltmann@google.com
svetoslavganov@android.com
svetoslavganov@google.com
diff --git a/core/java/android/printservice/recommendation/OWNERS b/core/java/android/printservice/recommendation/OWNERS
index 72f09832becf..28a242037f6a 100644
--- a/core/java/android/printservice/recommendation/OWNERS
+++ b/core/java/android/printservice/recommendation/OWNERS
@@ -1,5 +1,4 @@
# Bug component: 47273
-moltmann@google.com
svetoslavganov@android.com
svetoslavganov@google.com
diff --git a/core/java/com/android/internal/compat/CompatibilityOverrideConfig.aidl b/core/java/com/android/internal/compat/CompatibilityOverrideConfig.aidl
new file mode 100644
index 000000000000..5d02a29edcd5
--- /dev/null
+++ b/core/java/com/android/internal/compat/CompatibilityOverrideConfig.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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 com.android.internal.compat;
+
+parcelable CompatibilityOverrideConfig;
diff --git a/core/java/com/android/internal/compat/CompatibilityOverrideConfig.java b/core/java/com/android/internal/compat/CompatibilityOverrideConfig.java
new file mode 100644
index 000000000000..1c222a73eabc
--- /dev/null
+++ b/core/java/com/android/internal/compat/CompatibilityOverrideConfig.java
@@ -0,0 +1,75 @@
+/*
+ * 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 com.android.internal.compat;
+
+
+import android.app.compat.PackageOverride;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Parcelable containing compat config overrides for a given application.
+ * @hide
+ */
+public final class CompatibilityOverrideConfig implements Parcelable {
+ public final Map<Long, PackageOverride> overrides;
+
+ public CompatibilityOverrideConfig(Map<Long, PackageOverride> overrides) {
+ this.overrides = overrides;
+ }
+
+ private CompatibilityOverrideConfig(Parcel in) {
+ int keyCount = in.readInt();
+ overrides = new HashMap<>();
+ for (int i = 0; i < keyCount; i++) {
+ long key = in.readLong();
+ PackageOverride override = in.readParcelable(PackageOverride.class.getClassLoader());
+ overrides.put(key, override);
+ }
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(overrides.size());
+ for (Long key : overrides.keySet()) {
+ dest.writeLong(key);
+ dest.writeParcelable(overrides.get(key), 0);
+ }
+ }
+
+ public static final Creator<CompatibilityOverrideConfig> CREATOR =
+ new Creator<CompatibilityOverrideConfig>() {
+
+ @Override
+ public CompatibilityOverrideConfig createFromParcel(Parcel in) {
+ return new CompatibilityOverrideConfig(in);
+ }
+
+ @Override
+ public CompatibilityOverrideConfig[] newArray(int size) {
+ return new CompatibilityOverrideConfig[size];
+ }
+ };
+}
diff --git a/core/java/com/android/internal/compat/IPlatformCompat.aidl b/core/java/com/android/internal/compat/IPlatformCompat.aidl
index a5eb5f607c12..60213e4411c3 100644
--- a/core/java/com/android/internal/compat/IPlatformCompat.aidl
+++ b/core/java/com/android/internal/compat/IPlatformCompat.aidl
@@ -21,6 +21,7 @@ import com.android.internal.compat.IOverrideValidator;
import java.util.Map;
parcelable CompatibilityChangeConfig;
+parcelable CompatibilityOverrideConfig;
parcelable CompatibilityChangeInfo;
/**
* Platform private API for talking with the PlatformCompat service.
@@ -152,6 +153,17 @@ interface IPlatformCompat {
/**
* Adds overrides to compatibility changes.
*
+ * <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 setOverridesFromInstaller(in CompatibilityOverrideConfig overrides, in String packageName);
+
+ /**
+ * Adds overrides to compatibility changes.
+ *
* <p>Does not kill the app, to be only used in tests.
*
* @param overrides parcelable containing the compat change overrides to be applied
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 79a0dfd61e9f..088682c9f2d8 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -206,6 +206,7 @@ cc_library_shared {
],
shared_libs: [
+ "android.hardware.memtrack-unstable-ndk_platform",
"libandroidicu",
"libbpf_android",
"libnetdbpf",
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index 28fc8ede1653..223b4dcc0549 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -33,6 +33,7 @@
#include <string>
#include <vector>
+#include <aidl/android/hardware/memtrack/DeviceInfo.h>
#include <android-base/logging.h>
#include <bionic/malloc.h>
#include <debuggerd/client.h>
@@ -43,7 +44,9 @@
#include <nativehelper/JNIPlatformHelp.h>
#include <nativehelper/ScopedUtfChars.h>
#include "jni.h"
+#include <dmabufinfo/dmabuf_sysfs_stats.h>
#include <dmabufinfo/dmabufinfo.h>
+#include <dmabufinfo/dmabuf_sysfs_stats.h>
#include <meminfo/procmeminfo.h>
#include <meminfo/sysmeminfo.h>
#include <memtrack/memtrack.h>
@@ -519,14 +522,15 @@ static jlong android_os_Debug_getPssPid(JNIEnv *env, jobject clazz, jint pid,
}
if (outUssSwapPssRss != NULL) {
- if (env->GetArrayLength(outUssSwapPssRss) >= 1) {
+ int outLen = env->GetArrayLength(outUssSwapPssRss);
+ if (outLen >= 1) {
jlong* outUssSwapPssRssArray = env->GetLongArrayElements(outUssSwapPssRss, 0);
if (outUssSwapPssRssArray != NULL) {
outUssSwapPssRssArray[0] = uss;
- if (env->GetArrayLength(outUssSwapPssRss) >= 2) {
+ if (outLen >= 2) {
outUssSwapPssRssArray[1] = swapPss;
}
- if (env->GetArrayLength(outUssSwapPssRss) >= 3) {
+ if (outLen >= 3) {
outUssSwapPssRssArray[2] = rss;
}
}
@@ -535,10 +539,20 @@ static jlong android_os_Debug_getPssPid(JNIEnv *env, jobject clazz, jint pid,
}
if (outMemtrack != NULL) {
- if (env->GetArrayLength(outMemtrack) >= 1) {
+ int outLen = env->GetArrayLength(outMemtrack);
+ if (outLen >= 1) {
jlong* outMemtrackArray = env->GetLongArrayElements(outMemtrack, 0);
if (outMemtrackArray != NULL) {
outMemtrackArray[0] = memtrack;
+ if (outLen >= 2) {
+ outMemtrackArray[1] = graphics_mem.graphics;
+ }
+ if (outLen >= 3) {
+ outMemtrackArray[2] = graphics_mem.gl;
+ }
+ if (outLen >= 4) {
+ outMemtrackArray[3] = graphics_mem.other;
+ }
}
env->ReleaseLongArrayElements(outMemtrack, outMemtrackArray, 0);
}
@@ -802,6 +816,16 @@ static jlong android_os_Debug_getIonHeapsSizeKb(JNIEnv* env, jobject clazz) {
return heapsSizeKb;
}
+static jlong android_os_Debug_getDmabufTotalExportedKb(JNIEnv* env, jobject clazz) {
+ jlong dmabufTotalSizeKb = -1;
+ uint64_t size;
+
+ if (dmabufinfo::GetDmabufTotalExportedKb(&size)) {
+ dmabufTotalSizeKb = size;
+ }
+ return dmabufTotalSizeKb;
+}
+
static jlong android_os_Debug_getIonPoolsSizeKb(JNIEnv* env, jobject clazz) {
jlong poolsSizeKb = -1;
uint64_t size;
@@ -813,8 +837,44 @@ static jlong android_os_Debug_getIonPoolsSizeKb(JNIEnv* env, jobject clazz) {
return poolsSizeKb;
}
-static jlong android_os_Debug_getIonMappedSizeKb(JNIEnv* env, jobject clazz) {
- jlong ionPss = 0;
+static jlong android_os_Debug_getDmabufHeapPoolsSizeKb(JNIEnv* env, jobject clazz) {
+ jlong poolsSizeKb = -1;
+ uint64_t size;
+
+ if (meminfo::ReadDmabufHeapPoolsSizeKb(&size)) {
+ poolsSizeKb = size;
+ }
+
+ return poolsSizeKb;
+}
+
+static jlong android_os_Debug_getGpuDmaBufUsageKb(JNIEnv* env, jobject clazz) {
+ std::vector<aidl::android::hardware::memtrack::DeviceInfo> gpu_device_info;
+ if (!memtrack_gpu_device_info(&gpu_device_info)) {
+ return -1;
+ }
+
+ dmabufinfo::DmabufSysfsStats stats;
+ if (!GetDmabufSysfsStats(&stats)) {
+ return -1;
+ }
+
+ jlong sizeKb = 0;
+ const auto& importer_stats = stats.importer_info();
+ for (const auto& dev_info : gpu_device_info) {
+ const auto& importer_info = importer_stats.find(dev_info.name);
+ if (importer_info == importer_stats.end()) {
+ continue;
+ }
+
+ sizeKb += importer_info->second.size;
+ }
+
+ return sizeKb;
+}
+
+static jlong android_os_Debug_getDmabufMappedSizeKb(JNIEnv* env, jobject clazz) {
+ jlong dmabufPss = 0;
std::vector<dmabufinfo::DmaBuffer> dmabufs;
std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir("/proc"), closedir);
@@ -838,10 +898,10 @@ static jlong android_os_Debug_getIonMappedSizeKb(JNIEnv* env, jobject clazz) {
}
for (const dmabufinfo::DmaBuffer& buf : dmabufs) {
- ionPss += buf.size() / 1024;
+ dmabufPss += buf.size() / 1024;
}
- return ionPss;
+ return dmabufPss;
}
static jlong android_os_Debug_getGpuTotalUsageKb(JNIEnv* env, jobject clazz) {
@@ -919,10 +979,16 @@ static const JNINativeMethod gMethods[] = {
(void*)android_os_Debug_getFreeZramKb },
{ "getIonHeapsSizeKb", "()J",
(void*)android_os_Debug_getIonHeapsSizeKb },
+ { "getDmabufTotalExportedKb", "()J",
+ (void*)android_os_Debug_getDmabufTotalExportedKb },
+ { "getGpuDmaBufUsageKb", "()J",
+ (void*)android_os_Debug_getGpuDmaBufUsageKb },
{ "getIonPoolsSizeKb", "()J",
(void*)android_os_Debug_getIonPoolsSizeKb },
- { "getIonMappedSizeKb", "()J",
- (void*)android_os_Debug_getIonMappedSizeKb },
+ { "getDmabufMappedSizeKb", "()J",
+ (void*)android_os_Debug_getDmabufMappedSizeKb },
+ { "getDmabufHeapPoolsSizeKb", "()J",
+ (void*)android_os_Debug_getDmabufHeapPoolsSizeKb },
{ "getGpuTotalUsageKb", "()J",
(void*)android_os_Debug_getGpuTotalUsageKb },
{ "isVmapStack", "()Z",
diff --git a/core/proto/android/net/networkrequest.proto b/core/proto/android/net/networkrequest.proto
index 6794c8cd8acb..0041f199b448 100644
--- a/core/proto/android/net/networkrequest.proto
+++ b/core/proto/android/net/networkrequest.proto
@@ -63,6 +63,9 @@ message NetworkRequestProto {
// higher-scoring network will not go into the background immediately,
// but will linger and go into the background after the linger timeout.
TYPE_BACKGROUND_REQUEST = 5;
+ // Like TRACK_DEFAULT, but tracks the system default network, instead of
+ // the default network of the calling application.
+ TYPE_TRACK_SYSTEM_DEFAULT = 6;
}
// The type of the request. This is only used by the system and is always
// NONE elsewhere.
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index af6b97318103..24539b724f70 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1790,6 +1790,12 @@
<permission android:name="android.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS"
android:protectionLevel="signature|privileged" />
+ <!-- @SystemApi @hide Allows an application to manage an automotive device's application network
+ preference as it relates to OEM_PAID and OEM_PRIVATE capable networks.
+ <p>Not for use by third-party or privileged applications. -->
+ <permission android:name="android.permission.CONTROL_OEM_PAID_NETWORK_PREFERENCE"
+ android:protectionLevel="signature" />
+
<!-- ======================================= -->
<!-- Permissions for short range, peripheral networks -->
<!-- ======================================= -->
@@ -3797,6 +3803,11 @@
<permission android:name="android.permission.MOVE_PACKAGE"
android:protectionLevel="signature|privileged" />
+ <!-- @TestApi Allows an application to keep uninstalled packages as apks.
+ @hide -->
+ <permission android:name="android.permission.KEEP_UNINSTALLED_PACKAGES"
+ android:protectionLevel="signature" />
+
<!-- Allows an application to change whether an application component (other than its own) is
enabled or not.
<p>Not for use by third-party applications. -->
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 20cb27085661..ee45249c2030 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1547,8 +1547,8 @@
take precedence over lower ones.
See com.android.server.timedetector.TimeDetectorStrategy for available sources. -->
<string-array name="config_autoTimeSourcesPriority">
- <item>telephony</item>
<item>network</item>
+ <item>telephony</item>
</string-array>
<!-- Enables the TimeZoneRuleManager service. This is the global switch for the updateable time
diff --git a/core/tests/coretests/src/android/provider/OWNERS b/core/tests/coretests/src/android/provider/OWNERS
new file mode 100644
index 000000000000..581da714f326
--- /dev/null
+++ b/core/tests/coretests/src/android/provider/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/provider/OWNERS
diff --git a/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java b/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java
index 7917a06cb9b7..2c1bbf0d0b83 100644
--- a/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/LooperStatsTest.java
@@ -232,7 +232,7 @@ public final class LooperStatsTest {
assertThat(entry3.handlerClassName).isEqualTo(
"com.android.internal.os.LooperStatsTest$TestHandlerSecond");
assertThat(entry3.messageName).startsWith(
- "com.android.internal.os.-$$Lambda$LooperStatsTest$");
+ "com.android.internal.os.LooperStatsTest-$$ExternalSyntheticLambda");
assertThat(entry3.messageCount).isEqualTo(1);
assertThat(entry3.recordedMessageCount).isEqualTo(1);
assertThat(entry3.exceptionCount).isEqualTo(0);
diff --git a/core/tests/coretests/src/com/android/internal/widget/OWNERS b/core/tests/coretests/src/com/android/internal/widget/OWNERS
new file mode 100644
index 000000000000..b40fe240d80c
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/widget/OWNERS
@@ -0,0 +1,3 @@
+# LockSettings related
+per-file *LockPattern* = file:/services/core/java/com/android/server/locksettings/OWNERS
+per-file *Lockscreen* = file:/services/core/java/com/android/server/locksettings/OWNERS
diff --git a/data/etc/OWNERS b/data/etc/OWNERS
index 65d3a012b129..549e074d297c 100644
--- a/data/etc/OWNERS
+++ b/data/etc/OWNERS
@@ -6,7 +6,6 @@ jeffv@google.com
jsharkey@android.com
jsharkey@google.com
lorenzo@google.com
-moltmann@google.com
svetoslavganov@android.com
svetoslavganov@google.com
toddke@android.com
diff --git a/graphics/java/android/graphics/pdf/OWNERS b/graphics/java/android/graphics/pdf/OWNERS
index f04e2008a437..057dc0d9583c 100644
--- a/graphics/java/android/graphics/pdf/OWNERS
+++ b/graphics/java/android/graphics/pdf/OWNERS
@@ -5,4 +5,3 @@ djsollen@google.com
sumir@google.com
svetoslavganov@android.com
svetoslavganov@google.com
-moltmann@google.com
diff --git a/tools/hiddenapi/Android.bp b/keystore/java/android/security/AppUriAuthenticationPolicy.aidl
index e0eb06cbea7f..5c52c86f0426 100644
--- a/tools/hiddenapi/Android.bp
+++ b/keystore/java/android/security/AppUriAuthenticationPolicy.aidl
@@ -14,17 +14,6 @@
* limitations under the License.
*/
-python_binary_host {
- name: "merge_csv",
- main: "merge_csv.py",
- srcs: ["merge_csv.py"],
- version: {
- py2: {
- enabled: false,
- },
- py3: {
- enabled: true,
- embedded_launcher: true
- },
- },
-}
+package android.security;
+
+parcelable AppUriAuthenticationPolicy;
diff --git a/keystore/java/android/security/AppUriAuthenticationPolicy.java b/keystore/java/android/security/AppUriAuthenticationPolicy.java
new file mode 100644
index 000000000000..0244ce97c0d4
--- /dev/null
+++ b/keystore/java/android/security/AppUriAuthenticationPolicy.java
@@ -0,0 +1,241 @@
+/*
+ * 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.net.Uri;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * The app-URI authentication policy is set by the credential management app. This policy determines
+ * which alias for a private key and certificate pair should be used for authentication.
+ * <p>
+ * The authentication policy should be added as a parameter when calling
+ * {@link KeyChain#createManageCredentialsIntent}.
+ * <p>
+ * Example:
+ * <pre>{@code
+ * AppUriAuthenticationPolicy authenticationPolicy = new AppUriAuthenticationPolicy.Builder()
+ * .addAppAndUriMapping("com.test.pkg", testUri, "testAlias")
+ * .addAppAndUriMapping("com.test2.pkg", testUri1, "testAlias2")
+ * .addAppAndUriMapping("com.test2.pkg", testUri2, "testAlias2")
+ * .build();
+ * Intent requestIntent = KeyChain.createManageCredentialsIntent(authenticationPolicy);
+ * }</pre>
+ * <p>
+ */
+public final class AppUriAuthenticationPolicy implements Parcelable {
+
+ private static final String KEY_AUTHENTICATION_POLICY_APP_TO_URIS =
+ "authentication_policy_app_to_uris";
+ private static final String KEY_AUTHENTICATION_POLICY_APP = "policy_app";
+
+ /**
+ * The mappings from an app and list of URIs to a list of aliases, which will be used for
+ * authentication.
+ * <p>
+ * appPackageName -> uri -> alias
+ */
+ @NonNull
+ private final Map<String, UrisToAliases> mAppToUris;
+
+ private AppUriAuthenticationPolicy(@NonNull Map<String, UrisToAliases> appToUris) {
+ Objects.requireNonNull(appToUris);
+ this.mAppToUris = appToUris;
+ }
+
+ /**
+ * Builder class for {@link AppUriAuthenticationPolicy} objects.
+ */
+ public static final class Builder {
+ private Map<String, UrisToAliases> mPackageNameToUris;
+
+ /**
+ * Initialize a new Builder to construct an {@link AppUriAuthenticationPolicy}.
+ */
+ public Builder() {
+ mPackageNameToUris = new HashMap<>();
+ }
+
+ /**
+ * Adds mappings from an app and URI to an alias, which will be used for authentication.
+ * <p>
+ * If this method is called with a package name and URI that was previously added, the
+ * previous alias will be overwritten.
+ *
+ * @param appPackageName The app's package name to authenticate the user to.
+ * @param uri The URI to authenticate the user to.
+ * @param alias The alias which will be used for authentication.
+ *
+ * @return the same Builder instance.
+ */
+ @NonNull
+ public Builder addAppAndUriMapping(@NonNull String appPackageName, @NonNull Uri uri,
+ @NonNull String alias) {
+ Objects.requireNonNull(appPackageName);
+ Objects.requireNonNull(uri);
+ Objects.requireNonNull(alias);
+ UrisToAliases urisToAliases =
+ mPackageNameToUris.getOrDefault(appPackageName, new UrisToAliases());
+ urisToAliases.addUriToAlias(uri, alias);
+ mPackageNameToUris.put(appPackageName, urisToAliases);
+ return this;
+ }
+
+ /**
+ * Adds mappings from an app and list of URIs to a list of aliases, which will be used for
+ * authentication.
+ * <p>
+ * appPackageName -> uri -> alias
+ *
+ * @hide
+ */
+ @NonNull
+ public Builder addAppAndUriMapping(@NonNull String appPackageName,
+ @NonNull UrisToAliases urisToAliases) {
+ Objects.requireNonNull(appPackageName);
+ Objects.requireNonNull(urisToAliases);
+ mPackageNameToUris.put(appPackageName, urisToAliases);
+ return this;
+ }
+
+ /**
+ * Combines all of the attributes that have been set on the {@link Builder}
+ *
+ * @return a new {@link AppUriAuthenticationPolicy} object.
+ */
+ @NonNull
+ public AppUriAuthenticationPolicy build() {
+ return new AppUriAuthenticationPolicy(mPackageNameToUris);
+ }
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeMap(mAppToUris);
+ }
+
+ @NonNull
+ public static final Parcelable.Creator<AppUriAuthenticationPolicy> CREATOR =
+ new Parcelable.Creator<AppUriAuthenticationPolicy>() {
+ @Override
+ public AppUriAuthenticationPolicy createFromParcel(Parcel in) {
+ Map<String, UrisToAliases> appToUris = new HashMap<>();
+ in.readMap(appToUris, UrisToAliases.class.getClassLoader());
+ return new AppUriAuthenticationPolicy(appToUris);
+ }
+
+ @Override
+ public AppUriAuthenticationPolicy[] newArray(int size) {
+ return new AppUriAuthenticationPolicy[size];
+ }
+ };
+
+ @Override
+ public String toString() {
+ return "AppUriAuthenticationPolicy{"
+ + "mPackageNameToUris=" + mAppToUris
+ + '}';
+ }
+
+ /**
+ * Return the authentication policy mapping, which determines which alias for a private key
+ * and certificate pair should be used for authentication.
+ * <p>
+ * appPackageName -> uri -> alias
+ */
+ @NonNull
+ public Map<String, Map<Uri, String>> getAppAndUriMappings() {
+ Map<String, Map<Uri, String>> appAndUris = new HashMap<>();
+ for (Map.Entry<String, UrisToAliases> entry : mAppToUris.entrySet()) {
+ appAndUris.put(entry.getKey(), entry.getValue().getUrisToAliases());
+ }
+ return appAndUris;
+ }
+
+ /**
+ * Restore a previously saved {@link AppUriAuthenticationPolicy} from XML.
+ *
+ * @hide
+ */
+ @Nullable
+ public static AppUriAuthenticationPolicy readFromXml(@NonNull XmlPullParser parser)
+ throws IOException, XmlPullParserException {
+ AppUriAuthenticationPolicy.Builder builder = new AppUriAuthenticationPolicy.Builder();
+ int outerDepth = parser.getDepth();
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ }
+ if (!parser.getName().equals(KEY_AUTHENTICATION_POLICY_APP_TO_URIS)) {
+ continue;
+ }
+ String app = parser.getAttributeValue(null, KEY_AUTHENTICATION_POLICY_APP);
+ UrisToAliases urisToAliases = UrisToAliases.readFromXml(parser);
+ builder.addAppAndUriMapping(app, urisToAliases);
+ }
+ return builder.build();
+ }
+
+ /**
+ * Save the {@link AppUriAuthenticationPolicy} to XML.
+ *
+ * @hide
+ */
+ public void writeToXml(@NonNull XmlSerializer out) throws IOException {
+ for (Map.Entry<String, UrisToAliases> appsToUris : mAppToUris.entrySet()) {
+ out.startTag(null, KEY_AUTHENTICATION_POLICY_APP_TO_URIS);
+ out.attribute(null, KEY_AUTHENTICATION_POLICY_APP, appsToUris.getKey());
+ appsToUris.getValue().writeToXml(out);
+ out.endTag(null, KEY_AUTHENTICATION_POLICY_APP_TO_URIS);
+ }
+ }
+
+ /**
+ * Get the set of aliases found in the policy.
+ *
+ * @hide
+ */
+ public Set<String> getAliases() {
+ Set<String> aliases = new HashSet<>();
+ for (UrisToAliases appsToUris : mAppToUris.values()) {
+ aliases.addAll(appsToUris.getUrisToAliases().values());
+ }
+ return aliases;
+ }
+
+}
diff --git a/keystore/java/android/security/CredentialManagementApp.java b/keystore/java/android/security/CredentialManagementApp.java
new file mode 100644
index 000000000000..cbb23015dbe8
--- /dev/null
+++ b/keystore/java/android/security/CredentialManagementApp.java
@@ -0,0 +1,123 @@
+/*
+ * 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.util.Log;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.IOException;
+import java.util.Objects;
+
+/**
+ * The credential management app has the ability to manage the user's KeyChain credentials on
+ * unmanaged devices. {@link KeyChain#createManageCredentialsIntent} should be used by an app to
+ * request to become the credential management app. The user must approve this request before the
+ * app can manage the user's credentials.
+ * <p>
+ * Note: there can only be one credential management on the device. If another app requests to
+ * become the credential management app and the user approves, then the existing credential
+ * management app will no longer be able to manage credentials.
+ * <p>
+ * The requesting credential management app should include its authentication policy in the
+ * requesting intent. The authentication policy declares which certificates should be used for a
+ * given list of apps and URIs.
+ *
+ * @hide
+ * @see AppUriAuthenticationPolicy
+ */
+public class CredentialManagementApp {
+
+ private static final String TAG = "CredentialManagementApp";
+ private static final String KEY_PACKAGE_NAME = "package_name";
+
+ /**
+ * The credential management app's package name
+ */
+ @NonNull
+ private final String mPackageName;
+
+ /**
+ * The mappings from an app and list of URIs to a list of aliases, which will be used for
+ * authentication.
+ * <p>
+ * appPackageName -> uri -> alias
+ */
+ @NonNull
+ private AppUriAuthenticationPolicy mAuthenticationPolicy;
+
+ public CredentialManagementApp(@NonNull String packageName,
+ @NonNull AppUriAuthenticationPolicy authenticationPolicy) {
+ Objects.requireNonNull(packageName);
+ Objects.requireNonNull(authenticationPolicy);
+ mPackageName = packageName;
+ mAuthenticationPolicy = authenticationPolicy;
+ }
+
+ /**
+ * Returns the package name of the credential management app.
+ */
+ @NonNull
+ public String getPackageName() {
+ return mPackageName;
+ }
+
+ /**
+ * Returns the authentication policy of the credential management app.
+ */
+ @NonNull
+ public AppUriAuthenticationPolicy getAuthenticationPolicy() {
+ return mAuthenticationPolicy;
+ }
+
+ /**
+ * Sets the authentication policy of the credential management app.
+ */
+ public void setAuthenticationPolicy(@Nullable AppUriAuthenticationPolicy authenticationPolicy) {
+ Objects.requireNonNull(authenticationPolicy);
+ mAuthenticationPolicy = authenticationPolicy;
+ }
+
+ /**
+ * Restore a previously saved {@link CredentialManagementApp} from XML.
+ */
+ @Nullable
+ public static CredentialManagementApp readFromXml(@NonNull XmlPullParser parser) {
+ try {
+ String packageName = parser.getAttributeValue(null, KEY_PACKAGE_NAME);
+ AppUriAuthenticationPolicy policy = AppUriAuthenticationPolicy.readFromXml(parser);
+ return new CredentialManagementApp(packageName, policy);
+ } catch (XmlPullParserException | IOException e) {
+ Log.w(TAG, "Reading from xml failed", e);
+ }
+ return null;
+ }
+
+ /**
+ * Save the {@link CredentialManagementApp} to XML.
+ */
+ public void writeToXml(@NonNull XmlSerializer out) throws IOException {
+ out.attribute(null, KEY_PACKAGE_NAME, mPackageName);
+ if (mAuthenticationPolicy != null) {
+ mAuthenticationPolicy.writeToXml(out);
+ }
+ }
+}
diff --git a/keystore/java/android/security/Credentials.java b/keystore/java/android/security/Credentials.java
index 9e1fb54bedbe..ae9f866459d6 100644
--- a/keystore/java/android/security/Credentials.java
+++ b/keystore/java/android/security/Credentials.java
@@ -49,6 +49,8 @@ public class Credentials {
public static final String INSTALL_AS_USER_ACTION = "android.credentials.INSTALL_AS_USER";
+ public static final String ACTION_MANAGE_CREDENTIALS = "android.security.MANAGE_CREDENTIALS";
+
/**
* Key prefix for CA certificates.
*
diff --git a/keystore/java/android/security/IKeyChainService.aidl b/keystore/java/android/security/IKeyChainService.aidl
index 1ae6a631dbcb..f708298a2cbd 100644
--- a/keystore/java/android/security/IKeyChainService.aidl
+++ b/keystore/java/android/security/IKeyChainService.aidl
@@ -18,6 +18,8 @@ package android.security;
import android.content.pm.StringParceledListSlice;
import android.security.keymaster.KeymasterCertificateChain;
import android.security.keystore.ParcelableKeyGenParameterSpec;
+import android.security.AppUriAuthenticationPolicy;
+import android.net.Uri;
/**
* Caller is required to ensure that {@link KeyStore#unlock
@@ -47,6 +49,7 @@ interface IKeyChainService {
in byte[] privateKey, in byte[] userCert, in byte[] certChain, String alias, int uid);
boolean removeKeyPair(String alias);
boolean containsKeyPair(String alias);
+ int[] getGrants(String alias);
// APIs used by Settings
boolean deleteCaCertificate(String alias);
@@ -56,6 +59,12 @@ interface IKeyChainService {
boolean containsCaAlias(String alias);
byte[] getEncodedCaCertificate(String alias, boolean includeDeletedSystem);
List<String> getCaCertificateChainAliases(String rootAlias, boolean includeDeletedSystem);
+ void setCredentialManagementApp(String packageName, in AppUriAuthenticationPolicy policy);
+ boolean hasCredentialManagementApp();
+ String getCredentialManagementAppPackageName();
+ AppUriAuthenticationPolicy getCredentialManagementAppPolicy();
+ String getPredefinedAliasForPackageAndUri(String packageName, in Uri uri);
+ void removeCredentialManagementApp();
// APIs used by KeyChainActivity
void setGrant(int uid, String alias, boolean value);
diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java
index 6df62c0a0cba..63690d3c1567 100644
--- a/keystore/java/android/security/KeyChain.java
+++ b/keystore/java/android/security/KeyChain.java
@@ -15,6 +15,8 @@
*/
package android.security;
+import static android.security.Credentials.ACTION_MANAGE_CREDENTIALS;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SdkConstant;
@@ -122,6 +124,11 @@ public final class KeyChain {
private static final String CERT_INSTALLER_PACKAGE = "com.android.certinstaller";
/**
+ * Package name for Settings.
+ */
+ private static final String SETTINGS_PACKAGE = "com.android.settings";
+
+ /**
* Extra for use with {@link #ACTION_CHOOSER}
* @hide Also used by KeyChainActivity implementation
*/
@@ -202,6 +209,20 @@ public final class KeyChain {
public static final String EXTRA_PKCS12 = "PKCS12";
/**
+ * Extra used by {@link #createManageCredentialsIntent(AppUriAuthenticationPolicy)} to specify
+ * the authentication policy of the credential management app.
+ *
+ * <p>The authentication policy declares which alias for a private key and certificate pair
+ * should be used for authentication, given a list of apps and URIs.
+ *
+ * <p>The extra value should be a {@link AppUriAuthenticationPolicy}.
+ *
+ * @hide
+ */
+ public static final String EXTRA_AUTHENTICATION_POLICY =
+ "android.security.extra.AUTHENTICATION_POLICY";
+
+ /**
* Broadcast Action: Indicates the trusted storage has changed. Sent when
* one of this happens:
*
@@ -386,6 +407,23 @@ public final class KeyChain {
}
/**
+ * Returns an {@code Intent} that should be used by an app to request to manage the user's
+ * credentials. This is limited to unmanaged devices. The authentication policy must be
+ * provided to be able to make this request successfully.
+ *
+ * @param policy The authentication policy determines which alias for a private key and
+ * certificate pair should be used for authentication.
+ */
+ @NonNull
+ public static Intent createManageCredentialsIntent(@NonNull AppUriAuthenticationPolicy policy) {
+ Intent intent = new Intent(ACTION_MANAGE_CREDENTIALS);
+ intent.setComponent(ComponentName.createRelative(SETTINGS_PACKAGE,
+ ".security.RequestManageCredentials"));
+ intent.putExtra(EXTRA_AUTHENTICATION_POLICY, policy);
+ return intent;
+ }
+
+ /**
* Launches an {@code Activity} for the user to select the alias
* for a private key and certificate pair for authentication. The
* selected alias or null will be returned via the
diff --git a/keystore/java/android/security/KeyStoreSecurityLevel.java b/keystore/java/android/security/KeyStoreSecurityLevel.java
index 372add9b7ecb..d188b6525579 100644
--- a/keystore/java/android/security/KeyStoreSecurityLevel.java
+++ b/keystore/java/android/security/KeyStoreSecurityLevel.java
@@ -190,7 +190,7 @@ public class KeyStoreSecurityLevel {
keyDescriptor.blob = wrappedKey;
keyDescriptor.domain = wrappedKeyDescriptor.domain;
- return handleExceptions(() -> mSecurityLevel.importWrappedKey(wrappedKeyDescriptor,
+ return handleExceptions(() -> mSecurityLevel.importWrappedKey(keyDescriptor,
wrappingKeyDescriptor, maskingKey,
args.toArray(new KeyParameter[args.size()]), authenticatorSpecs));
}
diff --git a/keystore/java/android/security/UrisToAliases.java b/keystore/java/android/security/UrisToAliases.java
new file mode 100644
index 000000000000..65d433abe166
--- /dev/null
+++ b/keystore/java/android/security/UrisToAliases.java
@@ -0,0 +1,138 @@
+/*
+ * 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.net.Uri;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * The mapping from URI to alias, which determines the alias to use when the user visits a URI.
+ * This mapping is part of the {@link AppUriAuthenticationPolicy}, which specifies which app this
+ * mapping should be used for.
+ *
+ * @hide
+ * @see AppUriAuthenticationPolicy
+ */
+public final class UrisToAliases implements Parcelable {
+
+ private static final String KEY_AUTHENTICATION_POLICY_URI_TO_ALIAS =
+ "authentication_policy_uri_to_alias";
+ private static final String KEY_AUTHENTICATION_POLICY_URI = "policy_uri";
+ private static final String KEY_AUTHENTICATION_POLICY_ALIAS = "policy_alias";
+
+ /**
+ * The mappings from URIs to aliases, which will be used for authentication.
+ */
+ @NonNull
+ private final Map<Uri, String> mUrisToAliases;
+
+ public UrisToAliases() {
+ this.mUrisToAliases = new HashMap<>();
+ }
+
+ private UrisToAliases(@NonNull Map<Uri, String> urisToAliases) {
+ this.mUrisToAliases = urisToAliases;
+ }
+
+ @NonNull
+ public static final Creator<UrisToAliases> CREATOR = new Creator<UrisToAliases>() {
+ @Override
+ public UrisToAliases createFromParcel(Parcel in) {
+ Map<Uri, String> urisToAliases = new HashMap<>();
+ in.readMap(urisToAliases, String.class.getClassLoader());
+ return new UrisToAliases(urisToAliases);
+ }
+
+ @Override
+ public UrisToAliases[] newArray(int size) {
+ return new UrisToAliases[size];
+ }
+ };
+
+ /**
+ * Returns the mapping from URIs to aliases.
+ */
+ @NonNull
+ public Map<Uri, String> getUrisToAliases() {
+ return Collections.unmodifiableMap(mUrisToAliases);
+ }
+
+ /**
+ * Adds mapping from an URI to an alias.
+ */
+ public void addUriToAlias(@NonNull Uri uri, @NonNull String alias) {
+ mUrisToAliases.put(uri, alias);
+ }
+
+ /**
+ * Restore a previously saved {@link UrisToAliases} from XML.
+ */
+ @Nullable
+ public static UrisToAliases readFromXml(@NonNull XmlPullParser parser)
+ throws IOException, XmlPullParserException {
+ Map<Uri, String> urisToAliases = new HashMap<>();
+ int outerDepth = parser.getDepth();
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ }
+ if (!parser.getName().equals(KEY_AUTHENTICATION_POLICY_URI_TO_ALIAS)) {
+ continue;
+ }
+ Uri uri = Uri.parse(parser.getAttributeValue(null, KEY_AUTHENTICATION_POLICY_URI));
+ String alias = parser.getAttributeValue(null, KEY_AUTHENTICATION_POLICY_ALIAS);
+ urisToAliases.put(uri, alias);
+ }
+ return new UrisToAliases(urisToAliases);
+ }
+
+ /**
+ * Save the {@link UrisToAliases} to XML.
+ */
+ public void writeToXml(@NonNull XmlSerializer out) throws IOException {
+ for (Map.Entry<Uri, String> urisToAliases : mUrisToAliases.entrySet()) {
+ out.startTag(null, KEY_AUTHENTICATION_POLICY_URI_TO_ALIAS);
+ out.attribute(null, KEY_AUTHENTICATION_POLICY_URI, urisToAliases.getKey().toString());
+ out.attribute(null, KEY_AUTHENTICATION_POLICY_ALIAS, urisToAliases.getValue());
+ out.endTag(null, KEY_AUTHENTICATION_POLICY_URI_TO_ALIAS);
+ }
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeMap(mUrisToAliases);
+ }
+}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
index 334b1110d651..988838b46334 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
@@ -17,6 +17,7 @@
package android.security.keystore;
import android.annotation.Nullable;
+import android.content.Context;
import android.os.Build;
import android.security.Credentials;
import android.security.KeyPairGeneratorSpec;
@@ -25,6 +26,8 @@ import android.security.keymaster.KeyCharacteristics;
import android.security.keymaster.KeymasterArguments;
import android.security.keymaster.KeymasterCertificateChain;
import android.security.keymaster.KeymasterDefs;
+import android.telephony.TelephonyManager;
+import android.util.ArraySet;
import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
import com.android.internal.org.bouncycastle.asn1.ASN1InputStream;
@@ -477,11 +480,11 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
success = true;
return keyPair;
- } catch (ProviderException e) {
+ } catch (ProviderException | IllegalArgumentException | DeviceIdAttestationException e) {
if ((mSpec.getPurposes() & KeyProperties.PURPOSE_WRAP_KEY) != 0) {
throw new SecureKeyImportUnavailableException(e);
} else {
- throw e;
+ throw new ProviderException(e);
}
} finally {
if (!success) {
@@ -491,7 +494,7 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
}
private Iterable<byte[]> createCertificateChain(final String privateKeyAlias, KeyPair keyPair)
- throws ProviderException {
+ throws ProviderException, DeviceIdAttestationException {
byte[] challenge = mSpec.getAttestationChallenge();
if (challenge != null) {
KeymasterArguments args = new KeymasterArguments();
@@ -510,6 +513,60 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
Build.MODEL.getBytes(StandardCharsets.UTF_8));
}
+ int[] idTypes = mSpec.getAttestationIds();
+ if (idTypes != null) {
+ final Set<Integer> idTypesSet = new ArraySet<>(idTypes.length);
+ for (int idType : idTypes) {
+ idTypesSet.add(idType);
+ }
+ TelephonyManager telephonyService = null;
+ if (idTypesSet.contains(AttestationUtils.ID_TYPE_IMEI)
+ || idTypesSet.contains(AttestationUtils.ID_TYPE_MEID)) {
+ telephonyService =
+ (TelephonyManager) KeyStore.getApplicationContext().getSystemService(
+ Context.TELEPHONY_SERVICE);
+ if (telephonyService == null) {
+ throw new DeviceIdAttestationException(
+ "Unable to access telephony service");
+ }
+ }
+ for (final Integer idType : idTypesSet) {
+ switch (idType) {
+ case AttestationUtils.ID_TYPE_SERIAL:
+ args.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_SERIAL,
+ Build.getSerial().getBytes(StandardCharsets.UTF_8)
+ );
+ break;
+ case AttestationUtils.ID_TYPE_IMEI: {
+ final String imei = telephonyService.getImei(0);
+ if (imei == null) {
+ throw new DeviceIdAttestationException("Unable to retrieve IMEI");
+ }
+ args.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_IMEI,
+ imei.getBytes(StandardCharsets.UTF_8)
+ );
+ break;
+ }
+ case AttestationUtils.ID_TYPE_MEID: {
+ final String meid = telephonyService.getMeid(0);
+ if (meid == null) {
+ throw new DeviceIdAttestationException("Unable to retrieve MEID");
+ }
+ args.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_MEID,
+ meid.getBytes(StandardCharsets.UTF_8)
+ );
+ break;
+ }
+ case AttestationUtils.USE_INDIVIDUAL_ATTESTATION: {
+ args.addBoolean(KeymasterDefs.KM_TAG_DEVICE_UNIQUE_ATTESTATION);
+ break;
+ }
+ default:
+ throw new IllegalArgumentException("Unknown device ID type " + idType);
+ }
+ }
+ }
+
return getAttestationChain(privateKeyAlias, keyPair, args);
}
@@ -547,7 +604,8 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
}
}
- private KeymasterArguments constructKeyGenerationArguments() {
+ private KeymasterArguments constructKeyGenerationArguments()
+ throws IllegalArgumentException, DeviceIdAttestationException {
KeymasterArguments args = new KeymasterArguments();
args.addUnsignedInt(KeymasterDefs.KM_TAG_KEY_SIZE, mKeySizeBits);
args.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, mKeymasterAlgorithm);
@@ -565,9 +623,9 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
mSpec.getKeyValidityForConsumptionEnd());
addAlgorithmSpecificParameters(args);
- if (mSpec.isUniqueIdIncluded())
+ if (mSpec.isUniqueIdIncluded()) {
args.addBoolean(KeymasterDefs.KM_TAG_INCLUDE_UNIQUE_ID);
-
+ }
return args;
}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java b/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
index 16bf5469296f..087151711138 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
@@ -434,14 +434,16 @@ public class AndroidKeyStoreProvider extends Provider {
@NonNull
public static java.security.KeyStore getKeyStoreForUid(int uid)
throws KeyStoreException, NoSuchProviderException {
- String providerName = PROVIDER_NAME;
+ final java.security.KeyStore.LoadStoreParameter loadParameter;
if (android.security.keystore2.AndroidKeyStoreProvider.isInstalled()) {
- providerName = "AndroidKeyStoreLegacy";
+ loadParameter = new android.security.keystore2.AndroidKeyStoreLoadStoreParameter(
+ KeyProperties.legacyUidToNamespace(uid));
+ } else {
+ loadParameter = new AndroidKeyStoreLoadStoreParameter(uid);
}
- java.security.KeyStore result =
- java.security.KeyStore.getInstance(providerName);
+ java.security.KeyStore result = java.security.KeyStore.getInstance(PROVIDER_NAME);
try {
- result.load(new AndroidKeyStoreLoadStoreParameter(uid));
+ result.load(loadParameter);
} catch (NoSuchAlgorithmException | CertificateException | IOException e) {
throw new KeyStoreException(
"Failed to load AndroidKeyStore KeyStore for UID " + uid, e);
diff --git a/keystore/java/android/security/keystore/ArrayUtils.java b/keystore/java/android/security/keystore/ArrayUtils.java
index c8c1de4a5e83..f22b6041800f 100644
--- a/keystore/java/android/security/keystore/ArrayUtils.java
+++ b/keystore/java/android/security/keystore/ArrayUtils.java
@@ -34,6 +34,14 @@ public abstract class ArrayUtils {
return ((array != null) && (array.length > 0)) ? array.clone() : array;
}
+ /**
+ * Clones an array if it is not null and has a length greater than 0. Otherwise, returns the
+ * array.
+ */
+ public static int[] cloneIfNotEmpty(int[] array) {
+ return ((array != null) && (array.length > 0)) ? array.clone() : array;
+ }
+
public static byte[] cloneIfNotEmpty(byte[] array) {
return ((array != null) && (array.length > 0)) ? array.clone() : array;
}
diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
index c2a7b2ee6323..e92eaca2b6e9 100644
--- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java
+++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
@@ -267,6 +267,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu
private final boolean mUserPresenceRequired;
private final byte[] mAttestationChallenge;
private final boolean mDevicePropertiesAttestationIncluded;
+ private final int[] mAttestationIds;
private final boolean mUniqueIdIncluded;
private final boolean mUserAuthenticationValidWhileOnBody;
private final boolean mInvalidatedByBiometricEnrollment;
@@ -308,6 +309,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu
boolean userPresenceRequired,
byte[] attestationChallenge,
boolean devicePropertiesAttestationIncluded,
+ int[] attestationIds,
boolean uniqueIdIncluded,
boolean userAuthenticationValidWhileOnBody,
boolean invalidatedByBiometricEnrollment,
@@ -361,6 +363,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu
mUserAuthenticationType = userAuthenticationType;
mAttestationChallenge = Utils.cloneIfNotNull(attestationChallenge);
mDevicePropertiesAttestationIncluded = devicePropertiesAttestationIncluded;
+ mAttestationIds = attestationIds;
mUniqueIdIncluded = uniqueIdIncluded;
mUserAuthenticationValidWhileOnBody = userAuthenticationValidWhileOnBody;
mInvalidatedByBiometricEnrollment = invalidatedByBiometricEnrollment;
@@ -720,6 +723,25 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu
}
/**
+ * @hide
+ * Allows the caller to specify device IDs to be attested to in the certificate for the
+ * generated key pair. These values are the enums specified in
+ * {@link android.security.keystore.AttestationUtils}
+ *
+ * @see android.security.keystore.AttestationUtils#ID_TYPE_SERIAL
+ * @see android.security.keystore.AttestationUtils#ID_TYPE_IMEI
+ * @see android.security.keystore.AttestationUtils#ID_TYPE_MEID
+ * @see android.security.keystore.AttestationUtils#USE_INDIVIDUAL_ATTESTATION
+ *
+ * @return integer array representing the requested device IDs to attest.
+ */
+ @SystemApi
+ @Nullable
+ public int[] getAttestationIds() {
+ return Utils.cloneIfNotNull(mAttestationIds);
+ }
+
+ /**
* @hide This is a system-only API
*
* Returns {@code true} if the attestation certificate will contain a unique ID field.
@@ -834,6 +856,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu
private boolean mUserPresenceRequired = false;
private byte[] mAttestationChallenge = null;
private boolean mDevicePropertiesAttestationIncluded = false;
+ private int[] mAttestationIds = null;
private boolean mUniqueIdIncluded = false;
private boolean mUserAuthenticationValidWhileOnBody;
private boolean mInvalidatedByBiometricEnrollment = true;
@@ -902,6 +925,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu
mAttestationChallenge = sourceSpec.getAttestationChallenge();
mDevicePropertiesAttestationIncluded =
sourceSpec.isDevicePropertiesAttestationIncluded();
+ mAttestationIds = sourceSpec.getAttestationIds();
mUniqueIdIncluded = sourceSpec.isUniqueIdIncluded();
mUserAuthenticationValidWhileOnBody = sourceSpec.isUserAuthenticationValidWhileOnBody();
mInvalidatedByBiometricEnrollment = sourceSpec.isInvalidatedByBiometricEnrollment();
@@ -1473,6 +1497,26 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu
}
/**
+ * @hide
+ * Sets which IDs to attest in the attestation certificate for the key. The acceptable
+ * values in this integer array are the enums specified in
+ * {@link android.security.keystore.AttestationUtils}
+ *
+ * @param attestationIds the array of ID types to attest to in the certificate.
+ *
+ * @see android.security.keystore.AttestationUtils#ID_TYPE_SERIAL
+ * @see android.security.keystore.AttestationUtils#ID_TYPE_IMEI
+ * @see android.security.keystore.AttestationUtils#ID_TYPE_MEID
+ * @see android.security.keystore.AttestationUtils#USE_INDIVIDUAL_ATTESTATION
+ */
+ @SystemApi
+ @NonNull
+ public Builder setAttestationIds(@NonNull int[] attestationIds) {
+ mAttestationIds = attestationIds;
+ return this;
+ }
+
+ /**
* @hide Only system apps can use this method.
*
* Sets whether to include a temporary unique ID field in the attestation certificate.
@@ -1638,6 +1682,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu
mUserPresenceRequired,
mAttestationChallenge,
mDevicePropertiesAttestationIncluded,
+ mAttestationIds,
mUniqueIdIncluded,
mUserAuthenticationValidWhileOnBody,
mInvalidatedByBiometricEnrollment,
diff --git a/keystore/java/android/security/keystore/ParcelableKeyGenParameterSpec.java b/keystore/java/android/security/keystore/ParcelableKeyGenParameterSpec.java
index 8163472abdfb..1f2f853b67a8 100644
--- a/keystore/java/android/security/keystore/ParcelableKeyGenParameterSpec.java
+++ b/keystore/java/android/security/keystore/ParcelableKeyGenParameterSpec.java
@@ -101,6 +101,7 @@ public final class ParcelableKeyGenParameterSpec implements Parcelable {
out.writeBoolean(mSpec.isUserPresenceRequired());
out.writeByteArray(mSpec.getAttestationChallenge());
out.writeBoolean(mSpec.isDevicePropertiesAttestationIncluded());
+ out.writeIntArray(mSpec.getAttestationIds());
out.writeBoolean(mSpec.isUniqueIdIncluded());
out.writeBoolean(mSpec.isUserAuthenticationValidWhileOnBody());
out.writeBoolean(mSpec.isInvalidatedByBiometricEnrollment());
@@ -160,6 +161,7 @@ public final class ParcelableKeyGenParameterSpec implements Parcelable {
final boolean userPresenceRequired = in.readBoolean();
final byte[] attestationChallenge = in.createByteArray();
final boolean devicePropertiesAttestationIncluded = in.readBoolean();
+ final int[] attestationIds = in.createIntArray();
final boolean uniqueIdIncluded = in.readBoolean();
final boolean userAuthenticationValidWhileOnBody = in.readBoolean();
final boolean invalidatedByBiometricEnrollment = in.readBoolean();
@@ -195,6 +197,7 @@ public final class ParcelableKeyGenParameterSpec implements Parcelable {
userPresenceRequired,
attestationChallenge,
devicePropertiesAttestationIncluded,
+ attestationIds,
uniqueIdIncluded,
userAuthenticationValidWhileOnBody,
invalidatedByBiometricEnrollment,
diff --git a/keystore/java/android/security/keystore/Utils.java b/keystore/java/android/security/keystore/Utils.java
index 5722c7b53ef4..e58b1ccb5370 100644
--- a/keystore/java/android/security/keystore/Utils.java
+++ b/keystore/java/android/security/keystore/Utils.java
@@ -33,4 +33,8 @@ abstract class Utils {
static byte[] cloneIfNotNull(byte[] value) {
return (value != null) ? value.clone() : null;
}
+
+ static int[] cloneIfNotNull(int[] value) {
+ return (value != null) ? value.clone() : null;
+ }
}
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreHmacSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreHmacSpi.java
index 8475ad9fd57b..0f777495a3fe 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreHmacSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreHmacSpi.java
@@ -164,6 +164,9 @@ public abstract class AndroidKeyStoreHmacSpi extends MacSpi implements KeyStoreC
List<KeyParameter> parameters = new ArrayList<>();
parameters.add(KeyStore2ParameterUtils.makeEnum(
+ KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_SIGN
+ ));
+ parameters.add(KeyStore2ParameterUtils.makeEnum(
KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_HMAC
));
parameters.add(KeyStore2ParameterUtils.makeEnum(
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreKey.java b/keystore/java/android/security/keystore2/AndroidKeyStoreKey.java
index 32650aeda1b1..5619585d9c3c 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreKey.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreKey.java
@@ -21,7 +21,6 @@ import android.security.KeyStoreSecurityLevel;
import android.system.keystore2.Authorization;
import android.system.keystore2.Domain;
import android.system.keystore2.KeyDescriptor;
-import android.util.Log;
import java.security.Key;
@@ -127,15 +126,6 @@ public class AndroidKeyStoreKey implements Key {
return false;
}
- // If the key ids are equal and the class matches all the other fields cannot differ
- // unless we have a bug.
- if (!mAlgorithm.equals(other.mAlgorithm)
- || !mAuthorizations.equals(other.mAuthorizations)
- || !mDescriptor.equals(other.mDescriptor)) {
- Log.e("AndroidKeyStoreKey", "Bug: key ids are identical, but key metadata"
- + "differs.");
- return false;
- }
return true;
}
}
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
index 70e30d2de5a1..4d27c3454a84 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
@@ -18,16 +18,20 @@ package android.security.keystore2;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.content.Context;
import android.hardware.security.keymint.KeyParameter;
import android.hardware.security.keymint.SecurityLevel;
import android.os.Build;
import android.security.KeyPairGeneratorSpec;
+import android.security.KeyStore;
import android.security.KeyStore2;
import android.security.KeyStoreException;
import android.security.KeyStoreSecurityLevel;
import android.security.keymaster.KeymasterArguments;
import android.security.keymaster.KeymasterDefs;
import android.security.keystore.ArrayUtils;
+import android.security.keystore.AttestationUtils;
+import android.security.keystore.DeviceIdAttestationException;
import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyProperties;
import android.security.keystore.KeymasterUtils;
@@ -38,6 +42,8 @@ import android.system.keystore2.IKeystoreSecurityLevel;
import android.system.keystore2.KeyDescriptor;
import android.system.keystore2.KeyMetadata;
import android.system.keystore2.ResponseCode;
+import android.telephony.TelephonyManager;
+import android.util.ArraySet;
import android.util.Log;
import libcore.util.EmptyArray;
@@ -478,7 +484,8 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
}
throw p;
}
- } catch (UnrecoverableKeyException e) {
+ } catch (UnrecoverableKeyException | IllegalArgumentException
+ | DeviceIdAttestationException e) {
throw new ProviderException(
"Failed to construct key object from newly generated key pair.", e);
} finally {
@@ -496,7 +503,7 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
}
private void addAttestationParameters(@NonNull List<KeyParameter> params)
- throws ProviderException {
+ throws ProviderException, IllegalArgumentException, DeviceIdAttestationException {
byte[] challenge = mSpec.getAttestationChallenge();
if (challenge != null) {
@@ -526,15 +533,69 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
Build.MODEL.getBytes(StandardCharsets.UTF_8)
));
}
- } else {
- if (mSpec.isDevicePropertiesAttestationIncluded()) {
- throw new ProviderException("An attestation challenge must be provided when "
- + "requesting device properties attestation.");
+
+ int[] idTypes = mSpec.getAttestationIds();
+ if (idTypes == null) {
+ return;
+ }
+ final Set<Integer> idTypesSet = new ArraySet<>(idTypes.length);
+ for (int idType : idTypes) {
+ idTypesSet.add(idType);
+ }
+ TelephonyManager telephonyService = null;
+ if (idTypesSet.contains(AttestationUtils.ID_TYPE_IMEI)
+ || idTypesSet.contains(AttestationUtils.ID_TYPE_MEID)) {
+ telephonyService =
+ (TelephonyManager) KeyStore.getApplicationContext().getSystemService(
+ Context.TELEPHONY_SERVICE);
+ if (telephonyService == null) {
+ throw new DeviceIdAttestationException("Unable to access telephony service");
+ }
+ }
+ for (final Integer idType : idTypesSet) {
+ switch (idType) {
+ case AttestationUtils.ID_TYPE_SERIAL:
+ params.add(KeyStore2ParameterUtils.makeBytes(
+ KeymasterDefs.KM_TAG_ATTESTATION_ID_SERIAL,
+ Build.getSerial().getBytes(StandardCharsets.UTF_8)
+ ));
+ break;
+ case AttestationUtils.ID_TYPE_IMEI: {
+ final String imei = telephonyService.getImei(0);
+ if (imei == null) {
+ throw new DeviceIdAttestationException("Unable to retrieve IMEI");
+ }
+ params.add(KeyStore2ParameterUtils.makeBytes(
+ KeymasterDefs.KM_TAG_ATTESTATION_ID_IMEI,
+ imei.getBytes(StandardCharsets.UTF_8)
+ ));
+ break;
+ }
+ case AttestationUtils.ID_TYPE_MEID: {
+ final String meid = telephonyService.getMeid(0);
+ if (meid == null) {
+ throw new DeviceIdAttestationException("Unable to retrieve MEID");
+ }
+ params.add(KeyStore2ParameterUtils.makeBytes(
+ KeymasterDefs.KM_TAG_ATTESTATION_ID_MEID,
+ meid.getBytes(StandardCharsets.UTF_8)
+ ));
+ break;
+ }
+ case AttestationUtils.USE_INDIVIDUAL_ATTESTATION: {
+ params.add(KeyStore2ParameterUtils.makeBool(
+ KeymasterDefs.KM_TAG_DEVICE_UNIQUE_ATTESTATION));
+ break;
+ }
+ default:
+ throw new IllegalArgumentException("Unknown device ID type " + idType);
+ }
}
}
}
- private Collection<KeyParameter> constructKeyGenerationArguments() {
+ private Collection<KeyParameter> constructKeyGenerationArguments()
+ throws DeviceIdAttestationException, IllegalArgumentException {
List<KeyParameter> params = new ArrayList<>();
params.add(KeyStore2ParameterUtils.makeInt(KeymasterDefs.KM_TAG_KEY_SIZE, mKeySizeBits));
params.add(KeyStore2ParameterUtils.makeEnum(
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java
index 8c8acc418a0e..39607aeb3852 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java
@@ -866,7 +866,8 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi {
try {
response = mKeyStore.getKeyEntry(wrappingkey);
} catch (android.security.KeyStoreException e) {
- throw new KeyStoreException("Failed to load wrapping key.", e);
+ throw new KeyStoreException("Failed to import wrapped key. Keystore error code: "
+ + e.getErrorCode(), e);
}
KeyDescriptor wrappedKey = makeKeyDescriptor(alias);
diff --git a/packages/Connectivity/framework/src/android/net/CaptivePortalData.java b/packages/Connectivity/framework/src/android/net/CaptivePortalData.java
index 9b56b23cc879..f4b46e9f11ed 100644
--- a/packages/Connectivity/framework/src/android/net/CaptivePortalData.java
+++ b/packages/Connectivity/framework/src/android/net/CaptivePortalData.java
@@ -16,12 +16,15 @@
package android.net;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.Objects;
/**
@@ -40,10 +43,29 @@ public final class CaptivePortalData implements Parcelable {
private final long mExpiryTimeMillis;
private final boolean mCaptive;
private final String mVenueFriendlyName;
+ private final int mVenueInfoUrlSource;
+ private final int mTermsAndConditionsSource;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"CAPTIVE_PORTAL_DATA_SOURCE_"}, value = {
+ CAPTIVE_PORTAL_DATA_SOURCE_OTHER,
+ CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT})
+ public @interface CaptivePortalDataSource {}
+
+ /**
+ * Source of information: Other (default)
+ */
+ public static final int CAPTIVE_PORTAL_DATA_SOURCE_OTHER = 0;
+
+ /**
+ * Source of information: Wi-Fi Passpoint
+ */
+ public static final int CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT = 1;
private CaptivePortalData(long refreshTimeMillis, Uri userPortalUrl, Uri venueInfoUrl,
boolean isSessionExtendable, long byteLimit, long expiryTimeMillis, boolean captive,
- String venueFriendlyName) {
+ String venueFriendlyName, int venueInfoUrlSource, int termsAndConditionsSource) {
mRefreshTimeMillis = refreshTimeMillis;
mUserPortalUrl = userPortalUrl;
mVenueInfoUrl = venueInfoUrl;
@@ -52,11 +74,14 @@ public final class CaptivePortalData implements Parcelable {
mExpiryTimeMillis = expiryTimeMillis;
mCaptive = captive;
mVenueFriendlyName = venueFriendlyName;
+ mVenueInfoUrlSource = venueInfoUrlSource;
+ mTermsAndConditionsSource = termsAndConditionsSource;
}
private CaptivePortalData(Parcel p) {
this(p.readLong(), p.readParcelable(null), p.readParcelable(null), p.readBoolean(),
- p.readLong(), p.readLong(), p.readBoolean(), p.readString());
+ p.readLong(), p.readLong(), p.readBoolean(), p.readString(), p.readInt(),
+ p.readInt());
}
@Override
@@ -74,6 +99,8 @@ public final class CaptivePortalData implements Parcelable {
dest.writeLong(mExpiryTimeMillis);
dest.writeBoolean(mCaptive);
dest.writeString(mVenueFriendlyName);
+ dest.writeInt(mVenueInfoUrlSource);
+ dest.writeInt(mTermsAndConditionsSource);
}
/**
@@ -88,6 +115,9 @@ public final class CaptivePortalData implements Parcelable {
private long mExpiryTime = -1;
private boolean mCaptive;
private String mVenueFriendlyName;
+ private @CaptivePortalDataSource int mVenueInfoUrlSource = CAPTIVE_PORTAL_DATA_SOURCE_OTHER;
+ private @CaptivePortalDataSource int mUserPortalUrlSource =
+ CAPTIVE_PORTAL_DATA_SOURCE_OTHER;
/**
* Create an empty builder.
@@ -100,8 +130,8 @@ public final class CaptivePortalData implements Parcelable {
public Builder(@Nullable CaptivePortalData data) {
if (data == null) return;
setRefreshTime(data.mRefreshTimeMillis)
- .setUserPortalUrl(data.mUserPortalUrl)
- .setVenueInfoUrl(data.mVenueInfoUrl)
+ .setUserPortalUrl(data.mUserPortalUrl, data.mTermsAndConditionsSource)
+ .setVenueInfoUrl(data.mVenueInfoUrl, data.mVenueInfoUrlSource)
.setSessionExtendable(data.mIsSessionExtendable)
.setBytesRemaining(data.mByteLimit)
.setExpiryTime(data.mExpiryTimeMillis)
@@ -123,7 +153,18 @@ public final class CaptivePortalData implements Parcelable {
*/
@NonNull
public Builder setUserPortalUrl(@Nullable Uri userPortalUrl) {
+ return setUserPortalUrl(userPortalUrl, CAPTIVE_PORTAL_DATA_SOURCE_OTHER);
+ }
+
+ /**
+ * Set the URL to be used for users to login to the portal, if captive, and the source of
+ * the data, see {@link CaptivePortalDataSource}
+ */
+ @NonNull
+ public Builder setUserPortalUrl(@Nullable Uri userPortalUrl,
+ @CaptivePortalDataSource int source) {
mUserPortalUrl = userPortalUrl;
+ mUserPortalUrlSource = source;
return this;
}
@@ -132,7 +173,18 @@ public final class CaptivePortalData implements Parcelable {
*/
@NonNull
public Builder setVenueInfoUrl(@Nullable Uri venueInfoUrl) {
+ return setVenueInfoUrl(venueInfoUrl, CAPTIVE_PORTAL_DATA_SOURCE_OTHER);
+ }
+
+ /**
+ * Set the URL that can be used by users to view information about the network venue, and
+ * the source of the data, see {@link CaptivePortalDataSource}
+ */
+ @NonNull
+ public Builder setVenueInfoUrl(@Nullable Uri venueInfoUrl,
+ @CaptivePortalDataSource int source) {
mVenueInfoUrl = venueInfoUrl;
+ mVenueInfoUrlSource = source;
return this;
}
@@ -188,7 +240,8 @@ public final class CaptivePortalData implements Parcelable {
public CaptivePortalData build() {
return new CaptivePortalData(mRefreshTime, mUserPortalUrl, mVenueInfoUrl,
mIsSessionExtendable, mBytesRemaining, mExpiryTime, mCaptive,
- mVenueFriendlyName);
+ mVenueFriendlyName, mVenueInfoUrlSource,
+ mUserPortalUrlSource);
}
}
@@ -249,6 +302,22 @@ public final class CaptivePortalData implements Parcelable {
}
/**
+ * Get the information source of the Venue URL
+ * @return The source that the Venue URL was obtained from
+ */
+ public @CaptivePortalDataSource int getVenueInfoUrlSource() {
+ return mVenueInfoUrlSource;
+ }
+
+ /**
+ * Get the information source of the user portal URL
+ * @return The source that the user portal URL was obtained from
+ */
+ public @CaptivePortalDataSource int getUserPortalUrlSource() {
+ return mTermsAndConditionsSource;
+ }
+
+ /**
* Get the venue friendly name
*/
@Nullable
@@ -272,7 +341,8 @@ public final class CaptivePortalData implements Parcelable {
@Override
public int hashCode() {
return Objects.hash(mRefreshTimeMillis, mUserPortalUrl, mVenueInfoUrl,
- mIsSessionExtendable, mByteLimit, mExpiryTimeMillis, mCaptive, mVenueFriendlyName);
+ mIsSessionExtendable, mByteLimit, mExpiryTimeMillis, mCaptive, mVenueFriendlyName,
+ mVenueInfoUrlSource, mTermsAndConditionsSource);
}
@Override
@@ -286,7 +356,9 @@ public final class CaptivePortalData implements Parcelable {
&& mByteLimit == other.mByteLimit
&& mExpiryTimeMillis == other.mExpiryTimeMillis
&& mCaptive == other.mCaptive
- && Objects.equals(mVenueFriendlyName, other.mVenueFriendlyName);
+ && Objects.equals(mVenueFriendlyName, other.mVenueFriendlyName)
+ && mVenueInfoUrlSource == other.mVenueInfoUrlSource
+ && mTermsAndConditionsSource == other.mTermsAndConditionsSource;
}
@Override
@@ -300,6 +372,8 @@ public final class CaptivePortalData implements Parcelable {
+ ", expiryTime: " + mExpiryTimeMillis
+ ", captive: " + mCaptive
+ ", venueFriendlyName: " + mVenueFriendlyName
+ + ", venueInfoUrlSource: " + mVenueInfoUrlSource
+ + ", termsAndConditionsSource: " + mTermsAndConditionsSource
+ "}";
}
}
diff --git a/packages/Connectivity/framework/src/android/net/ConnectivityFrameworkInitializer.java b/packages/Connectivity/framework/src/android/net/ConnectivityFrameworkInitializer.java
index 9afa5d1311c5..92a792b78410 100644
--- a/packages/Connectivity/framework/src/android/net/ConnectivityFrameworkInitializer.java
+++ b/packages/Connectivity/framework/src/android/net/ConnectivityFrameworkInitializer.java
@@ -49,17 +49,6 @@ public final class ConnectivityFrameworkInitializer {
}
);
- // TODO: move outside of the connectivity JAR
- SystemServiceRegistry.registerContextAwareService(
- Context.VPN_MANAGEMENT_SERVICE,
- VpnManager.class,
- (context) -> {
- final ConnectivityManager cm = context.getSystemService(
- ConnectivityManager.class);
- return cm.createVpnManager();
- }
- );
-
SystemServiceRegistry.registerContextAwareService(
Context.CONNECTIVITY_DIAGNOSTICS_SERVICE,
ConnectivityDiagnosticsManager.class,
diff --git a/packages/Connectivity/framework/src/android/net/ConnectivityManager.java b/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
index d04a5bee5105..4213f8af95fc 100644
--- a/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
+++ b/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
@@ -21,6 +21,7 @@ import static android.net.NetworkRequest.Type.BACKGROUND_REQUEST;
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.NetworkRequest.Type.TRACK_SYSTEM_DEFAULT;
import static android.net.QosCallback.QosCallbackRegistrationException;
import android.annotation.CallbackExecutor;
@@ -823,6 +824,7 @@ public class ConnectivityManager {
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562)
private final IConnectivityManager mService;
+
/**
* A kludge to facilitate static access where a Context pointer isn't available, like in the
* case of the static set/getProcessDefaultNetwork methods and from the Network class.
@@ -1068,106 +1070,55 @@ public class ConnectivityManager {
}
/**
- * Checks if a VPN app supports always-on mode.
- *
- * In order to support the always-on feature, an app has to
- * <ul>
- * <li>target {@link VERSION_CODES#N API 24} or above, and
- * <li>not opt out through the {@link VpnService#SERVICE_META_DATA_SUPPORTS_ALWAYS_ON}
- * meta-data field.
- * </ul>
- *
- * @param userId The identifier of the user for whom the VPN app is installed.
- * @param vpnPackage The canonical package name of the VPN app.
- * @return {@code true} if and only if the VPN app exists and supports always-on mode.
+ * Calls VpnManager#isAlwaysOnVpnPackageSupportedForUser.
+ * @deprecated TODO: remove when callers have migrated to VpnManager.
* @hide
*/
+ @Deprecated
public boolean isAlwaysOnVpnPackageSupportedForUser(int userId, @Nullable String vpnPackage) {
- try {
- return mService.isAlwaysOnVpnPackageSupported(userId, vpnPackage);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ return getVpnManager().isAlwaysOnVpnPackageSupportedForUser(userId, vpnPackage);
}
/**
- * Configures an always-on VPN connection through a specific application.
- * This connection is automatically granted and persisted after a reboot.
- *
- * <p>The designated package should declare a {@link VpnService} in its
- * manifest guarded by {@link android.Manifest.permission.BIND_VPN_SERVICE},
- * otherwise the call will fail.
- *
- * @param userId The identifier of the user to set an always-on VPN for.
- * @param vpnPackage The package name for an installed VPN app on the device, or {@code null}
- * to remove an existing always-on VPN configuration.
- * @param lockdownEnabled {@code true} to disallow networking when the VPN is not connected or
- * {@code false} otherwise.
- * @param lockdownAllowlist The list of packages that are allowed to access network directly
- * when VPN is in lockdown mode but is not running. Non-existent packages are ignored so
- * this method must be called when a package that should be allowed is installed or
- * uninstalled.
- * @return {@code true} if the package is set as always-on VPN controller;
- * {@code false} otherwise.
+ * Calls VpnManager#setAlwaysOnVpnPackageForUser.
+ * @deprecated TODO: remove when callers have migrated to VpnManager.
* @hide
*/
- @RequiresPermission(android.Manifest.permission.CONTROL_ALWAYS_ON_VPN)
+ @Deprecated
public boolean setAlwaysOnVpnPackageForUser(int userId, @Nullable String vpnPackage,
boolean lockdownEnabled, @Nullable List<String> lockdownAllowlist) {
- try {
- return mService.setAlwaysOnVpnPackage(
- userId, vpnPackage, lockdownEnabled, lockdownAllowlist);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ return getVpnManager().setAlwaysOnVpnPackageForUser(userId, vpnPackage, lockdownEnabled,
+ lockdownAllowlist);
}
- /**
- * Returns the package name of the currently set always-on VPN application.
- * If there is no always-on VPN set, or the VPN is provided by the system instead
- * of by an app, {@code null} will be returned.
- *
- * @return Package name of VPN controller responsible for always-on VPN,
- * or {@code null} if none is set.
+ /**
+ * Calls VpnManager#getAlwaysOnVpnPackageForUser.
+ * @deprecated TODO: remove when callers have migrated to VpnManager.
* @hide
*/
- @RequiresPermission(android.Manifest.permission.CONTROL_ALWAYS_ON_VPN)
+ @Deprecated
public String getAlwaysOnVpnPackageForUser(int userId) {
- try {
- return mService.getAlwaysOnVpnPackage(userId);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ return getVpnManager().getAlwaysOnVpnPackageForUser(userId);
}
/**
- * @return whether always-on VPN is in lockdown mode.
- *
+ * Calls VpnManager#isVpnLockdownEnabled.
+ * @deprecated TODO: remove when callers have migrated to VpnManager.
* @hide
- **/
- @RequiresPermission(android.Manifest.permission.CONTROL_ALWAYS_ON_VPN)
+ */
+ @Deprecated
public boolean isVpnLockdownEnabled(int userId) {
- try {
- return mService.isVpnLockdownEnabled(userId);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
-
+ return getVpnManager().isVpnLockdownEnabled(userId);
}
/**
- * @return the list of packages that are allowed to access network when always-on VPN is in
- * lockdown mode but not connected. Returns {@code null} when VPN lockdown is not active.
- *
+ * Calls VpnManager#getVpnLockdownAllowlist.
+ * @deprecated TODO: remove when callers have migrated to VpnManager.
* @hide
- **/
- @RequiresPermission(android.Manifest.permission.CONTROL_ALWAYS_ON_VPN)
- public List<String> getVpnLockdownWhitelist(int userId) {
- try {
- return mService.getVpnLockdownWhitelist(userId);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ */
+ @Deprecated
+ public List<String> getVpnLockdownAllowlist(int userId) {
+ return getVpnManager().getVpnLockdownAllowlist(userId);
}
/**
@@ -1220,6 +1171,45 @@ public class ConnectivityManager {
}
/**
+ * Informs ConnectivityService of whether the legacy lockdown VPN, as implemented by
+ * LockdownVpnTracker, is in use. This is deprecated for new devices starting from Android 12
+ * but is still supported for backwards compatibility.
+ * <p>
+ * This type of VPN is assumed always to use the system default network, and must always declare
+ * exactly one underlying network, which is the network that was the default when the VPN
+ * connected.
+ * <p>
+ * Calling this method with {@code true} enables legacy behaviour, specifically:
+ * <ul>
+ * <li>Any VPN that applies to userId 0 behaves specially with respect to deprecated
+ * {@link #CONNECTIVITY_ACTION} broadcasts. Any such broadcasts will have the state in the
+ * {@link #EXTRA_NETWORK_INFO} replaced by state of the VPN network. Also, any time the VPN
+ * connects, a {@link #CONNECTIVITY_ACTION} broadcast will be sent for the network
+ * underlying the VPN.</li>
+ * <li>Deprecated APIs that return {@link NetworkInfo} objects will have their state
+ * similarly replaced by the VPN network state.</li>
+ * <li>Information on current network interfaces passed to NetworkStatsService will not
+ * include any VPN interfaces.</li>
+ * </ul>
+ *
+ * @param enabled whether legacy lockdown VPN is enabled or disabled
+ *
+ * TODO: @SystemApi(client = MODULE_LIBRARIES)
+ *
+ * @hide
+ */
+ @RequiresPermission(anyOf = {
+ NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
+ android.Manifest.permission.NETWORK_SETTINGS})
+ public void setLegacyLockdownVpnEnabled(boolean enabled) {
+ try {
+ mService.setLegacyLockdownVpnEnabled(enabled);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Returns details about the currently active default data network
* for a given uid. This is for internal use only to avoid spying
* other apps.
@@ -3179,20 +3169,13 @@ public class ConnectivityManager {
}
/**
- * If the LockdownVpn mechanism is enabled, updates the vpn
- * with a reload of its profile.
- *
- * @return a boolean with {@code} indicating success
- *
- * <p>This method can only be called by the system UID
- * {@hide}
+ * Calls VpnManager#updateLockdownVpn.
+ * @deprecated TODO: remove when callers have migrated to VpnManager.
+ * @hide
*/
+ @Deprecated
public boolean updateLockdownVpn() {
- try {
- return mService.updateLockdownVpn();
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ return getVpnManager().updateLockdownVpn();
}
/**
@@ -3721,7 +3704,8 @@ public class ConnectivityManager {
printStackTrace();
checkCallbackNotNull(callback);
Preconditions.checkArgument(
- reqType == TRACK_DEFAULT || need != null, "null NetworkCapabilities");
+ reqType == TRACK_DEFAULT || reqType == TRACK_SYSTEM_DEFAULT || need != null,
+ "null NetworkCapabilities");
final NetworkRequest request;
final String callingPackageName = mContext.getOpPackageName();
try {
@@ -4192,8 +4176,9 @@ public class ConnectivityManager {
}
/**
- * Registers to receive notifications about changes in the system default network. The callbacks
- * will continue to be called until either the application exits or
+ * Registers to receive notifications about changes in the application's default network. This
+ * may be a physical network or a virtual network, such as a VPN that applies to the
+ * application. The callbacks will continue to be called until either the application exits or
* {@link #unregisterNetworkCallback(NetworkCallback)} is called.
*
* <p>To avoid performance issues due to apps leaking callbacks, the system will limit the
@@ -4206,7 +4191,7 @@ public class ConnectivityManager {
* {@link #unregisterNetworkCallback(NetworkCallback)}.
*
* @param networkCallback The {@link NetworkCallback} that the system will call as the
- * system default network changes.
+ * application's default network changes.
* The callback is invoked on the default internal Handler.
* @throws RuntimeException if the app already has too many callbacks registered.
*/
@@ -4216,8 +4201,9 @@ public class ConnectivityManager {
}
/**
- * Registers to receive notifications about changes in the system default network. The callbacks
- * will continue to be called until either the application exits or
+ * Registers to receive notifications about changes in the application's default network. This
+ * may be a physical network or a virtual network, such as a VPN that applies to the
+ * application. The callbacks will continue to be called until either the application exits or
* {@link #unregisterNetworkCallback(NetworkCallback)} is called.
*
* <p>To avoid performance issues due to apps leaking callbacks, the system will limit the
@@ -4230,26 +4216,60 @@ public class ConnectivityManager {
* {@link #unregisterNetworkCallback(NetworkCallback)}.
*
* @param networkCallback The {@link NetworkCallback} that the system will call as the
- * system default network changes.
+ * application's default network changes.
* @param handler {@link Handler} to specify the thread upon which the callback will be invoked.
* @throws RuntimeException if the app already has too many callbacks registered.
*/
@RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
public void registerDefaultNetworkCallback(@NonNull NetworkCallback networkCallback,
@NonNull Handler handler) {
- // This works because if the NetworkCapabilities are null,
- // ConnectivityService takes them from the default request.
- //
- // Since the capabilities are exactly the same as the default request's
- // capabilities, this request is guaranteed, at all times, to be
- // satisfied by the same network, if any, that satisfies the default
- // request, i.e., the system default network.
CallbackHandler cbHandler = new CallbackHandler(handler);
sendRequestForNetwork(null /* NetworkCapabilities need */, networkCallback, 0,
TRACK_DEFAULT, TYPE_NONE, cbHandler);
}
/**
+ * Registers to receive notifications about changes in the system default network. The callbacks
+ * will continue to be called until either the application exits or
+ * {@link #unregisterNetworkCallback(NetworkCallback)} is called.
+ *
+ * This method should not be used to determine networking state seen by applications, because in
+ * many cases, most or even all application traffic may not use the default network directly,
+ * and traffic from different applications may go on different networks by default. As an
+ * example, if a VPN is connected, traffic from all applications might be sent through the VPN
+ * and not onto the system default network. Applications or system components desiring to do
+ * determine network state as seen by applications should use other methods such as
+ * {@link #registerDefaultNetworkCallback(NetworkCallback, Handler)}.
+ *
+ * <p>To avoid performance issues due to apps leaking callbacks, the system will limit the
+ * number of outstanding requests to 100 per app (identified by their UID), shared with
+ * all variants of this method, of {@link #requestNetwork} as well as
+ * {@link ConnectivityDiagnosticsManager#registerConnectivityDiagnosticsCallback}.
+ * Requesting a network with this method will count toward this limit. If this limit is
+ * exceeded, an exception will be thrown. To avoid hitting this issue and to conserve resources,
+ * make sure to unregister the callbacks with
+ * {@link #unregisterNetworkCallback(NetworkCallback)}.
+ *
+ * @param networkCallback The {@link NetworkCallback} that the system will call as the
+ * system default network changes.
+ * @param handler {@link Handler} to specify the thread upon which the callback will be invoked.
+ * @throws RuntimeException if the app already has too many callbacks registered.
+ *
+ * @hide
+ */
+ @SystemApi(client = MODULE_LIBRARIES)
+ @SuppressLint({"ExecutorRegistration", "PairedRegistration"})
+ @RequiresPermission(anyOf = {
+ NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
+ android.Manifest.permission.NETWORK_SETTINGS})
+ public void registerSystemDefaultNetworkCallback(@NonNull NetworkCallback networkCallback,
+ @NonNull Handler handler) {
+ CallbackHandler cbHandler = new CallbackHandler(handler);
+ sendRequestForNetwork(null /* NetworkCapabilities need */, networkCallback, 0,
+ TRACK_SYSTEM_DEFAULT, TYPE_NONE, cbHandler);
+ }
+
+ /**
* Requests bandwidth update for a given {@link Network} and returns whether the update request
* is accepted by ConnectivityService. Once accepted, ConnectivityService will poll underlying
* network connection for updated bandwidth information. The caller will be notified via
@@ -4519,6 +4539,8 @@ public class ConnectivityManager {
try {
mService.factoryReset();
mTetheringManager.stopAllTethering();
+ // TODO: Migrate callers to VpnManager#factoryReset.
+ getVpnManager().factoryReset();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -4812,9 +4834,13 @@ public class ConnectivityManager {
return new TestNetworkManager(ITestNetworkManager.Stub.asInterface(tnBinder));
}
- /** @hide */
- public VpnManager createVpnManager() {
- return new VpnManager(mContext, mService);
+ /**
+ * Temporary hack to shim calls from ConnectivityManager to VpnManager. We cannot store a
+ * private final mVpnManager because ConnectivityManager is initialized before VpnManager.
+ * @hide TODO: remove.
+ */
+ public VpnManager getVpnManager() {
+ return mContext.getSystemService(VpnManager.class);
}
/** @hide */
@@ -4848,15 +4874,6 @@ public class ConnectivityManager {
}
}
- private void setOemNetworkPreference(@NonNull final OemNetworkPreferences preference) {
- try {
- mService.setOemNetworkPreference(preference);
- } catch (RemoteException e) {
- Log.e(TAG, "setOemNetworkPreference() failed for preference: " + preference.toString());
- throw e.rethrowFromSystemServer();
- }
- }
-
@NonNull
private final List<QosCallbackConnection> mQosCallbackConnections = new ArrayList<>();
@@ -5058,4 +5075,60 @@ public class ConnectivityManager {
sendRequestForNetwork(nc, networkCallback, 0, BACKGROUND_REQUEST,
TYPE_NONE, handler == null ? getDefaultHandler() : new CallbackHandler(handler));
}
+
+ /**
+ * Listener for {@link #setOemNetworkPreference(OemNetworkPreferences, Executor,
+ * OnSetOemNetworkPreferenceListener)}.
+ * @hide
+ */
+ @SystemApi
+ public interface OnSetOemNetworkPreferenceListener {
+ /**
+ * Called when setOemNetworkPreference() successfully completes.
+ */
+ void onComplete();
+ }
+
+ /**
+ * Used by automotive devices to set the network preferences used to direct traffic at an
+ * application level as per the given OemNetworkPreferences. An example use-case would be an
+ * automotive OEM wanting to provide connectivity for applications critical to the usage of a
+ * vehicle via a particular network.
+ *
+ * Calling this will overwrite the existing preference.
+ *
+ * @param preference {@link OemNetworkPreferences} The application network preference to be set.
+ * @param executor the executor on which listener will be invoked.
+ * @param listener {@link OnSetOemNetworkPreferenceListener} optional listener used to
+ * communicate completion of setOemNetworkPreference(). This will only be
+ * called once upon successful completion of setOemNetworkPreference().
+ * @throws IllegalArgumentException if {@code preference} contains invalid preference values.
+ * @throws SecurityException if missing the appropriate permissions.
+ * @throws UnsupportedOperationException if called on a non-automotive device.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.CONTROL_OEM_PAID_NETWORK_PREFERENCE)
+ public void setOemNetworkPreference(@NonNull final OemNetworkPreferences preference,
+ @Nullable @CallbackExecutor final Executor executor,
+ @Nullable final OnSetOemNetworkPreferenceListener listener) {
+ Objects.requireNonNull(preference, "OemNetworkPreferences must be non-null");
+ if (null != listener) {
+ Objects.requireNonNull(executor, "Executor must be non-null");
+ }
+ final IOnSetOemNetworkPreferenceListener listenerInternal = listener == null ? null :
+ new IOnSetOemNetworkPreferenceListener.Stub() {
+ @Override
+ public void onComplete() {
+ executor.execute(listener::onComplete);
+ }
+ };
+
+ try {
+ mService.setOemNetworkPreference(preference, listenerInternal);
+ } catch (RemoteException e) {
+ Log.e(TAG, "setOemNetworkPreference() failed for preference: " + preference.toString());
+ throw e.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl b/packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl
index f909d1362550..6391802f3330 100644
--- a/packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl
+++ b/packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl
@@ -20,6 +20,7 @@ import android.app.PendingIntent;
import android.net.ConnectionInfo;
import android.net.ConnectivityDiagnosticsManager;
import android.net.IConnectivityDiagnosticsCallback;
+import android.net.IOnSetOemNetworkPreferenceListener;
import android.net.IQosCallback;
import android.net.ISocketKeepaliveCallback;
import android.net.LinkProperties;
@@ -42,9 +43,6 @@ import android.os.PersistableBundle;
import android.os.ResultReceiver;
import com.android.connectivity.aidl.INetworkAgent;
-import com.android.internal.net.LegacyVpnInfo;
-import com.android.internal.net.VpnConfig;
-import com.android.internal.net.VpnProfile;
/**
* Interface that answers queries about, and allows changing, the
@@ -122,35 +120,8 @@ interface IConnectivityManager
ProxyInfo getProxyForNetwork(in Network nework);
- boolean prepareVpn(String oldPackage, String newPackage, int userId);
-
- void setVpnPackageAuthorization(String packageName, int userId, int vpnType);
-
- ParcelFileDescriptor establishVpn(in VpnConfig config);
-
- boolean provisionVpnProfile(in VpnProfile profile, String packageName);
-
- void deleteVpnProfile(String packageName);
-
- void startVpnProfile(String packageName);
-
- void stopVpnProfile(String packageName);
-
- VpnConfig getVpnConfig(int userId);
-
- @UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
- void startLegacyVpn(in VpnProfile profile);
-
- LegacyVpnInfo getLegacyVpnInfo(int userId);
-
- boolean updateLockdownVpn();
- boolean isAlwaysOnVpnPackageSupported(int userId, String packageName);
- boolean setAlwaysOnVpnPackage(int userId, String packageName, boolean lockdown,
- in List<String> lockdownWhitelist);
- String getAlwaysOnVpnPackage(int userId);
- boolean isVpnLockdownEnabled(int userId);
- List<String> getVpnLockdownWhitelist(int userId);
void setRequireVpnForUids(boolean requireVpn, in UidRange[] ranges);
+ void setLegacyLockdownVpnEnabled(boolean enabled);
void setProvisioningNotificationVisible(boolean visible, int networkType, in String action);
@@ -199,10 +170,6 @@ interface IConnectivityManager
int getRestoreDefaultNetworkDelay(int networkType);
- boolean addVpnAddress(String address, int prefixLength);
- boolean removeVpnAddress(String address, int prefixLength);
- boolean setUnderlyingNetworksForVpn(in Network[] networks);
-
void factoryReset();
void startNattKeepalive(in Network network, int intervalSeconds,
@@ -222,8 +189,6 @@ interface IConnectivityManager
byte[] getNetworkWatchlistConfigHash();
int getConnectionOwnerUid(in ConnectionInfo connectionInfo);
- boolean isCallerCurrentAlwaysOnVpnApp();
- boolean isCallerCurrentAlwaysOnVpnLockdownApp();
void registerConnectivityDiagnosticsCallback(in IConnectivityDiagnosticsCallback callback,
in NetworkRequest request, String callingPackageName);
@@ -245,5 +210,6 @@ interface IConnectivityManager
void registerQosSocketCallback(in QosSocketInfo socketInfo, in IQosCallback callback);
void unregisterQosCallback(in IQosCallback callback);
- void setOemNetworkPreference(in OemNetworkPreferences preference);
+ void setOemNetworkPreference(in OemNetworkPreferences preference,
+ in IOnSetOemNetworkPreferenceListener listener);
}
diff --git a/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java b/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java
index 55b2c3c9e11f..26d14cbfaa95 100644
--- a/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java
@@ -762,12 +762,14 @@ public final class NetworkCapabilities implements Parcelable {
final int originalSignalStrength = mSignalStrength;
final int originalOwnerUid = getOwnerUid();
final int[] originalAdministratorUids = getAdministratorUids();
+ final TransportInfo originalTransportInfo = getTransportInfo();
clearAll();
mTransportTypes = (originalTransportTypes & TEST_NETWORKS_ALLOWED_TRANSPORTS)
| (1 << TRANSPORT_TEST);
mNetworkCapabilities = originalCapabilities & TEST_NETWORKS_ALLOWED_CAPABILITIES;
mNetworkSpecifier = originalSpecifier;
mSignalStrength = originalSignalStrength;
+ mTransportInfo = originalTransportInfo;
// Only retain the owner and administrator UIDs if they match the app registering the remote
// caller that registered the network.
@@ -2083,9 +2085,10 @@ public final class NetworkCapabilities implements Parcelable {
/**
* Check if private dns is broken.
*
- * @return {@code true} if {@code mPrivateDnsBroken} is set when private DNS is broken.
+ * @return {@code true} if private DNS is broken on this network.
* @hide
*/
+ @SystemApi
public boolean isPrivateDnsBroken() {
return mPrivateDnsBroken;
}
@@ -2328,6 +2331,17 @@ public final class NetworkCapabilities implements Parcelable {
}
/**
+ * Completely clears the contents of this object, removing even the capabilities that are
+ * set by default when the object is constructed.
+ * @return this builder
+ */
+ @NonNull
+ public Builder clearAll() {
+ mCaps.clearAll();
+ return this;
+ }
+
+ /**
* Sets the owner UID.
*
* The default value is {@link Process#INVALID_UID}. Pass this value to reset.
diff --git a/packages/Connectivity/framework/src/android/net/NetworkRequest.java b/packages/Connectivity/framework/src/android/net/NetworkRequest.java
index 6540397d6200..4e3085f4704d 100644
--- a/packages/Connectivity/framework/src/android/net/NetworkRequest.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkRequest.java
@@ -16,22 +16,6 @@
package android.net;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_FOREGROUND;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_PARTIAL_CONNECTIVITY;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
-
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
@@ -46,8 +30,6 @@ import android.os.Process;
import android.text.TextUtils;
import android.util.proto.ProtoOutputStream;
-import java.util.Arrays;
-import java.util.List;
import java.util.Objects;
import java.util.Set;
@@ -104,17 +86,14 @@ public class NetworkRequest implements Parcelable {
* callbacks about the single, highest scoring current network
* (if any) that matches the specified NetworkCapabilities, or
*
- * - TRACK_DEFAULT, a hybrid of the two designed such that the
- * framework will issue callbacks for the single, highest scoring
- * current network (if any) that matches the capabilities of the
- * default Internet request (mDefaultRequest), but which cannot cause
- * the framework to either create or retain the existence of any
- * specific network. Note that from the point of view of the request
- * matching code, TRACK_DEFAULT is identical to REQUEST: its special
- * behaviour is not due to different semantics, but to the fact that
- * the system will only ever create a TRACK_DEFAULT with capabilities
- * that are identical to the default request's capabilities, thus
- * causing it to share fate in every way with the default request.
+ * - TRACK_DEFAULT, which causes the framework to issue callbacks for
+ * the single, highest scoring current network (if any) that will
+ * be chosen for an app, but which cannot cause the framework to
+ * either create or retain the existence of any specific network.
+ *
+ * - TRACK_SYSTEM_DEFAULT, which causes the framework to send callbacks
+ * for the network (if any) that satisfies the default Internet
+ * request.
*
* - BACKGROUND_REQUEST, like REQUEST but does not cause any networks
* to retain the NET_CAPABILITY_FOREGROUND capability. A network with
@@ -137,6 +116,7 @@ public class NetworkRequest implements Parcelable {
TRACK_DEFAULT,
REQUEST,
BACKGROUND_REQUEST,
+ TRACK_SYSTEM_DEFAULT,
};
/**
@@ -174,30 +154,8 @@ public class NetworkRequest implements Parcelable {
* needed in terms of {@link NetworkCapabilities} features
*/
public static class Builder {
- /**
- * Capabilities that are currently compatible with VCN networks.
- */
- private static final List<Integer> VCN_SUPPORTED_CAPABILITIES = Arrays.asList(
- NET_CAPABILITY_CAPTIVE_PORTAL,
- NET_CAPABILITY_DUN,
- NET_CAPABILITY_FOREGROUND,
- NET_CAPABILITY_INTERNET,
- NET_CAPABILITY_NOT_CONGESTED,
- NET_CAPABILITY_NOT_METERED,
- NET_CAPABILITY_NOT_RESTRICTED,
- NET_CAPABILITY_NOT_ROAMING,
- NET_CAPABILITY_NOT_SUSPENDED,
- NET_CAPABILITY_NOT_VPN,
- NET_CAPABILITY_PARTIAL_CONNECTIVITY,
- NET_CAPABILITY_TEMPORARILY_NOT_METERED,
- NET_CAPABILITY_TRUSTED,
- NET_CAPABILITY_VALIDATED);
-
private final NetworkCapabilities mNetworkCapabilities;
- // A boolean that represents the user modified NOT_VCN_MANAGED capability.
- private boolean mModifiedNotVcnManaged = false;
-
/**
* Default constructor for Builder.
*/
@@ -219,7 +177,6 @@ public class NetworkRequest implements Parcelable {
// maybeMarkCapabilitiesRestricted() doesn't add back.
final NetworkCapabilities nc = new NetworkCapabilities(mNetworkCapabilities);
nc.maybeMarkCapabilitiesRestricted();
- deduceNotVcnManagedCapability(nc);
return new NetworkRequest(nc, ConnectivityManager.TYPE_NONE,
ConnectivityManager.REQUEST_ID_UNSET, Type.NONE);
}
@@ -236,9 +193,6 @@ public class NetworkRequest implements Parcelable {
*/
public Builder addCapability(@NetworkCapabilities.NetCapability int capability) {
mNetworkCapabilities.addCapability(capability);
- if (capability == NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED) {
- mModifiedNotVcnManaged = true;
- }
return this;
}
@@ -250,9 +204,6 @@ public class NetworkRequest implements Parcelable {
*/
public Builder removeCapability(@NetworkCapabilities.NetCapability int capability) {
mNetworkCapabilities.removeCapability(capability);
- if (capability == NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED) {
- mModifiedNotVcnManaged = true;
- }
return this;
}
@@ -310,9 +261,6 @@ public class NetworkRequest implements Parcelable {
@NonNull
public Builder clearCapabilities() {
mNetworkCapabilities.clearAll();
- // If the caller explicitly clear all capabilities, the NOT_VCN_MANAGED capabilities
- // should not be add back later.
- mModifiedNotVcnManaged = true;
return this;
}
@@ -432,25 +380,6 @@ public class NetworkRequest implements Parcelable {
mNetworkCapabilities.setSignalStrength(signalStrength);
return this;
}
-
- /**
- * Deduce the NET_CAPABILITY_NOT_VCN_MANAGED capability from other capabilities
- * and user intention, which includes:
- * 1. For the requests that don't have anything besides
- * {@link #VCN_SUPPORTED_CAPABILITIES}, add the NET_CAPABILITY_NOT_VCN_MANAGED to
- * allow the callers automatically utilize VCN networks if available.
- * 2. For the requests that explicitly add or remove NET_CAPABILITY_NOT_VCN_MANAGED,
- * do not alter them to allow user fire request that suits their need.
- *
- * @hide
- */
- private void deduceNotVcnManagedCapability(final NetworkCapabilities nc) {
- if (mModifiedNotVcnManaged) return;
- for (final int cap : nc.getCapabilities()) {
- if (!VCN_SUPPORTED_CAPABILITIES.contains(cap)) return;
- }
- nc.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
- }
}
// implement the Parcelable interface
@@ -601,6 +530,8 @@ public class NetworkRequest implements Parcelable {
return NetworkRequestProto.TYPE_REQUEST;
case BACKGROUND_REQUEST:
return NetworkRequestProto.TYPE_BACKGROUND_REQUEST;
+ case TRACK_SYSTEM_DEFAULT:
+ return NetworkRequestProto.TYPE_TRACK_SYSTEM_DEFAULT;
default:
return NetworkRequestProto.TYPE_UNKNOWN;
}
diff --git a/packages/Connectivity/framework/src/android/net/VpnTransportInfo.java b/packages/Connectivity/framework/src/android/net/VpnTransportInfo.java
new file mode 100644
index 000000000000..0242ba08742c
--- /dev/null
+++ b/packages/Connectivity/framework/src/android/net/VpnTransportInfo.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2017 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.annotation.SystemApi.Client.MODULE_LIBRARIES;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.SparseArray;
+
+import com.android.internal.util.MessageUtils;
+
+import java.util.Objects;
+
+/**
+ * Container for VPN-specific transport information.
+ *
+ * @see android.net.TransportInfo
+ * @see NetworkCapabilities#getTransportInfo()
+ *
+ * @hide
+ */
+@SystemApi(client = MODULE_LIBRARIES)
+public final class VpnTransportInfo implements TransportInfo, Parcelable {
+ private static final SparseArray<String> sTypeToString =
+ MessageUtils.findMessageNames(new Class[]{VpnManager.class}, new String[]{"TYPE_VPN_"});
+
+ /** Type of this VPN. */
+ @VpnManager.VpnType public final int type;
+
+ public VpnTransportInfo(@VpnManager.VpnType int type) {
+ this.type = type;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof VpnTransportInfo)) return false;
+
+ VpnTransportInfo that = (VpnTransportInfo) o;
+ return this.type == that.type;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(type);
+ }
+
+ @Override
+ public String toString() {
+ final String typeString = sTypeToString.get(type, "VPN_TYPE_???");
+ return String.format("VpnTransportInfo{%s}", typeString);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeInt(type);
+ }
+
+ public static final @NonNull Creator<VpnTransportInfo> CREATOR =
+ new Creator<VpnTransportInfo>() {
+ public VpnTransportInfo createFromParcel(Parcel in) {
+ return new VpnTransportInfo(in.readInt());
+ }
+ public VpnTransportInfo[] newArray(int size) {
+ return new VpnTransportInfo[size];
+ }
+ };
+}
diff --git a/packages/Connectivity/service/Android.bp b/packages/Connectivity/service/Android.bp
index 8fc318180778..ed1716fad8c0 100644
--- a/packages/Connectivity/service/Android.bp
+++ b/packages/Connectivity/service/Android.bp
@@ -25,7 +25,6 @@ cc_library_shared {
],
srcs: [
"jni/com_android_server_TestNetworkService.cpp",
- "jni/com_android_server_connectivity_Vpn.cpp",
"jni/onload.cpp",
],
shared_libs: [
diff --git a/packages/Connectivity/service/jni/onload.cpp b/packages/Connectivity/service/jni/onload.cpp
index 3afcb0e8f688..00128794bcd0 100644
--- a/packages/Connectivity/service/jni/onload.cpp
+++ b/packages/Connectivity/service/jni/onload.cpp
@@ -19,7 +19,6 @@
namespace android {
-int register_android_server_connectivity_Vpn(JNIEnv* env);
int register_android_server_TestNetworkService(JNIEnv* env);
extern "C" jint JNI_OnLoad(JavaVM* vm, void*) {
@@ -29,12 +28,11 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void*) {
return JNI_ERR;
}
- if (register_android_server_connectivity_Vpn(env) < 0
- || register_android_server_TestNetworkService(env) < 0) {
+ if (register_android_server_TestNetworkService(env) < 0) {
return JNI_ERR;
}
return JNI_VERSION_1_6;
}
-}; \ No newline at end of file
+};
diff --git a/packages/PackageInstaller/OWNERS b/packages/PackageInstaller/OWNERS
index 252670a6fb13..8e1774b0baa2 100644
--- a/packages/PackageInstaller/OWNERS
+++ b/packages/PackageInstaller/OWNERS
@@ -1,5 +1,4 @@
svetoslavganov@google.com
-moltmann@google.com
toddke@google.com
suprabh@google.com
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 39be9cbff40d..c3fc019c6787 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -87,6 +87,7 @@
<!-- TODO(b/152310230): remove once APIs are confirmed to be sufficient -->
<uses-permission android:name="com.android.permission.USE_INSTALLER_V2" />
<uses-permission android:name="android.permission.MOVE_PACKAGE" />
+ <uses-permission android:name="android.permission.KEEP_UNINSTALLED_PACKAGES" />
<uses-permission android:name="android.permission.CLEAR_APP_USER_DATA" />
<uses-permission android:name="android.permission.CLEAR_APP_CACHE" />
<uses-permission android:name="android.permission.ACCESS_INSTANT_APPS" />
@@ -357,6 +358,7 @@
<uses-permission android:name="android.permission.BIND_VOICE_INTERACTION" />
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
<uses-permission android:name="android.permission.DOWNLOAD_WITHOUT_NOTIFICATION" />
+ <uses-permission android:name="android.permission.BIND_RESUME_ON_REBOOT_SERVICE" />
<application android:label="@string/app_label"
android:theme="@android:style/Theme.DeviceDefault.DayNight"
diff --git a/packages/Shell/OWNERS b/packages/Shell/OWNERS
index 6ba1fcb058b1..34901f5830c4 100644
--- a/packages/Shell/OWNERS
+++ b/packages/Shell/OWNERS
@@ -6,7 +6,6 @@ nandana@google.com
svetoslavganov@google.com
hackbod@google.com
yamasani@google.com
-moltmann@google.com
toddke@google.com
cbrubaker@google.com
omakoto@google.com
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
index c5a35eaf3e6c..d18902a7796b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
@@ -27,12 +27,11 @@ import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.UserInfo;
import android.net.ConnectivityManager;
import android.net.ConnectivityManager.NetworkCallback;
-import android.net.IConnectivityManager;
import android.net.Network;
import android.net.NetworkRequest;
+import android.net.VpnManager;
import android.os.Handler;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.os.UserHandle;
import android.os.UserManager;
import android.security.KeyChain;
@@ -75,7 +74,7 @@ public class SecurityControllerImpl extends CurrentUserTracker implements Securi
private final Context mContext;
private final ConnectivityManager mConnectivityManager;
- private final IConnectivityManager mConnectivityManagerService;
+ private final VpnManager mVpnManager;
private final DevicePolicyManager mDevicePolicyManager;
private final PackageManager mPackageManager;
private final UserManager mUserManager;
@@ -107,8 +106,7 @@ public class SecurityControllerImpl extends CurrentUserTracker implements Securi
context.getSystemService(Context.DEVICE_POLICY_SERVICE);
mConnectivityManager = (ConnectivityManager)
context.getSystemService(Context.CONNECTIVITY_SERVICE);
- mConnectivityManagerService = IConnectivityManager.Stub.asInterface(
- ServiceManager.getService(Context.CONNECTIVITY_SERVICE));
+ mVpnManager = context.getSystemService(VpnManager.class);
mPackageManager = context.getPackageManager();
mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
mBgExecutor = bgExecutor;
@@ -346,25 +344,19 @@ public class SecurityControllerImpl extends CurrentUserTracker implements Securi
private void updateState() {
// Find all users with an active VPN
SparseArray<VpnConfig> vpns = new SparseArray<>();
- try {
- for (UserInfo user : mUserManager.getUsers()) {
- VpnConfig cfg = mConnectivityManagerService.getVpnConfig(user.id);
- if (cfg == null) {
+ for (UserInfo user : mUserManager.getUsers()) {
+ VpnConfig cfg = mVpnManager.getVpnConfig(user.id);
+ if (cfg == null) {
+ continue;
+ } else if (cfg.legacy) {
+ // Legacy VPNs should do nothing if the network is disconnected. Third-party
+ // VPN warnings need to continue as traffic can still go to the app.
+ LegacyVpnInfo legacyVpn = mVpnManager.getLegacyVpnInfo(user.id);
+ if (legacyVpn == null || legacyVpn.state != LegacyVpnInfo.STATE_CONNECTED) {
continue;
- } else if (cfg.legacy) {
- // Legacy VPNs should do nothing if the network is disconnected. Third-party
- // VPN warnings need to continue as traffic can still go to the app.
- LegacyVpnInfo legacyVpn = mConnectivityManagerService.getLegacyVpnInfo(user.id);
- if (legacyVpn == null || legacyVpn.state != LegacyVpnInfo.STATE_CONNECTED) {
- continue;
- }
}
- vpns.put(user.id, cfg);
}
- } catch (RemoteException rme) {
- // Roll back to previous state
- Log.e(TAG, "Unable to list active VPNs", rme);
- return;
+ vpns.put(user.id, cfg);
}
mCurrentVpns = vpns;
}
diff --git a/services/core/Android.bp b/services/core/Android.bp
index ba7f0805f3da..8cb52e5f6f4e 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -98,7 +98,6 @@ java_library_static {
"android.hardware.power-V1-java",
"android.hardware.power-V1.0-java",
"android.hardware.vibrator-V1-java",
- "android.net.ipsec.ike.stubs.module_lib",
"app-compat-annotations",
"framework-tethering.stubs.module_lib",
"service-permission.stubs.system_server",
@@ -207,8 +206,5 @@ filegroup {
"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",
- "java/com/android/server/net/LockdownVpnTracker.java",
],
}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 2f883517a378..558fbc25d7df 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -16,7 +16,6 @@
package com.android.server;
-import static android.Manifest.permission.NETWORK_STACK;
import static android.Manifest.permission.RECEIVE_DATA_ACTIVITY_CHANGE;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport.KEY_NETWORK_PROBES_ATTEMPTED_BITMASK;
@@ -45,8 +44,9 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PAID;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE;
import static android.net.NetworkCapabilities.NET_CAPABILITY_PARTIAL_CONNECTIVITY;
import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
@@ -95,6 +95,7 @@ import android.net.INetworkMonitor;
import android.net.INetworkMonitorCallbacks;
import android.net.INetworkPolicyListener;
import android.net.INetworkStatsService;
+import android.net.IOnSetOemNetworkPreferenceListener;
import android.net.IQosCallback;
import android.net.ISocketKeepaliveCallback;
import android.net.InetAddresses;
@@ -132,12 +133,13 @@ import android.net.RouteInfo;
import android.net.RouteInfoParcel;
import android.net.SocketKeepalive;
import android.net.TetheringManager;
+import android.net.TransportInfo;
import android.net.UidRange;
import android.net.UidRangeParcel;
import android.net.UnderlyingNetworkInfo;
import android.net.Uri;
import android.net.VpnManager;
-import android.net.VpnService;
+import android.net.VpnTransportInfo;
import android.net.metrics.INetdEventListener;
import android.net.metrics.IpConnectivityLog;
import android.net.metrics.NetworkEvent;
@@ -168,8 +170,6 @@ import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
-import android.security.Credentials;
-import android.security.KeyStore;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.ArraySet;
@@ -185,9 +185,6 @@ import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IBatteryStats;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.net.LegacyVpnInfo;
-import com.android.internal.net.VpnConfig;
-import com.android.internal.net.VpnProfile;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.AsyncChannel;
import com.android.internal.util.IndentingPrintWriter;
@@ -212,9 +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;
import com.android.server.net.NetworkPolicyManagerInternal;
import com.android.server.utils.PriorityDump;
@@ -307,18 +302,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
private final PerUidCounter mNetworkRequestCounter;
- private KeyStore mKeyStore;
-
- @VisibleForTesting
- @GuardedBy("mVpns")
- protected final SparseArray<Vpn> mVpns = new SparseArray<>();
-
- // TODO: investigate if mLockdownEnabled can be removed and replaced everywhere by
- // a direct call to LockdownVpnTracker.isEnabled().
- @GuardedBy("mVpns")
- private boolean mLockdownEnabled;
- @GuardedBy("mVpns")
- private LockdownVpnTracker mLockdownTracker;
+ private volatile boolean mLockdownEnabled;
/**
* Stale copy of uid rules provided by NPMS. As long as they are accessed only in internal
@@ -569,6 +553,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
private static final int EVENT_SET_REQUIRE_VPN_FOR_UIDS = 47;
/**
+ * used internally when setting the default networks for OemNetworkPreferences.
+ * obj = OemNetworkPreferences
+ */
+ private static final int EVENT_SET_OEM_NETWORK_PREFERENCE = 48;
+
+ /**
* Argument for {@link #EVENT_PROVISIONING_NOTIFICATION} to indicate that the notification
* should be shown.
*/
@@ -753,6 +743,27 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
}
+ // When a lockdown VPN connects, send another CONNECTED broadcast for the underlying
+ // network type, to preserve previous behaviour.
+ private void maybeSendLegacyLockdownBroadcast(@NonNull NetworkAgentInfo vpnNai) {
+ if (vpnNai != mService.getLegacyLockdownNai()) return;
+
+ if (vpnNai.declaredUnderlyingNetworks == null
+ || vpnNai.declaredUnderlyingNetworks.length != 1) {
+ Log.wtf(TAG, "Legacy lockdown VPN must have exactly one underlying network: "
+ + Arrays.toString(vpnNai.declaredUnderlyingNetworks));
+ return;
+ }
+ final NetworkAgentInfo underlyingNai = mService.getNetworkAgentInfoForNetwork(
+ vpnNai.declaredUnderlyingNetworks[0]);
+ if (underlyingNai == null) return;
+
+ final int type = underlyingNai.networkInfo.getType();
+ final DetailedState state = DetailedState.CONNECTED;
+ maybeLogBroadcast(underlyingNai, state, type, true /* isDefaultNetwork */);
+ mService.sendLegacyNetworkBroadcast(underlyingNai, state, type);
+ }
+
/** Adds the given network to the specified legacy type list. */
public void add(int type, NetworkAgentInfo nai) {
if (!isTypeSupported(type)) {
@@ -770,9 +781,17 @@ public class ConnectivityService extends IConnectivityManager.Stub
// Send a broadcast if this is the first network of its type or if it's the default.
final boolean isDefaultNetwork = mService.isDefaultNetwork(nai);
+
+ // If a legacy lockdown VPN is active, override the NetworkInfo state in all broadcasts
+ // to preserve previous behaviour.
+ final DetailedState state = mService.getLegacyLockdownState(DetailedState.CONNECTED);
if ((list.size() == 1) || isDefaultNetwork) {
- maybeLogBroadcast(nai, DetailedState.CONNECTED, type, isDefaultNetwork);
- mService.sendLegacyNetworkBroadcast(nai, DetailedState.CONNECTED, type);
+ maybeLogBroadcast(nai, state, type, isDefaultNetwork);
+ mService.sendLegacyNetworkBroadcast(nai, state, type);
+ }
+
+ if (type == TYPE_VPN && state == DetailedState.CONNECTED) {
+ maybeSendLegacyLockdownBroadcast(nai);
}
}
@@ -967,13 +986,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
/**
- * Get a reference to the system keystore.
- */
- public KeyStore getKeyStore() {
- return KeyStore.getInstance();
- }
-
- /**
* @see ProxyTracker
*/
public ProxyTracker makeProxyTracker(@NonNull Context context,
@@ -1037,10 +1049,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
mMetricsLog = logger;
mNetworkRanker = new NetworkRanker();
- final NetworkRequest defaultInternetRequest = createDefaultInternetRequestForTransport(
- -1, NetworkRequest.Type.REQUEST);
- mDefaultRequest = new NetworkRequestInfo(null, defaultInternetRequest, new Binder(),
- null /* attributionTag */);
+ final NetworkRequest defaultInternetRequest = createDefaultRequest();
+ mDefaultRequest = new NetworkRequestInfo(
+ defaultInternetRequest, null, new Binder(),
+ null /* attributionTags */);
mNetworkRequests.put(defaultInternetRequest, mDefaultRequest);
mDefaultNetworkRequests.add(mDefaultRequest);
mNetworkRequestInfoLogs.log("REGISTER " + mDefaultRequest);
@@ -1082,7 +1094,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
mProxyTracker = mDeps.makeProxyTracker(mContext, mHandler);
mNetd = netd;
- mKeyStore = mDeps.getKeyStore();
mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
mLocationPermissionChecker = new LocationPermissionChecker(mContext);
@@ -1171,43 +1182,15 @@ public class ConnectivityService extends IConnectivityManager.Stub
mPermissionMonitor = new PermissionMonitor(mContext, mNetd);
- // Set up the listener for user state for creating user VPNs.
+ // Listen for user add/removes to inform PermissionMonitor.
// Should run on mHandler to avoid any races.
IntentFilter intentFilter = new IntentFilter();
- intentFilter.addAction(Intent.ACTION_USER_STARTED);
- intentFilter.addAction(Intent.ACTION_USER_STOPPED);
intentFilter.addAction(Intent.ACTION_USER_ADDED);
intentFilter.addAction(Intent.ACTION_USER_REMOVED);
- intentFilter.addAction(Intent.ACTION_USER_UNLOCKED);
mUserAllContext = mContext.createContextAsUser(UserHandle.ALL, 0 /* flags */);
- mUserAllContext.registerReceiver(
- mIntentReceiver,
- intentFilter,
- null /* broadcastPermission */,
- mHandler);
- mContext.createContextAsUser(UserHandle.SYSTEM, 0 /* flags */).registerReceiver(
- mUserPresentReceiver,
- new IntentFilter(Intent.ACTION_USER_PRESENT),
- null /* broadcastPermission */,
- null /* scheduler */);
-
- // Listen to package add and removal events for all users.
- intentFilter = new IntentFilter();
- intentFilter.addAction(Intent.ACTION_PACKAGE_REPLACED);
- intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
- intentFilter.addDataScheme("package");
- mUserAllContext.registerReceiver(
- mIntentReceiver,
- intentFilter,
- null /* broadcastPermission */,
- mHandler);
-
- // Listen to lockdown VPN reset.
- intentFilter = new IntentFilter();
- intentFilter.addAction(LockdownVpnTracker.ACTION_LOCKDOWN_RESET);
- mUserAllContext.registerReceiver(
- mIntentReceiver, intentFilter, NETWORK_STACK, mHandler);
+ mUserAllContext.registerReceiver(mIntentReceiver, intentFilter,
+ null /* broadcastPermission */, mHandler);
mNetworkActivityTracker = new LegacyNetworkActivityTracker(mContext, mNMS);
@@ -1248,21 +1231,29 @@ public class ConnectivityService extends IConnectivityManager.Stub
private static NetworkCapabilities createDefaultNetworkCapabilitiesForUid(int uid) {
final NetworkCapabilities netCap = new NetworkCapabilities();
netCap.addCapability(NET_CAPABILITY_INTERNET);
- netCap.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
netCap.removeCapability(NET_CAPABILITY_NOT_VPN);
netCap.setSingleUid(uid);
return netCap;
}
+ private NetworkRequest createDefaultRequest() {
+ return createDefaultInternetRequestForTransport(
+ TYPE_NONE, NetworkRequest.Type.REQUEST);
+ }
+
private NetworkRequest createDefaultInternetRequestForTransport(
int transportType, NetworkRequest.Type type) {
final NetworkCapabilities netCap = new NetworkCapabilities();
netCap.addCapability(NET_CAPABILITY_INTERNET);
- netCap.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
netCap.setRequestorUidAndPackageName(Process.myUid(), mContext.getPackageName());
- if (transportType > -1) {
+ if (transportType > TYPE_NONE) {
netCap.addTransportType(transportType);
}
+ return createNetworkRequest(type, netCap);
+ }
+
+ private NetworkRequest createNetworkRequest(
+ NetworkRequest.Type type, NetworkCapabilities netCap) {
return new NetworkRequest(netCap, TYPE_NONE, nextNetworkRequestId(), type);
}
@@ -1312,7 +1303,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (enable) {
handleRegisterNetworkRequest(new NetworkRequestInfo(
- null, networkRequest, new Binder(), null /* attributionTag */));
+ networkRequest, null, new Binder(),
+ null /* attributionTags */));
} else {
handleReleaseNetworkRequest(networkRequest, Process.SYSTEM_UID,
/* callOnUnavailable */ false);
@@ -1385,9 +1377,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
private Network[] getVpnUnderlyingNetworks(int uid) {
- synchronized (mVpns) {
- if (mLockdownEnabled) return null;
- }
+ if (mLockdownEnabled) return null;
final NetworkAgentInfo nai = getVpnForUid(uid);
if (nai != null) return nai.declaredUnderlyingNetworks;
return null;
@@ -1472,11 +1462,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (isNetworkWithCapabilitiesBlocked(nc, uid, ignoreBlocked)) {
networkInfo.setDetailedState(DetailedState.BLOCKED, null, null);
}
- synchronized (mVpns) {
- if (mLockdownTracker != null) {
- mLockdownTracker.augmentNetworkInfo(networkInfo);
- }
- }
+ networkInfo.setDetailedState(
+ getLegacyLockdownState(networkInfo.getDetailedState()),
+ "" /* reason */, null /* extraInfo */);
}
/**
@@ -1535,14 +1523,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
return nai.network;
}
- // Public because it's used by mLockdownTracker.
- public NetworkInfo getActiveNetworkInfoUnfiltered() {
- enforceAccessPermission();
- final int uid = mDeps.getCallingUid();
- NetworkState state = getUnfilteredActiveNetworkState(uid);
- return state.networkInfo;
- }
-
@Override
public NetworkInfo getActiveNetworkInfoForUid(int uid, boolean ignoreBlocked) {
NetworkStack.checkNetworkStackPermission(mContext);
@@ -2164,22 +2144,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
isBackgroundRestricted);
}
- /**
- * Require that the caller is either in the same user or has appropriate permission to interact
- * across users.
- *
- * @param userId Target user for whatever operation the current IPC is supposed to perform.
- */
- private void enforceCrossUserPermission(int userId) {
- if (userId == UserHandle.getCallingUserId()) {
- // Not a cross-user call.
- return;
- }
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
- "ConnectivityService");
- }
-
private boolean checkAnyPermissionOf(String... permissions) {
for (String permission : permissions) {
if (mContext.checkCallingOrSelfPermission(permission) == PERMISSION_GRANTED) {
@@ -2260,12 +2224,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, pid, uid);
}
- private void enforceControlAlwaysOnVpnPermission() {
- mContext.enforceCallingOrSelfPermission(
- android.Manifest.permission.CONTROL_ALWAYS_ON_VPN,
- "ConnectivityService");
- }
-
private void enforceNetworkStackOrSettingsPermission() {
enforceAnyPermissionOf(
android.Manifest.permission.NETWORK_SETTINGS,
@@ -2290,6 +2248,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK);
}
+ private void enforceOemNetworkPreferencesPermission() {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.CONTROL_OEM_PAID_NETWORK_PREFERENCE,
+ "ConnectivityService");
+ }
+
private boolean checkNetworkStackPermission() {
return checkAnyPermissionOf(
android.Manifest.permission.NETWORK_STACK,
@@ -2338,13 +2302,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
private Intent makeGeneralIntent(NetworkInfo info, String bcastType) {
- synchronized (mVpns) {
- if (mLockdownTracker != null) {
- info = new NetworkInfo(info);
- mLockdownTracker.augmentNetworkInfo(info);
- }
- }
-
Intent intent = new Intent(bcastType);
intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, new NetworkInfo(info));
intent.putExtra(ConnectivityManager.EXTRA_NETWORK_TYPE, info.getType());
@@ -2438,10 +2395,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
}
- // Try bringing up tracker, but KeyStore won't be ready yet for secondary users so wait
- // for user to unlock device too.
- updateLockdownVpn();
-
// Create network requests for always-on networks.
mHandler.sendMessage(mHandler.obtainMessage(EVENT_CONFIGURE_ALWAYS_ON_NETWORKS));
}
@@ -2632,6 +2585,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
pw.println();
+ pw.print("Current per-app default networks: ");
+ pw.increaseIndent();
+ dumpPerAppNetworkPreferences(pw);
+ pw.decreaseIndent();
+ pw.println();
+
pw.println("Current Networks:");
pw.increaseIndent();
dumpNetworks(pw);
@@ -2752,6 +2711,40 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
}
+ private void dumpPerAppNetworkPreferences(IndentingPrintWriter pw) {
+ pw.println("Per-App Network Preference:");
+ pw.increaseIndent();
+ if (0 == mOemNetworkPreferences.getNetworkPreferences().size()) {
+ pw.println("none");
+ } else {
+ pw.println(mOemNetworkPreferences.toString());
+ }
+ pw.decreaseIndent();
+
+ for (final NetworkRequestInfo defaultRequest : mDefaultNetworkRequests) {
+ if (mDefaultRequest == defaultRequest) {
+ continue;
+ }
+
+ final boolean isActive = null != defaultRequest.getSatisfier();
+ pw.println("Is per-app network active:");
+ pw.increaseIndent();
+ pw.println(isActive);
+ if (isActive) {
+ pw.println("Active network: " + defaultRequest.getSatisfier().network.netId);
+ }
+ pw.println("Tracked UIDs:");
+ pw.increaseIndent();
+ if (0 == defaultRequest.mRequests.size()) {
+ pw.println("none, this should never occur.");
+ } else {
+ pw.println(defaultRequest.mRequests.get(0).networkCapabilities.getUids());
+ }
+ pw.decreaseIndent();
+ pw.decreaseIndent();
+ }
+ }
+
private void dumpNetworkRequests(IndentingPrintWriter pw) {
for (NetworkRequestInfo nri : requestsSortedById()) {
pw.println(nri.toString());
@@ -2885,7 +2878,15 @@ public class ConnectivityService extends IConnectivityManager.Stub
Log.wtf(TAG, "Non-virtual networks cannot have underlying networks");
break;
}
+
final List<Network> underlying = (List<Network>) arg.second;
+
+ if (isLegacyLockdownNai(nai)
+ && (underlying == null || underlying.size() != 1)) {
+ Log.wtf(TAG, "Legacy lockdown VPN " + nai.toShortString()
+ + " must have exactly one underlying network: " + underlying);
+ }
+
final Network[] oldUnderlying = nai.declaredUnderlyingNetworks;
nai.declaredUnderlyingNetworks = (underlying != null)
? underlying.toArray(new Network[0]) : null;
@@ -3494,7 +3495,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
// incorrect) behavior.
mNetworkActivityTracker.updateDataActivityTracking(
null /* newNetwork */, nai);
- notifyLockdownVpn(nai);
ensureNetworkTransitionWakelock(nai.toShortString());
}
}
@@ -3584,29 +3584,38 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
private void handleRegisterNetworkRequest(@NonNull final NetworkRequestInfo nri) {
+ handleRegisterNetworkRequest(Collections.singletonList(nri));
+ }
+
+ private void handleRegisterNetworkRequest(@NonNull final List<NetworkRequestInfo> nris) {
ensureRunningOnConnectivityServiceThread();
- mNetworkRequestInfoLogs.log("REGISTER " + nri);
- for (final NetworkRequest req : nri.mRequests) {
- mNetworkRequests.put(req, nri);
- if (req.isListen()) {
- for (final NetworkAgentInfo network : mNetworkAgentInfos) {
- if (req.networkCapabilities.hasSignalStrength()
- && network.satisfiesImmutableCapabilitiesOf(req)) {
- updateSignalStrengthThresholds(network, "REGISTER", req);
+ for (final NetworkRequestInfo nri : nris) {
+ mNetworkRequestInfoLogs.log("REGISTER " + nri);
+ for (final NetworkRequest req : nri.mRequests) {
+ mNetworkRequests.put(req, nri);
+ if (req.isListen()) {
+ for (final NetworkAgentInfo network : mNetworkAgentInfos) {
+ if (req.networkCapabilities.hasSignalStrength()
+ && network.satisfiesImmutableCapabilitiesOf(req)) {
+ updateSignalStrengthThresholds(network, "REGISTER", req);
+ }
}
}
}
}
+
rematchAllNetworksAndRequests();
- // If the nri is satisfied, return as its score has already been sent if needed.
- if (nri.isBeingSatisfied()) {
- return;
- }
+ for (final NetworkRequestInfo nri : nris) {
+ // If the nri is satisfied, return as its score has already been sent if needed.
+ if (nri.isBeingSatisfied()) {
+ return;
+ }
- // As this request was not satisfied on rematch and thus never had any scores sent to the
- // factories, send null now for each request of type REQUEST.
- for (final NetworkRequest req : nri.mRequests) {
- if (req.isRequest()) sendUpdatedScoreToFactories(req, null);
+ // As this request was not satisfied on rematch and thus never had any scores sent to
+ // the factories, send null now for each request of type REQUEST.
+ for (final NetworkRequest req : nri.mRequests) {
+ if (req.isRequest()) sendUpdatedScoreToFactories(req, null);
+ }
}
}
@@ -3779,6 +3788,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
removeListenRequestFromNetworks(req);
}
}
+ mDefaultNetworkRequests.remove(nri);
mNetworkRequestCounter.decrementCount(nri.mUid);
mNetworkRequestInfoLogs.log("RELEASE " + nri);
@@ -4417,6 +4427,16 @@ public class ConnectivityService extends IConnectivityManager.Stub
case EVENT_SET_REQUIRE_VPN_FOR_UIDS:
handleSetRequireVpnForUids(toBool(msg.arg1), (UidRange[]) msg.obj);
break;
+ case EVENT_SET_OEM_NETWORK_PREFERENCE:
+ final Pair<OemNetworkPreferences, IOnSetOemNetworkPreferenceListener> arg =
+ (Pair<OemNetworkPreferences,
+ IOnSetOemNetworkPreferenceListener>) msg.obj;
+ try {
+ handleSetOemNetworkPreference(arg.first, arg.second);
+ } catch (RemoteException e) {
+ loge("handleMessage.EVENT_SET_OEM_NETWORK_PREFERENCE failed", e);
+ }
+ break;
}
}
}
@@ -4719,183 +4739,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
/**
- * Prepare for a VPN application.
- * VPN permissions are checked in the {@link Vpn} class. If the caller is not {@code userId},
- * {@link android.Manifest.permission.INTERACT_ACROSS_USERS_FULL} permission is required.
- *
- * @param oldPackage Package name of the application which currently controls VPN, which will
- * be replaced. If there is no such application, this should should either be
- * {@code null} or {@link VpnConfig.LEGACY_VPN}.
- * @param newPackage Package name of the application which should gain control of VPN, or
- * {@code null} to disable.
- * @param userId User for whom to prepare the new VPN.
- *
- * @hide
- */
- @Override
- public boolean prepareVpn(@Nullable String oldPackage, @Nullable String newPackage,
- int userId) {
- enforceCrossUserPermission(userId);
-
- synchronized (mVpns) {
- throwIfLockdownEnabled();
- Vpn vpn = mVpns.get(userId);
- if (vpn != null) {
- return vpn.prepare(oldPackage, newPackage, VpnManager.TYPE_VPN_SERVICE);
- } else {
- return false;
- }
- }
- }
-
- /**
- * Set whether the VPN package has the ability to launch VPNs without user intervention. This
- * method is used by system-privileged apps. VPN permissions are checked in the {@link Vpn}
- * class. If the caller is not {@code userId}, {@link
- * android.Manifest.permission.INTERACT_ACROSS_USERS_FULL} permission is required.
- *
- * @param packageName The package for which authorization state should change.
- * @param userId User for whom {@code packageName} is installed.
- * @param authorized {@code true} if this app should be able to start a VPN connection without
- * explicit user approval, {@code false} if not.
- * @param vpnType The {@link VpnManager.VpnType} constant representing what class of VPN
- * permissions should be granted. When unauthorizing an app, {@link
- * VpnManager.TYPE_VPN_NONE} should be used.
- * @hide
- */
- @Override
- public void setVpnPackageAuthorization(
- String packageName, int userId, @VpnManager.VpnType int vpnType) {
- enforceCrossUserPermission(userId);
-
- synchronized (mVpns) {
- Vpn vpn = mVpns.get(userId);
- if (vpn != null) {
- vpn.setPackageAuthorization(packageName, vpnType);
- }
- }
- }
-
- /**
- * Configure a TUN interface and return its file descriptor. Parameters
- * are encoded and opaque to this class. This method is used by VpnBuilder
- * and not available in ConnectivityManager. Permissions are checked in
- * Vpn class.
- * @hide
- */
- @Override
- public ParcelFileDescriptor establishVpn(VpnConfig config) {
- int user = UserHandle.getUserId(mDeps.getCallingUid());
- synchronized (mVpns) {
- throwIfLockdownEnabled();
- return mVpns.get(user).establish(config);
- }
- }
-
- /**
- * Stores the given VPN profile based on the provisioning package name.
- *
- * <p>If there is already a VPN profile stored for the provisioning package, this call will
- * overwrite the profile.
- *
- * <p>This is designed to serve the VpnManager only; settings-based VPN profiles are managed
- * exclusively by the Settings app, and passed into the platform at startup time.
- *
- * @return {@code true} if user consent has already been granted, {@code false} otherwise.
- * @hide
- */
- @Override
- public boolean provisionVpnProfile(@NonNull VpnProfile profile, @NonNull String packageName) {
- final int user = UserHandle.getUserId(mDeps.getCallingUid());
- synchronized (mVpns) {
- return mVpns.get(user).provisionVpnProfile(packageName, profile, mKeyStore);
- }
- }
-
- /**
- * Deletes the stored VPN profile for the provisioning package
- *
- * <p>If there are no profiles for the given package, this method will silently succeed.
- *
- * <p>This is designed to serve the VpnManager only; settings-based VPN profiles are managed
- * exclusively by the Settings app, and passed into the platform at startup time.
- *
- * @hide
- */
- @Override
- public void deleteVpnProfile(@NonNull String packageName) {
- final int user = UserHandle.getUserId(mDeps.getCallingUid());
- synchronized (mVpns) {
- mVpns.get(user).deleteVpnProfile(packageName, mKeyStore);
- }
- }
-
- /**
- * Starts the VPN based on the stored profile for the given package
- *
- * <p>This is designed to serve the VpnManager only; settings-based VPN profiles are managed
- * exclusively by the Settings app, and passed into the platform at startup time.
- *
- * @throws IllegalArgumentException if no profile was found for the given package name.
- * @hide
- */
- @Override
- public void startVpnProfile(@NonNull String packageName) {
- final int user = UserHandle.getUserId(mDeps.getCallingUid());
- synchronized (mVpns) {
- throwIfLockdownEnabled();
- mVpns.get(user).startVpnProfile(packageName, mKeyStore);
- }
- }
-
- /**
- * Stops the Platform VPN if the provided package is running one.
- *
- * <p>This is designed to serve the VpnManager only; settings-based VPN profiles are managed
- * exclusively by the Settings app, and passed into the platform at startup time.
- *
- * @hide
- */
- @Override
- public void stopVpnProfile(@NonNull String packageName) {
- final int user = UserHandle.getUserId(mDeps.getCallingUid());
- synchronized (mVpns) {
- mVpns.get(user).stopVpnProfile(packageName);
- }
- }
-
- /**
- * Start legacy VPN, controlling native daemons as needed. Creates a
- * secondary thread to perform connection work, returning quickly.
- */
- @Override
- public void startLegacyVpn(VpnProfile profile) {
- int user = UserHandle.getUserId(mDeps.getCallingUid());
- final LinkProperties egress = getActiveLinkProperties();
- if (egress == null) {
- throw new IllegalStateException("Missing active network connection");
- }
- synchronized (mVpns) {
- throwIfLockdownEnabled();
- mVpns.get(user).startLegacyVpn(profile, mKeyStore, null /* underlying */, egress);
- }
- }
-
- /**
- * Return the information of the ongoing legacy VPN. This method is used
- * by VpnSettings and not available in ConnectivityManager. Permissions
- * are checked in Vpn class.
- */
- @Override
- public LegacyVpnInfo getLegacyVpnInfo(int userId) {
- enforceCrossUserPermission(userId);
-
- synchronized (mVpns) {
- return mVpns.get(userId).getLegacyVpnInfo();
- }
- }
-
- /**
* Return the information of all ongoing VPNs.
*
* <p>This method is used to update NetworkStatsService.
@@ -4904,10 +4747,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
*/
private UnderlyingNetworkInfo[] getAllVpnInfo() {
ensureRunningOnConnectivityServiceThread();
- synchronized (mVpns) {
- if (mLockdownEnabled) {
- return new UnderlyingNetworkInfo[0];
- }
+ if (mLockdownEnabled) {
+ return new UnderlyingNetworkInfo[0];
}
List<UnderlyingNetworkInfo> infoList = new ArrayList<>();
for (NetworkAgentInfo nai : mNetworkAgentInfos) {
@@ -4963,25 +4804,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
nai.linkProperties.getInterfaceName(), interfaces);
}
- /**
- * Returns the information of the ongoing VPN for {@code userId}. This method is used by
- * VpnDialogs and not available in ConnectivityManager.
- * Permissions are checked in Vpn class.
- * @hide
- */
- @Override
- public VpnConfig getVpnConfig(int userId) {
- enforceCrossUserPermission(userId);
- synchronized (mVpns) {
- Vpn vpn = mVpns.get(userId);
- if (vpn != null) {
- return vpn.getVpnConfig();
- } else {
- return null;
- }
- }
- }
-
// TODO This needs to be the default network that applies to the NAI.
private Network[] underlyingNetworksOrDefault(final int ownerUid,
Network[] underlyingNetworks) {
@@ -5069,195 +4891,54 @@ public class ConnectivityService extends IConnectivityManager.Stub
mVpnBlockedUidRanges = newVpnBlockedUidRanges;
}
- private boolean isLockdownVpnEnabled() {
- return mKeyStore.contains(Credentials.LOCKDOWN_VPN);
- }
-
@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");
- return false;
- }
-
- synchronized (mVpns) {
- // Tear down existing lockdown if profile was removed
- mLockdownEnabled = isLockdownVpnEnabled();
- if (mLockdownEnabled) {
- byte[] profileTag = mKeyStore.get(Credentials.LOCKDOWN_VPN);
- if (profileTag == null) {
- loge("Lockdown VPN configured but cannot be read from keystore");
- return false;
- }
- String profileName = new String(profileTag);
- final VpnProfile profile = VpnProfile.decode(
- profileName, mKeyStore.get(Credentials.VPN + profileName));
- if (profile == null) {
- loge("Lockdown VPN configured invalid profile " + profileName);
- setLockdownTracker(null);
- return true;
- }
- int user = UserHandle.getUserId(mDeps.getCallingUid());
- Vpn vpn = mVpns.get(user);
- if (vpn == null) {
- logw("VPN for user " + user + " not ready yet. Skipping lockdown");
- return false;
- }
- setLockdownTracker(
- new LockdownVpnTracker(mContext, this, mHandler, mKeyStore, vpn, profile));
- } else {
- setLockdownTracker(null);
- }
- }
-
- return true;
- }
-
- /**
- * Internally set new {@link LockdownVpnTracker}, shutting down any existing
- * {@link LockdownVpnTracker}. Can be {@code null} to disable lockdown.
- */
- @GuardedBy("mVpns")
- private void setLockdownTracker(LockdownVpnTracker tracker) {
- // Shutdown any existing tracker
- final LockdownVpnTracker existing = mLockdownTracker;
- // TODO: Add a trigger when the always-on VPN enable/disable to reevaluate and send the
- // necessary onBlockedStatusChanged callbacks.
- mLockdownTracker = null;
- if (existing != null) {
- existing.shutdown();
- }
-
- if (tracker != null) {
- mLockdownTracker = tracker;
- mLockdownTracker.init();
- }
- }
-
- /**
- * Throws if there is any currently running, always-on Legacy VPN.
- *
- * <p>The LockdownVpnTracker and mLockdownEnabled both track whether an always-on Legacy VPN is
- * running across the entire system. Tracking for app-based VPNs is done on a per-user,
- * per-package basis in Vpn.java
- */
- @GuardedBy("mVpns")
- private void throwIfLockdownEnabled() {
- if (mLockdownEnabled) {
- throw new IllegalStateException("Unavailable in lockdown mode");
- }
+ public void setLegacyLockdownVpnEnabled(boolean enabled) {
+ enforceSettingsPermission();
+ mHandler.post(() -> mLockdownEnabled = enabled);
}
- /**
- * Starts the always-on VPN {@link VpnService} for user {@param userId}, which should perform
- * some setup and then call {@code establish()} to connect.
- *
- * @return {@code true} if the service was started, the service was already connected, or there
- * was no always-on VPN to start. {@code false} otherwise.
- */
- private boolean startAlwaysOnVpn(int userId) {
- synchronized (mVpns) {
- Vpn vpn = mVpns.get(userId);
- if (vpn == null) {
- // Shouldn't happen as all code paths that point here should have checked the Vpn
- // exists already.
- Log.wtf(TAG, "User " + userId + " has no Vpn configuration");
- return false;
- }
-
- return vpn.startAlwaysOnVpn(mKeyStore);
- }
+ private boolean isLegacyLockdownNai(NetworkAgentInfo nai) {
+ return mLockdownEnabled
+ && getVpnType(nai) == VpnManager.TYPE_VPN_LEGACY
+ && nai.networkCapabilities.appliesToUid(Process.FIRST_APPLICATION_UID);
}
- @Override
- public boolean isAlwaysOnVpnPackageSupported(int userId, String packageName) {
- enforceSettingsPermission();
- enforceCrossUserPermission(userId);
-
- synchronized (mVpns) {
- Vpn vpn = mVpns.get(userId);
- if (vpn == null) {
- logw("User " + userId + " has no Vpn configuration");
- return false;
- }
- return vpn.isAlwaysOnPackageSupported(packageName, mKeyStore);
+ private NetworkAgentInfo getLegacyLockdownNai() {
+ if (!mLockdownEnabled) {
+ return null;
}
- }
-
- @Override
- public boolean setAlwaysOnVpnPackage(
- int userId, String packageName, boolean lockdown, List<String> lockdownWhitelist) {
- enforceControlAlwaysOnVpnPermission();
- enforceCrossUserPermission(userId);
-
- synchronized (mVpns) {
- // Can't set always-on VPN if legacy VPN is already in lockdown mode.
- if (isLockdownVpnEnabled()) {
- return false;
- }
+ // The legacy lockdown VPN always only applies to userId 0.
+ final NetworkAgentInfo nai = getVpnForUid(Process.FIRST_APPLICATION_UID);
+ if (nai == null || !isLegacyLockdownNai(nai)) return null;
- Vpn vpn = mVpns.get(userId);
- if (vpn == null) {
- logw("User " + userId + " has no Vpn configuration");
- return false;
- }
- if (!vpn.setAlwaysOnPackage(packageName, lockdown, lockdownWhitelist, mKeyStore)) {
- return false;
- }
- if (!startAlwaysOnVpn(userId)) {
- vpn.setAlwaysOnPackage(null, false, null, mKeyStore);
- return false;
- }
+ // The legacy lockdown VPN must always have exactly one underlying network.
+ // This code may run on any thread and declaredUnderlyingNetworks may change, so store it in
+ // a local variable. There is no need to make a copy because its contents cannot change.
+ final Network[] underlying = nai.declaredUnderlyingNetworks;
+ if (underlying == null || underlying.length != 1) {
+ return null;
}
- return true;
- }
- @Override
- public String getAlwaysOnVpnPackage(int userId) {
- enforceControlAlwaysOnVpnPermission();
- enforceCrossUserPermission(userId);
-
- synchronized (mVpns) {
- Vpn vpn = mVpns.get(userId);
- if (vpn == null) {
- logw("User " + userId + " has no Vpn configuration");
- return null;
- }
- return vpn.getAlwaysOnPackage();
+ // The legacy lockdown VPN always uses the default network.
+ // If the VPN's underlying network is no longer the current default network, it means that
+ // the default network has just switched, and the VPN is about to disconnect.
+ // Report that the VPN is not connected, so when the state of NetworkInfo objects
+ // overwritten by getLegacyLockdownState will be set to CONNECTING and not CONNECTED.
+ final NetworkAgentInfo defaultNetwork = getDefaultNetwork();
+ if (defaultNetwork == null || !defaultNetwork.network.equals(underlying[0])) {
+ return null;
}
- }
- @Override
- public boolean isVpnLockdownEnabled(int userId) {
- enforceControlAlwaysOnVpnPermission();
- enforceCrossUserPermission(userId);
-
- synchronized (mVpns) {
- Vpn vpn = mVpns.get(userId);
- if (vpn == null) {
- logw("User " + userId + " has no Vpn configuration");
- return false;
- }
- return vpn.getLockdown();
- }
- }
+ return nai;
+ };
- @Override
- public List<String> getVpnLockdownWhitelist(int userId) {
- enforceControlAlwaysOnVpnPermission();
- enforceCrossUserPermission(userId);
-
- synchronized (mVpns) {
- Vpn vpn = mVpns.get(userId);
- if (vpn == null) {
- logw("User " + userId + " has no Vpn configuration");
- return null;
- }
- return vpn.getLockdownAllowlist();
+ private DetailedState getLegacyLockdownState(DetailedState origState) {
+ if (origState != DetailedState.CONNECTED) {
+ return origState;
}
+ return (mLockdownEnabled && getLegacyLockdownNai() == null)
+ ? DetailedState.CONNECTING
+ : DetailedState.CONNECTED;
}
@Override
@@ -5292,111 +4973,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
}
- private void onUserStarted(int userId) {
- synchronized (mVpns) {
- Vpn userVpn = mVpns.get(userId);
- if (userVpn != null) {
- loge("Starting user already has a VPN");
- return;
- }
- userVpn = new Vpn(mHandler.getLooper(), mContext, mNMS, mNetd, userId, mKeyStore);
- mVpns.put(userId, userVpn);
- if (mUserManager.getUserInfo(userId).isPrimary() && isLockdownVpnEnabled()) {
- updateLockdownVpn();
- }
- }
- }
-
- private void onUserStopped(int userId) {
- synchronized (mVpns) {
- Vpn userVpn = mVpns.get(userId);
- if (userVpn == null) {
- loge("Stopped user has no VPN");
- return;
- }
- userVpn.onUserStopped();
- mVpns.delete(userId);
- }
- }
-
private void onUserAdded(int userId) {
mPermissionMonitor.onUserAdded(userId);
- synchronized (mVpns) {
- final int vpnsSize = mVpns.size();
- for (int i = 0; i < vpnsSize; i++) {
- Vpn vpn = mVpns.valueAt(i);
- vpn.onUserAdded(userId);
- }
- }
}
private void onUserRemoved(int userId) {
mPermissionMonitor.onUserRemoved(userId);
- synchronized (mVpns) {
- final int vpnsSize = mVpns.size();
- for (int i = 0; i < vpnsSize; i++) {
- Vpn vpn = mVpns.valueAt(i);
- vpn.onUserRemoved(userId);
- }
- }
- }
-
- private void onPackageReplaced(String packageName, int uid) {
- if (TextUtils.isEmpty(packageName) || uid < 0) {
- Log.wtf(TAG, "Invalid package in onPackageReplaced: " + packageName + " | " + uid);
- return;
- }
- final int userId = UserHandle.getUserId(uid);
- synchronized (mVpns) {
- final Vpn vpn = mVpns.get(userId);
- if (vpn == null) {
- return;
- }
- // Legacy always-on VPN won't be affected since the package name is not set.
- if (TextUtils.equals(vpn.getAlwaysOnPackage(), packageName)) {
- log("Restarting always-on VPN package " + packageName + " for user "
- + userId);
- vpn.startAlwaysOnVpn(mKeyStore);
- }
- }
- }
-
- private void onPackageRemoved(String packageName, int uid, boolean isReplacing) {
- if (TextUtils.isEmpty(packageName) || uid < 0) {
- Log.wtf(TAG, "Invalid package in onPackageRemoved: " + packageName + " | " + uid);
- return;
- }
-
- final int userId = UserHandle.getUserId(uid);
- synchronized (mVpns) {
- final Vpn vpn = mVpns.get(userId);
- if (vpn == null) {
- return;
- }
- // Legacy always-on VPN won't be affected since the package name is not set.
- if (TextUtils.equals(vpn.getAlwaysOnPackage(), packageName) && !isReplacing) {
- log("Removing always-on VPN package " + packageName + " for user "
- + userId);
- vpn.setAlwaysOnPackage(null, false, null, mKeyStore);
- }
- }
- }
-
- private void onUserUnlocked(int userId) {
- synchronized (mVpns) {
- // User present may be sent because of an unlock, which might mean an unlocked keystore.
- if (mUserManager.getUserInfo(userId).isPrimary() && isLockdownVpnEnabled()) {
- updateLockdownVpn();
- } else {
- startAlwaysOnVpn(userId);
- }
- }
- }
-
- private void onVpnLockdownReset() {
- synchronized (mVpns) {
- if (mLockdownTracker != null) mLockdownTracker.reset();
- }
}
private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
@@ -5405,52 +4987,20 @@ public class ConnectivityService extends IConnectivityManager.Stub
ensureRunningOnConnectivityServiceThread();
final String action = intent.getAction();
final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
- final int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
- final Uri packageData = intent.getData();
- final String packageName =
- packageData != null ? packageData.getSchemeSpecificPart() : null;
-
- if (LockdownVpnTracker.ACTION_LOCKDOWN_RESET.equals(action)) {
- onVpnLockdownReset();
- }
// UserId should be filled for below intents, check the existence.
if (userId == UserHandle.USER_NULL) return;
- if (Intent.ACTION_USER_STARTED.equals(action)) {
- onUserStarted(userId);
- } else if (Intent.ACTION_USER_STOPPED.equals(action)) {
- onUserStopped(userId);
- } else if (Intent.ACTION_USER_ADDED.equals(action)) {
+ if (Intent.ACTION_USER_ADDED.equals(action)) {
onUserAdded(userId);
} else if (Intent.ACTION_USER_REMOVED.equals(action)) {
onUserRemoved(userId);
- } else if (Intent.ACTION_USER_UNLOCKED.equals(action)) {
- onUserUnlocked(userId);
- } else if (Intent.ACTION_PACKAGE_REPLACED.equals(action)) {
- onPackageReplaced(packageName, uid);
- } else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
- final boolean isReplacing = intent.getBooleanExtra(
- Intent.EXTRA_REPLACING, false);
- onPackageRemoved(packageName, uid, isReplacing);
- } else {
+ } else {
Log.wtf(TAG, "received unexpected intent: " + action);
}
}
};
- private BroadcastReceiver mUserPresentReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- // Try creating lockdown tracker, since user present usually means
- // unlocked keystore.
- updateLockdownVpn();
- // Use the same context that registered receiver before to unregister it. Because use
- // different context to unregister receiver will cause exception.
- context.unregisterReceiver(this);
- }
- };
-
private final HashMap<Messenger, NetworkProviderInfo> mNetworkProviderInfos = new HashMap<>();
private final HashMap<NetworkRequest, NetworkRequestInfo> mNetworkRequests = new HashMap<>();
@@ -5549,10 +5099,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
final PendingIntent mPendingIntent;
boolean mPendingIntentSent;
+ @Nullable
+ final Messenger mMessenger;
+ @Nullable
private final IBinder mBinder;
final int mPid;
final int mUid;
- final Messenger messenger;
@Nullable
final String mCallingAttributionTag;
@@ -5568,12 +5120,17 @@ public class ConnectivityService extends IConnectivityManager.Stub
return uids;
}
- NetworkRequestInfo(NetworkRequest r, PendingIntent pi,
+ NetworkRequestInfo(@NonNull final NetworkRequest r, @Nullable final PendingIntent pi,
@Nullable String callingAttributionTag) {
+ this(Collections.singletonList(r), pi, callingAttributionTag);
+ }
+
+ NetworkRequestInfo(@NonNull final List<NetworkRequest> r,
+ @Nullable final PendingIntent pi, @Nullable String callingAttributionTag) {
mRequests = initializeRequests(r);
ensureAllNetworkRequestsHaveType(mRequests);
mPendingIntent = pi;
- messenger = null;
+ mMessenger = null;
mBinder = null;
mPid = getCallingPid();
mUid = mDeps.getCallingUid();
@@ -5581,11 +5138,16 @@ public class ConnectivityService extends IConnectivityManager.Stub
mCallingAttributionTag = callingAttributionTag;
}
- NetworkRequestInfo(Messenger m, NetworkRequest r, IBinder binder,
- @Nullable String callingAttributionTag) {
+ NetworkRequestInfo(@NonNull final NetworkRequest r, @Nullable final Messenger m,
+ @Nullable final IBinder binder, @Nullable String callingAttributionTag) {
+ this(Collections.singletonList(r), m, binder, callingAttributionTag);
+ }
+
+ NetworkRequestInfo(@NonNull final List<NetworkRequest> r, @Nullable final Messenger m,
+ @Nullable final IBinder binder, @Nullable String callingAttributionTag) {
super();
- messenger = m;
mRequests = initializeRequests(r);
+ mMessenger = m;
ensureAllNetworkRequestsHaveType(mRequests);
mBinder = binder;
mPid = getCallingPid();
@@ -5601,7 +5163,11 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
}
- NetworkRequestInfo(NetworkRequest r) {
+ NetworkRequestInfo(@NonNull final NetworkRequest r) {
+ this(Collections.singletonList(r));
+ }
+
+ NetworkRequestInfo(@NonNull final List<NetworkRequest> r) {
this(r, null /* pi */, null /* callingAttributionTag */);
}
@@ -5616,9 +5182,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
return mRequests.size() > 1;
}
- private List<NetworkRequest> initializeRequests(NetworkRequest r) {
- final ArrayList<NetworkRequest> tempRequests = new ArrayList<>();
- tempRequests.add(new NetworkRequest(r));
+ private List<NetworkRequest> initializeRequests(List<NetworkRequest> r) {
+ // Creating a defensive copy to prevent the sender from modifying the list being
+ // reflected in the return value of this method.
+ final List<NetworkRequest> tempRequests = new ArrayList<>(r);
return Collections.unmodifiableList(tempRequests);
}
@@ -5747,6 +5314,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
throw new SecurityException("Insufficient permissions to specify legacy type");
}
}
+ final NetworkCapabilities defaultNc = mDefaultRequest.mRequests.get(0).networkCapabilities;
final int callingUid = mDeps.getCallingUid();
final NetworkRequest.Type reqType;
try {
@@ -5757,11 +5325,15 @@ public class ConnectivityService extends IConnectivityManager.Stub
switch (reqType) {
case TRACK_DEFAULT:
// If the request type is TRACK_DEFAULT, the passed {@code networkCapabilities}
- // is unused and will be replaced by the one from the default network request.
- // This allows callers to keep track of the system default network.
+ // is unused and will be replaced by ones appropriate for the caller.
+ // This allows callers to keep track of the default network for their app.
networkCapabilities = createDefaultNetworkCapabilitiesForUid(callingUid);
enforceAccessPermission();
break;
+ case TRACK_SYSTEM_DEFAULT:
+ enforceSettingsPermission();
+ networkCapabilities = new NetworkCapabilities(defaultNc);
+ break;
case BACKGROUND_REQUEST:
enforceNetworkStackOrSettingsPermission();
// Fall-through since other checks are the same with normal requests.
@@ -5780,6 +5352,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
ensureRequestableCapabilities(networkCapabilities);
ensureSufficientPermissionsForRequest(networkCapabilities,
Binder.getCallingPid(), callingUid, callingPackageName);
+
// Set the UID range for this request to the single UID of the requester, or to an empty
// set of UIDs if the caller has the appropriate permission and UIDs have not been set.
// This will overwrite any allowed UIDs in the requested capabilities. Though there
@@ -5796,9 +5369,20 @@ public class ConnectivityService extends IConnectivityManager.Stub
NetworkRequest networkRequest = new NetworkRequest(networkCapabilities, legacyType,
nextNetworkRequestId(), reqType);
NetworkRequestInfo nri =
- new NetworkRequestInfo(messenger, networkRequest, binder, callingAttributionTag);
+ new NetworkRequestInfo(networkRequest, messenger, binder, callingAttributionTag);
if (DBG) log("requestNetwork for " + nri);
+ // For TRACK_SYSTEM_DEFAULT callbacks, the capabilities have been modified since they were
+ // copied from the default request above. (This is necessary to ensure, for example, that
+ // the callback does not leak sensitive information to unprivileged apps.) Check that the
+ // changes don't alter request matching.
+ if (reqType == NetworkRequest.Type.TRACK_SYSTEM_DEFAULT &&
+ (!networkCapabilities.equalRequestableCapabilities(defaultNc))) {
+ throw new IllegalStateException(
+ "TRACK_SYSTEM_DEFAULT capabilities don't match default request: "
+ + networkCapabilities + " vs. " + defaultNc);
+ }
+
mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_REQUEST, nri));
if (timeoutMs > 0) {
mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_TIMEOUT_NETWORK_REQUEST,
@@ -5952,7 +5536,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
NetworkRequest networkRequest = new NetworkRequest(nc, TYPE_NONE, nextNetworkRequestId(),
NetworkRequest.Type.LISTEN);
NetworkRequestInfo nri =
- new NetworkRequestInfo(messenger, networkRequest, binder, callingAttributionTag);
+ new NetworkRequestInfo(networkRequest, messenger, binder, callingAttributionTag);
if (VDBG) log("listenForNetwork for " + nri);
mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_LISTENER, nri));
@@ -6080,13 +5664,20 @@ public class ConnectivityService extends IConnectivityManager.Stub
@GuardedBy("mBlockedAppUids")
private final HashSet<Integer> mBlockedAppUids = new HashSet<>();
+ // Current OEM network preferences.
+ @NonNull
+ private OemNetworkPreferences mOemNetworkPreferences =
+ new OemNetworkPreferences.Builder().build();
+
// The always-on request for an Internet-capable network that apps without a specific default
// fall back to.
+ @VisibleForTesting
@NonNull
- private final NetworkRequestInfo mDefaultRequest;
+ final NetworkRequestInfo mDefaultRequest;
// Collection of NetworkRequestInfo's used for default networks.
+ @VisibleForTesting
@NonNull
- private final ArraySet<NetworkRequestInfo> mDefaultNetworkRequests = new ArraySet<>();
+ final ArraySet<NetworkRequestInfo> mDefaultNetworkRequests = new ArraySet<>();
private boolean isPerAppDefaultRequest(@NonNull final NetworkRequestInfo nri) {
return (mDefaultNetworkRequests.contains(nri) && mDefaultRequest != nri);
@@ -6389,20 +5980,18 @@ public class ConnectivityService extends IConnectivityManager.Stub
Math.max(naData.getRefreshTimeMillis(), apiData.getRefreshTimeMillis()));
}
- // Prioritize the user portal URL from the network agent.
- if (apiData.getUserPortalUrl() != null && (naData.getUserPortalUrl() == null
- || TextUtils.isEmpty(naData.getUserPortalUrl().toSafeString()))) {
- captivePortalBuilder.setUserPortalUrl(apiData.getUserPortalUrl());
+ // Prioritize the user portal URL from the network agent if the source is authenticated.
+ if (apiData.getUserPortalUrl() != null && naData.getUserPortalUrlSource()
+ != CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT) {
+ captivePortalBuilder.setUserPortalUrl(apiData.getUserPortalUrl(),
+ apiData.getUserPortalUrlSource());
}
- // Prioritize the venue information URL from the network agent.
- if (apiData.getVenueInfoUrl() != null && (naData.getVenueInfoUrl() == null
- || TextUtils.isEmpty(naData.getVenueInfoUrl().toSafeString()))) {
- captivePortalBuilder.setVenueInfoUrl(apiData.getVenueInfoUrl());
-
- // Note that venue friendly name can only come from the network agent because it is not
- // in use in RFC8908. However, if using the Capport venue URL, make sure that the
- // friendly name is not set from the network agent.
- captivePortalBuilder.setVenueFriendlyName(null);
+ // Prioritize the venue information URL from the network agent if the source is
+ // authenticated.
+ if (apiData.getVenueInfoUrl() != null && naData.getVenueInfoUrlSource()
+ != CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT) {
+ captivePortalBuilder.setVenueInfoUrl(apiData.getVenueInfoUrl(),
+ apiData.getVenueInfoUrlSource());
}
return captivePortalBuilder.build();
}
@@ -7165,7 +6754,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
private void callCallbackForRequest(@NonNull final NetworkRequestInfo nri,
@NonNull final NetworkAgentInfo networkAgent, final int notificationType,
final int arg1) {
- if (nri.messenger == null) {
+ if (nri.mMessenger == null) {
// Default request has no msgr. Also prevents callbacks from being invoked for
// NetworkRequestInfos registered with ConnectivityDiagnostics requests. Those callbacks
// are Type.LISTEN, but should not have NetworkCallbacks invoked.
@@ -7234,7 +6823,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
String notification = ConnectivityManager.getCallbackName(notificationType);
log("sending notification " + notification + " for " + nrForCallback);
}
- nri.messenger.send(msg);
+ nri.mMessenger.send(msg);
} catch (RemoteException e) {
// may occur naturally in the race of binder death.
loge("RemoteException caught trying to send a callback msg for " + nrForCallback);
@@ -7323,7 +6912,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
mLingerMonitor.noteLingerDefaultNetwork(oldDefaultNetwork, newDefaultNetwork);
}
mNetworkActivityTracker.updateDataActivityTracking(newDefaultNetwork, oldDefaultNetwork);
- notifyLockdownVpn(newDefaultNetwork);
handleApplyDefaultProxy(null != newDefaultNetwork
? newDefaultNetwork.linkProperties.getHttpProxy() : null);
updateTcpBufferSizes(null != newDefaultNetwork
@@ -7781,12 +7369,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
mDefaultInetConditionPublished = newDefaultNetwork.lastValidated ? 100 : 0;
mLegacyTypeTracker.add(
newDefaultNetwork.networkInfo.getType(), newDefaultNetwork);
- // If the legacy VPN is connected, notifyLockdownVpn may end up sending a broadcast
- // to reflect the NetworkInfo of this new network. This broadcast has to be sent
- // after the disconnect broadcasts above, but before the broadcasts sent by the
- // legacy type tracker below.
- // TODO : refactor this, it's too complex
- notifyLockdownVpn(newDefaultNetwork);
}
}
@@ -7844,18 +7426,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
sendInetConditionBroadcast(nai.networkInfo);
}
- private void notifyLockdownVpn(NetworkAgentInfo nai) {
- synchronized (mVpns) {
- if (mLockdownTracker != null) {
- if (nai != null && nai.isVPN()) {
- mLockdownTracker.onVpnStateChanged(nai.networkInfo);
- } else {
- mLockdownTracker.onNetworkInfoChanged();
- }
- }
- }
- }
-
@NonNull
private NetworkInfo mixInInfo(@NonNull final NetworkAgentInfo nai, @NonNull NetworkInfo info) {
final NetworkInfo newInfo = new NetworkInfo(info);
@@ -7894,7 +7464,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
oldInfo = networkAgent.networkInfo;
networkAgent.networkInfo = newInfo;
}
- notifyLockdownVpn(networkAgent);
if (DBG) {
log(networkAgent.toShortString() + " EVENT_NETWORK_INFO_CHANGED, going from "
@@ -8195,34 +7764,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
@Override
- public boolean addVpnAddress(String address, int prefixLength) {
- int user = UserHandle.getUserId(mDeps.getCallingUid());
- synchronized (mVpns) {
- throwIfLockdownEnabled();
- return mVpns.get(user).addAddress(address, prefixLength);
- }
- }
-
- @Override
- public boolean removeVpnAddress(String address, int prefixLength) {
- int user = UserHandle.getUserId(mDeps.getCallingUid());
- synchronized (mVpns) {
- throwIfLockdownEnabled();
- return mVpns.get(user).removeAddress(address, prefixLength);
- }
- }
-
- @Override
- public boolean setUnderlyingNetworksForVpn(Network[] networks) {
- int user = UserHandle.getUserId(mDeps.getCallingUid());
- final boolean success;
- synchronized (mVpns) {
- success = mVpns.get(user).setUnderlyingNetworks(networks);
- }
- return success;
- }
-
- @Override
public String getCaptivePortalServerUrl() {
enforceNetworkStackOrSettingsPermission();
String settingUrl = mContext.getResources().getString(
@@ -8301,8 +7842,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
return;
}
- final int userId = UserHandle.getCallingUserId();
-
final long token = Binder.clearCallingIdentity();
try {
final IpMemoryStore ipMemoryStore = IpMemoryStore.getMemoryStore(mContext);
@@ -8314,44 +7853,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
// Turn airplane mode off
setAirplaneMode(false);
- if (!mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_VPN)) {
- // Remove always-on package
- synchronized (mVpns) {
- final String alwaysOnPackage = getAlwaysOnVpnPackage(userId);
- if (alwaysOnPackage != null) {
- setAlwaysOnVpnPackage(userId, null, false, null);
- setVpnPackageAuthorization(alwaysOnPackage, userId, VpnManager.TYPE_VPN_NONE);
- }
-
- // Turn Always-on VPN off
- if (mLockdownEnabled && userId == UserHandle.USER_SYSTEM) {
- final long ident = Binder.clearCallingIdentity();
- try {
- mKeyStore.delete(Credentials.LOCKDOWN_VPN);
- mLockdownEnabled = false;
- setLockdownTracker(null);
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
-
- // Turn VPN off
- VpnConfig vpnConfig = getVpnConfig(userId);
- if (vpnConfig != null) {
- if (vpnConfig.legacy) {
- prepareVpn(VpnConfig.LEGACY_VPN, VpnConfig.LEGACY_VPN, userId);
- } else {
- // Prevent this app (packagename = vpnConfig.user) from initiating
- // VPN connections in the future without user intervention.
- setVpnPackageAuthorization(
- vpnConfig.user, userId, VpnManager.TYPE_VPN_NONE);
-
- prepareVpn(null, VpnConfig.LEGACY_VPN, userId);
- }
- }
- }
- }
-
// restore private DNS settings to default mode (opportunistic)
if (!mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_PRIVATE_DNS)) {
Settings.Global.putString(mContext.getContentResolver(),
@@ -8443,41 +7944,11 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
}
- @GuardedBy("mVpns")
- private Vpn getVpnIfOwner() {
- return getVpnIfOwner(mDeps.getCallingUid());
- }
-
- // TODO: stop calling into Vpn.java and get this information from data in this class.
- @GuardedBy("mVpns")
- private Vpn getVpnIfOwner(int uid) {
- final int user = UserHandle.getUserId(uid);
-
- final Vpn vpn = mVpns.get(user);
- if (vpn == null) {
- return null;
- } else {
- final UnderlyingNetworkInfo info = vpn.getUnderlyingNetworkInfo();
- return (info == null || info.ownerUid != uid) ? null : vpn;
- }
- }
-
- /**
- * Caller either needs to be an active VPN, or hold the NETWORK_STACK permission
- * for testing.
- */
- private Vpn enforceActiveVpnOrNetworkStackPermission() {
- if (checkNetworkStackPermission()) {
- return null;
- }
- synchronized (mVpns) {
- Vpn vpn = getVpnIfOwner();
- if (vpn != null) {
- return vpn;
- }
- }
- throw new SecurityException("App must either be an active VPN or have the NETWORK_STACK "
- + "permission");
+ private @VpnManager.VpnType int getVpnType(@Nullable NetworkAgentInfo vpn) {
+ if (vpn == null) return VpnManager.TYPE_VPN_NONE;
+ final TransportInfo ti = vpn.networkCapabilities.getTransportInfo();
+ if (!(ti instanceof VpnTransportInfo)) return VpnManager.TYPE_VPN_NONE;
+ return ((VpnTransportInfo) ti).type;
}
/**
@@ -8487,14 +7958,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
* connection is not found.
*/
public int getConnectionOwnerUid(ConnectionInfo connectionInfo) {
- final Vpn vpn = enforceActiveVpnOrNetworkStackPermission();
-
- // Only VpnService based VPNs should be able to get this information.
- if (vpn != null && vpn.getActiveAppVpnType() != VpnManager.TYPE_VPN_SERVICE) {
- throw new SecurityException(
- "getConnectionOwnerUid() not allowed for non-VpnService VPNs");
- }
-
if (connectionInfo.protocol != IPPROTO_TCP && connectionInfo.protocol != IPPROTO_UDP) {
throw new IllegalArgumentException("Unsupported protocol " + connectionInfo.protocol);
}
@@ -8502,28 +7965,19 @@ public class ConnectivityService extends IConnectivityManager.Stub
final int uid = mDeps.getConnectionOwnerUid(connectionInfo.protocol,
connectionInfo.local, connectionInfo.remote);
- /* Filter out Uids not associated with the VPN. */
- if (vpn != null && !vpn.appliesToUid(uid)) {
- return INVALID_UID;
- }
+ if (uid == INVALID_UID) return uid; // Not found.
- return uid;
- }
+ // Connection owner UIDs are visible only to the network stack and to the VpnService-based
+ // VPN, if any, that applies to the UID that owns the connection.
+ if (checkNetworkStackPermission()) return uid;
- @Override
- public boolean isCallerCurrentAlwaysOnVpnApp() {
- synchronized (mVpns) {
- Vpn vpn = getVpnIfOwner();
- return vpn != null && vpn.getAlwaysOn();
+ final NetworkAgentInfo vpn = getVpnForUid(uid);
+ if (vpn == null || getVpnType(vpn) != VpnManager.TYPE_VPN_SERVICE
+ || vpn.networkCapabilities.getOwnerUid() != Binder.getCallingUid()) {
+ return INVALID_UID;
}
- }
- @Override
- public boolean isCallerCurrentAlwaysOnVpnLockdownApp() {
- synchronized (mVpns) {
- Vpn vpn = getVpnIfOwner();
- return vpn != null && vpn.getLockdown();
- }
+ return uid;
}
/**
@@ -9201,9 +8655,212 @@ public class ConnectivityService extends IConnectivityManager.Stub
mQosCallbackTracker.unregisterCallback(callback);
}
+ private void enforceAutomotiveDevice() {
+ final boolean isAutomotiveDevice =
+ mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
+ if (!isAutomotiveDevice) {
+ throw new UnsupportedOperationException(
+ "setOemNetworkPreference() is only available on automotive devices.");
+ }
+ }
+
+ /**
+ * Used by automotive devices to set the network preferences used to direct traffic at an
+ * application level as per the given OemNetworkPreferences. An example use-case would be an
+ * automotive OEM wanting to provide connectivity for applications critical to the usage of a
+ * vehicle via a particular network.
+ *
+ * Calling this will overwrite the existing preference.
+ *
+ * @param preference {@link OemNetworkPreferences} The application network preference to be set.
+ * @param listener {@link ConnectivityManager.OnSetOemNetworkPreferenceListener} Listener used
+ * to communicate completion of setOemNetworkPreference();
+ */
@Override
- public void setOemNetworkPreference(@NonNull final OemNetworkPreferences preference) {
- // TODO http://b/176495594 track multiple default networks with networkPreferences
- if (DBG) log("setOemNetworkPreference() called with: " + preference.toString());
+ public void setOemNetworkPreference(
+ @NonNull final OemNetworkPreferences preference,
+ @Nullable final IOnSetOemNetworkPreferenceListener listener) {
+
+ enforceAutomotiveDevice();
+ enforceOemNetworkPreferencesPermission();
+
+ Objects.requireNonNull(preference, "OemNetworkPreferences must be non-null");
+ validateOemNetworkPreferences(preference);
+ mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_OEM_NETWORK_PREFERENCE,
+ new Pair<>(preference, listener)));
+ }
+
+ private void validateOemNetworkPreferences(@NonNull OemNetworkPreferences preference) {
+ for (@OemNetworkPreferences.OemNetworkPreference final int pref
+ : preference.getNetworkPreferences().values()) {
+ if (OemNetworkPreferences.OEM_NETWORK_PREFERENCE_UNINITIALIZED == pref) {
+ final String msg = "OEM_NETWORK_PREFERENCE_UNINITIALIZED is an invalid value.";
+ throw new IllegalArgumentException(msg);
+ }
+ }
+ }
+
+ private void handleSetOemNetworkPreference(
+ @NonNull final OemNetworkPreferences preference,
+ @NonNull final IOnSetOemNetworkPreferenceListener listener) throws RemoteException {
+ Objects.requireNonNull(preference, "OemNetworkPreferences must be non-null");
+ if (DBG) {
+ log("set OEM network preferences :" + preference.toString());
+ }
+ final List<NetworkRequestInfo> nris =
+ new OemNetworkRequestFactory().createNrisFromOemNetworkPreferences(preference);
+ updateDefaultNetworksForOemNetworkPreference(nris);
+ mOemNetworkPreferences = preference;
+ // TODO http://b/176496396 persist data to shared preferences.
+
+ if (null != listener) {
+ listener.onComplete();
+ }
+ }
+
+ private void updateDefaultNetworksForOemNetworkPreference(
+ @NonNull final List<NetworkRequestInfo> nris) {
+ ensureRunningOnConnectivityServiceThread();
+ clearNonDefaultNetworkAgents();
+ addDefaultNetworkRequests(nris);
+ }
+
+ private void clearNonDefaultNetworkAgents() {
+ // Copy mDefaultNetworkRequests to iterate and remove elements from it in
+ // handleRemoveNetworkRequest() without getting a ConcurrentModificationException.
+ final NetworkRequestInfo[] nris =
+ mDefaultNetworkRequests.toArray(new NetworkRequestInfo[0]);
+ for (final NetworkRequestInfo nri : nris) {
+ if (mDefaultRequest != nri) {
+ handleRemoveNetworkRequest(nri);
+ }
+ }
+ }
+
+ private void addDefaultNetworkRequests(@NonNull final List<NetworkRequestInfo> nris) {
+ mDefaultNetworkRequests.addAll(nris);
+ handleRegisterNetworkRequest(nris);
+ }
+
+ /**
+ * Class used to generate {@link NetworkRequestInfo} based off of {@link OemNetworkPreferences}.
+ */
+ @VisibleForTesting
+ final class OemNetworkRequestFactory {
+ List<NetworkRequestInfo> createNrisFromOemNetworkPreferences(
+ @NonNull final OemNetworkPreferences preference) {
+ final List<NetworkRequestInfo> nris = new ArrayList<>();
+ final SparseArray<Set<Integer>> uids =
+ createUidsFromOemNetworkPreferences(preference);
+ for (int i = 0; i < uids.size(); i++) {
+ final int key = uids.keyAt(i);
+ final Set<Integer> value = uids.valueAt(i);
+ final NetworkRequestInfo nri = createNriFromOemNetworkPreferences(key, value);
+ // No need to add an nri without any requests.
+ if (0 == nri.mRequests.size()) {
+ continue;
+ }
+ nris.add(nri);
+ }
+
+ return nris;
+ }
+
+ private SparseArray<Set<Integer>> createUidsFromOemNetworkPreferences(
+ @NonNull final OemNetworkPreferences preference) {
+ final SparseArray<Set<Integer>> uids = new SparseArray<>();
+ final PackageManager pm = mContext.getPackageManager();
+ for (final Map.Entry<String, Integer> entry :
+ preference.getNetworkPreferences().entrySet()) {
+ @OemNetworkPreferences.OemNetworkPreference final int pref = entry.getValue();
+ try {
+ final int uid = pm.getApplicationInfo(entry.getKey(), 0).uid;
+ if (!uids.contains(pref)) {
+ uids.put(pref, new ArraySet<>());
+ }
+ uids.get(pref).add(uid);
+ } catch (PackageManager.NameNotFoundException e) {
+ // Although this may seem like an error scenario, it is ok that uninstalled
+ // packages are sent on a network preference as the system will watch for
+ // package installations associated with this network preference and update
+ // accordingly. This is done so as to minimize race conditions on app install.
+ // TODO b/177092163 add app install watching.
+ continue;
+ }
+ }
+ return uids;
+ }
+
+ private NetworkRequestInfo createNriFromOemNetworkPreferences(
+ @OemNetworkPreferences.OemNetworkPreference final int preference,
+ @NonNull final Set<Integer> uids) {
+ final List<NetworkRequest> requests = new ArrayList<>();
+ // Requests will ultimately be evaluated by order of insertion therefore it matters.
+ switch (preference) {
+ case OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PAID:
+ requests.add(createUnmeteredNetworkRequest());
+ requests.add(createOemPaidNetworkRequest());
+ requests.add(createDefaultRequest());
+ break;
+ case OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK:
+ requests.add(createUnmeteredNetworkRequest());
+ requests.add(createOemPaidNetworkRequest());
+ break;
+ case OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY:
+ requests.add(createOemPaidNetworkRequest());
+ break;
+ case OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY:
+ requests.add(createOemPrivateNetworkRequest());
+ break;
+ default:
+ // This should never happen.
+ throw new IllegalArgumentException("createNriFromOemNetworkPreferences()"
+ + " called with invalid preference of " + preference);
+ }
+
+ setOemNetworkRequestUids(requests, uids);
+ return new NetworkRequestInfo(requests);
+ }
+
+ private NetworkRequest createUnmeteredNetworkRequest() {
+ final NetworkCapabilities netcap = createDefaultPerAppNetCap()
+ .addCapability(NET_CAPABILITY_NOT_METERED)
+ .addCapability(NET_CAPABILITY_VALIDATED);
+ return createNetworkRequest(NetworkRequest.Type.LISTEN, netcap);
+ }
+
+ private NetworkRequest createOemPaidNetworkRequest() {
+ // NET_CAPABILITY_OEM_PAID is a restricted capability.
+ final NetworkCapabilities netcap = createDefaultPerAppNetCap()
+ .addCapability(NET_CAPABILITY_OEM_PAID)
+ .removeCapability(NET_CAPABILITY_NOT_RESTRICTED);
+ return createNetworkRequest(NetworkRequest.Type.REQUEST, netcap);
+ }
+
+ private NetworkRequest createOemPrivateNetworkRequest() {
+ // NET_CAPABILITY_OEM_PRIVATE is a restricted capability.
+ final NetworkCapabilities netcap = createDefaultPerAppNetCap()
+ .addCapability(NET_CAPABILITY_OEM_PRIVATE)
+ .removeCapability(NET_CAPABILITY_NOT_RESTRICTED);
+ return createNetworkRequest(NetworkRequest.Type.REQUEST, netcap);
+ }
+
+ private NetworkCapabilities createDefaultPerAppNetCap() {
+ final NetworkCapabilities netCap = new NetworkCapabilities();
+ netCap.addCapability(NET_CAPABILITY_INTERNET);
+ netCap.setRequestorUidAndPackageName(Process.myUid(), mContext.getPackageName());
+ return netCap;
+ }
+
+ private void setOemNetworkRequestUids(@NonNull final List<NetworkRequest> requests,
+ @NonNull final Set<Integer> uids) {
+ final Set<UidRange> ranges = new ArraySet<>();
+ for (final int uid : uids) {
+ ranges.add(new UidRange(uid, uid));
+ }
+ for (final NetworkRequest req : requests) {
+ req.networkCapabilities.setUids(ranges);
+ }
+ }
}
}
diff --git a/services/core/java/com/android/server/EntropyMixer.java b/services/core/java/com/android/server/EntropyMixer.java
index c56cef2d58dc..a83c981235df 100644
--- a/services/core/java/com/android/server/EntropyMixer.java
+++ b/services/core/java/com/android/server/EntropyMixer.java
@@ -16,12 +16,6 @@
package com.android.server;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.PrintWriter;
-
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -33,10 +27,15 @@ import android.os.Message;
import android.os.SystemProperties;
import android.util.Slog;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+
/**
* A service designed to load and periodically save &quot;randomness&quot;
- * for the Linux kernel RNG and to mix in data from Hardware RNG (if present)
- * into the Linux RNG.
+ * for the Linux kernel RNG.
*
* <p>When a Linux system starts up, the entropy pool associated with
* {@code /dev/random} may be in a fairly predictable state. Applications which
@@ -45,15 +44,8 @@ import android.util.Slog;
* this effect, it's helpful to carry the entropy pool information across
* shutdowns and startups.
*
- * <p>On systems with Hardware RNG (/dev/hw_random), a block of output from HW
- * RNG is mixed into the Linux RNG on EntropyMixer's startup and whenever
- * EntropyMixer periodically runs to save a block of output from Linux RNG on
- * disk. This mixing is done in a way that does not increase the Linux RNG's
- * entropy estimate is not increased. This is to avoid having to trust/verify
- * the quality and authenticity of the &quot;randomness&quot; of the HW RNG.
- *
* <p>This class was modeled after the script in the
- * <a href="http://www.kernel.org/doc/man-pages/online/pages/man4/random.4.html">
+ * <a href="https://man7.org/linux/man-pages/man4/random.4.html">
* random(4) manual page</a>.
*/
public class EntropyMixer extends Binder {
@@ -64,7 +56,6 @@ public class EntropyMixer extends Binder {
private static final long START_NANOTIME = System.nanoTime();
private final String randomDevice;
- private final String hwRandomDevice;
private final String entropyFile;
/**
@@ -80,7 +71,6 @@ public class EntropyMixer extends Binder {
Slog.e(TAG, "Will not process invalid message");
return;
}
- addHwRandomEntropy();
writeEntropy();
scheduleEntropyWriter();
}
@@ -94,25 +84,21 @@ public class EntropyMixer extends Binder {
};
public EntropyMixer(Context context) {
- this(context, getSystemDir() + "/entropy.dat", "/dev/urandom", "/dev/hw_random");
+ this(context, getSystemDir() + "/entropy.dat", "/dev/urandom");
}
/** Test only interface, not for public use */
public EntropyMixer(
Context context,
String entropyFile,
- String randomDevice,
- String hwRandomDevice) {
+ String randomDevice) {
if (randomDevice == null) { throw new NullPointerException("randomDevice"); }
- if (hwRandomDevice == null) { throw new NullPointerException("hwRandomDevice"); }
if (entropyFile == null) { throw new NullPointerException("entropyFile"); }
this.randomDevice = randomDevice;
- this.hwRandomDevice = hwRandomDevice;
this.entropyFile = entropyFile;
loadInitialEntropy();
addDeviceSpecificEntropy();
- addHwRandomEntropy();
writeEntropy();
scheduleEntropyWriter();
IntentFilter broadcastFilter = new IntentFilter(Intent.ACTION_SHUTDOWN);
@@ -192,23 +178,6 @@ public class EntropyMixer extends Binder {
}
}
- /**
- * Mixes in the output from HW RNG (if present) into the Linux RNG.
- */
- private void addHwRandomEntropy() {
- if (!new File(hwRandomDevice).exists()) {
- // HW RNG not present/exposed -- ignore
- return;
- }
-
- try {
- RandomBlock.fromFile(hwRandomDevice).toFile(randomDevice, false);
- Slog.i(TAG, "Added HW RNG output to entropy pool");
- } catch (IOException e) {
- Slog.w(TAG, "Failed to add HW RNG output to entropy pool", e);
- }
- }
-
private static String getSystemDir() {
File dataDir = Environment.getDataDirectory();
File systemDir = new File(dataDir, "system");
diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java
index f648c3e146de..b48bc900aa84 100644
--- a/services/core/java/com/android/server/IpSecService.java
+++ b/services/core/java/com/android/server/IpSecService.java
@@ -29,6 +29,7 @@ import android.annotation.NonNull;
import android.app.AppOpsManager;
import android.content.Context;
import android.content.pm.PackageManager;
+import android.net.ConnectivityManager;
import android.net.IIpSecService;
import android.net.INetd;
import android.net.InetAddresses;
@@ -41,6 +42,7 @@ import android.net.IpSecTransformResponse;
import android.net.IpSecTunnelInterfaceResponse;
import android.net.IpSecUdpEncapResponse;
import android.net.LinkAddress;
+import android.net.LinkProperties;
import android.net.Network;
import android.net.TrafficStats;
import android.net.util.NetdService;
@@ -797,9 +799,15 @@ public class IpSecService extends IIpSecService.Stub {
}
}
- private final class TunnelInterfaceRecord extends OwnedResourceRecord {
+ /**
+ * Tracks an tunnel interface, and manages cleanup paths.
+ *
+ * <p>This class is not thread-safe, and expects that that users of this class will ensure
+ * synchronization and thread safety by holding the IpSecService.this instance lock
+ */
+ @VisibleForTesting
+ final class TunnelInterfaceRecord extends OwnedResourceRecord {
private final String mInterfaceName;
- private final Network mUnderlyingNetwork;
// outer addresses
private final String mLocalAddress;
@@ -810,6 +818,8 @@ public class IpSecService extends IIpSecService.Stub {
private final int mIfId;
+ private Network mUnderlyingNetwork;
+
TunnelInterfaceRecord(
int resourceId,
String interfaceName,
@@ -870,14 +880,22 @@ public class IpSecService extends IIpSecService.Stub {
releaseNetId(mOkey);
}
- public String getInterfaceName() {
- return mInterfaceName;
+ @GuardedBy("IpSecService.this")
+ public void setUnderlyingNetwork(Network underlyingNetwork) {
+ // When #applyTunnelModeTransform is called, this new underlying network will be used to
+ // update the output mark of the input transform.
+ mUnderlyingNetwork = underlyingNetwork;
}
+ @GuardedBy("IpSecService.this")
public Network getUnderlyingNetwork() {
return mUnderlyingNetwork;
}
+ public String getInterfaceName() {
+ return mInterfaceName;
+ }
+
/** Returns the local, outer address for the tunnelInterface */
public String getLocalAddress() {
return mLocalAddress;
@@ -1429,6 +1447,34 @@ public class IpSecService extends IIpSecService.Stub {
}
}
+ /** Set TunnelInterface to use a specific underlying network. */
+ @Override
+ public synchronized void setNetworkForTunnelInterface(
+ int tunnelResourceId, Network underlyingNetwork, String callingPackage) {
+ enforceTunnelFeatureAndPermissions(callingPackage);
+ Objects.requireNonNull(underlyingNetwork, "No underlying network was specified");
+
+ final UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid());
+
+ // Get tunnelInterface record; if no such interface is found, will throw
+ // IllegalArgumentException. userRecord.mTunnelInterfaceRecords is never null
+ final TunnelInterfaceRecord tunnelInterfaceInfo =
+ userRecord.mTunnelInterfaceRecords.getResourceOrThrow(tunnelResourceId);
+
+ final ConnectivityManager connectivityManager =
+ mContext.getSystemService(ConnectivityManager.class);
+ final LinkProperties lp = connectivityManager.getLinkProperties(underlyingNetwork);
+ if (tunnelInterfaceInfo.getInterfaceName().equals(lp.getInterfaceName())) {
+ throw new IllegalArgumentException(
+ "Underlying network cannot be the network being exposed by this tunnel");
+ }
+
+ // It is meaningless to check if the network exists or is valid because the network might
+ // disconnect at any time after it passes the check.
+
+ tunnelInterfaceInfo.setUnderlyingNetwork(underlyingNetwork);
+ }
+
/**
* Delete a TunnelInterface that has been been allocated by and registered with the system
* server
diff --git a/services/core/java/com/android/server/VcnManagementService.java b/services/core/java/com/android/server/VcnManagementService.java
index 4dce59f23a79..27210daac241 100644
--- a/services/core/java/com/android/server/VcnManagementService.java
+++ b/services/core/java/com/android/server/VcnManagementService.java
@@ -641,21 +641,34 @@ public class VcnManagementService extends IVcnManagementService.Stub {
}
boolean isVcnManagedNetwork = false;
+ boolean isRestrictedCarrierWifi = false;
if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
synchronized (mLock) {
ParcelUuid subGroup = mLastSnapshot.getGroupForSubId(subId);
Vcn vcn = mVcns.get(subGroup);
- if (vcn != null && vcn.isActive()) {
- isVcnManagedNetwork = true;
+ if (vcn != null) {
+ if (vcn.isActive()) {
+ isVcnManagedNetwork = true;
+ }
+
+ if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
+ // Carrier WiFi always restricted if VCN exists (even in safe mode).
+ isRestrictedCarrierWifi = true;
+ }
}
}
}
+
if (isVcnManagedNetwork) {
networkCapabilities.removeCapability(
NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED);
}
+ if (isRestrictedCarrierWifi) {
+ networkCapabilities.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
+ }
+
return new VcnUnderlyingNetworkPolicy(false /* isTearDownRequested */, networkCapabilities);
}
diff --git a/services/core/java/com/android/server/VpnManagerService.java b/services/core/java/com/android/server/VpnManagerService.java
new file mode 100644
index 000000000000..5d89bf1b1d82
--- /dev/null
+++ b/services/core/java/com/android/server/VpnManagerService.java
@@ -0,0 +1,918 @@
+/*
+ * 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 com.android.server;
+
+import static android.Manifest.permission.NETWORK_STACK;
+
+import static com.android.net.module.util.PermissionUtils.enforceAnyPermissionOf;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.ConnectivityManager;
+import android.net.INetd;
+import android.net.IVpnManager;
+import android.net.LinkProperties;
+import android.net.Network;
+import android.net.NetworkStack;
+import android.net.UnderlyingNetworkInfo;
+import android.net.Uri;
+import android.net.VpnManager;
+import android.net.VpnService;
+import android.net.util.NetdService;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.INetworkManagementService;
+import android.os.ParcelFileDescriptor;
+import android.os.Process;
+import android.os.ServiceManager;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.security.Credentials;
+import android.security.KeyStore;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.SparseArray;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.net.LegacyVpnInfo;
+import com.android.internal.net.VpnConfig;
+import com.android.internal.net.VpnProfile;
+import com.android.internal.util.DumpUtils;
+import com.android.internal.util.IndentingPrintWriter;
+import com.android.server.connectivity.Vpn;
+import com.android.server.net.LockdownVpnTracker;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.List;
+
+/**
+ * Service that tracks and manages VPNs, and backs the VpnService and VpnManager APIs.
+ * @hide
+ */
+public class VpnManagerService extends IVpnManager.Stub {
+ private static final String TAG = VpnManagerService.class.getSimpleName();
+
+ @VisibleForTesting
+ protected final HandlerThread mHandlerThread;
+ private final Handler mHandler;
+
+ private final Context mContext;
+ private final Context mUserAllContext;
+
+ private final Dependencies mDeps;
+
+ private final ConnectivityManager mCm;
+ private final KeyStore mKeyStore;
+ private final INetworkManagementService mNMS;
+ private final INetd mNetd;
+ private final UserManager mUserManager;
+
+ @VisibleForTesting
+ @GuardedBy("mVpns")
+ protected final SparseArray<Vpn> mVpns = new SparseArray<>();
+
+ // TODO: investigate if mLockdownEnabled can be removed and replaced everywhere by
+ // a direct call to LockdownVpnTracker.isEnabled().
+ @GuardedBy("mVpns")
+ private boolean mLockdownEnabled;
+ @GuardedBy("mVpns")
+ private LockdownVpnTracker mLockdownTracker;
+
+ /**
+ * Dependencies of VpnManager, for injection in tests.
+ */
+ @VisibleForTesting
+ public static class Dependencies {
+ /** Returns the calling UID of an IPC. */
+ public int getCallingUid() {
+ return Binder.getCallingUid();
+ }
+
+ /** Creates a HandlerThread to be used by this class. */
+ public HandlerThread makeHandlerThread() {
+ return new HandlerThread("VpnManagerService");
+ }
+
+ /** Returns the KeyStore instance to be used by this class. */
+ public KeyStore getKeyStore() {
+ return KeyStore.getInstance();
+ }
+
+ public INetd getNetd() {
+ return NetdService.getInstance();
+ }
+
+ public INetworkManagementService getINetworkManagementService() {
+ return INetworkManagementService.Stub.asInterface(
+ ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE));
+ }
+ }
+
+ public VpnManagerService(Context context, Dependencies deps) {
+ mContext = context;
+ mDeps = deps;
+ mHandlerThread = mDeps.makeHandlerThread();
+ mHandlerThread.start();
+ mHandler = mHandlerThread.getThreadHandler();
+ mKeyStore = mDeps.getKeyStore();
+ mUserAllContext = mContext.createContextAsUser(UserHandle.ALL, 0 /* flags */);
+ mCm = mContext.getSystemService(ConnectivityManager.class);
+ mNMS = mDeps.getINetworkManagementService();
+ mNetd = mDeps.getNetd();
+ mUserManager = mContext.getSystemService(UserManager.class);
+ registerReceivers();
+ log("VpnManagerService starting up");
+ }
+
+ /** Creates a new VpnManagerService */
+ public static VpnManagerService create(Context context) {
+ return new VpnManagerService(context, new Dependencies());
+ }
+
+ /** Informs the service that the system is ready. */
+ public void systemReady() {
+ // Try bringing up tracker, but KeyStore won't be ready yet for secondary users so wait
+ // for user to unlock device too.
+ updateLockdownVpn();
+ }
+
+ @Override
+ /** Dumps service state. */
+ protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter writer,
+ @Nullable String[] args) {
+ if (!DumpUtils.checkDumpPermission(mContext, TAG, writer)) return;
+ IndentingPrintWriter pw = new IndentingPrintWriter(writer, " ");
+ pw.println("VPNs:");
+ pw.increaseIndent();
+ synchronized (mVpns) {
+ for (int i = 0; i < mVpns.size(); i++) {
+ pw.println(mVpns.keyAt(i) + ": " + mVpns.valueAt(i).getPackage());
+ }
+ pw.decreaseIndent();
+ }
+ }
+
+ /**
+ * Prepare for a VPN application.
+ * VPN permissions are checked in the {@link Vpn} class. If the caller is not {@code userId},
+ * {@link android.Manifest.permission.INTERACT_ACROSS_USERS_FULL} permission is required.
+ *
+ * @param oldPackage Package name of the application which currently controls VPN, which will
+ * be replaced. If there is no such application, this should should either be
+ * {@code null} or {@link VpnConfig.LEGACY_VPN}.
+ * @param newPackage Package name of the application which should gain control of VPN, or
+ * {@code null} to disable.
+ * @param userId User for whom to prepare the new VPN.
+ *
+ * @hide
+ */
+ @Override
+ public boolean prepareVpn(@Nullable String oldPackage, @Nullable String newPackage,
+ int userId) {
+ enforceCrossUserPermission(userId);
+
+ synchronized (mVpns) {
+ throwIfLockdownEnabled();
+ Vpn vpn = mVpns.get(userId);
+ if (vpn != null) {
+ return vpn.prepare(oldPackage, newPackage, VpnManager.TYPE_VPN_SERVICE);
+ } else {
+ return false;
+ }
+ }
+ }
+
+ /**
+ * Set whether the VPN package has the ability to launch VPNs without user intervention. This
+ * method is used by system-privileged apps. VPN permissions are checked in the {@link Vpn}
+ * class. If the caller is not {@code userId}, {@link
+ * android.Manifest.permission.INTERACT_ACROSS_USERS_FULL} permission is required.
+ *
+ * @param packageName The package for which authorization state should change.
+ * @param userId User for whom {@code packageName} is installed.
+ * @param vpnType The {@link VpnManager.VpnType} constant representing what class of VPN
+ * permissions should be granted. When unauthorizing an app, {@link
+ * VpnManager.TYPE_VPN_NONE} should be used.
+ * @hide
+ */
+ @Override
+ public void setVpnPackageAuthorization(
+ String packageName, int userId, @VpnManager.VpnType int vpnType) {
+ enforceCrossUserPermission(userId);
+
+ synchronized (mVpns) {
+ Vpn vpn = mVpns.get(userId);
+ if (vpn != null) {
+ vpn.setPackageAuthorization(packageName, vpnType);
+ }
+ }
+ }
+
+ /**
+ * Configure a TUN interface and return its file descriptor. Parameters
+ * are encoded and opaque to this class. This method is used by VpnBuilder
+ * and not available in VpnManager. Permissions are checked in
+ * Vpn class.
+ * @hide
+ */
+ @Override
+ public ParcelFileDescriptor establishVpn(VpnConfig config) {
+ int user = UserHandle.getUserId(mDeps.getCallingUid());
+ synchronized (mVpns) {
+ throwIfLockdownEnabled();
+ return mVpns.get(user).establish(config);
+ }
+ }
+
+ @Override
+ public boolean addVpnAddress(String address, int prefixLength) {
+ int user = UserHandle.getUserId(mDeps.getCallingUid());
+ synchronized (mVpns) {
+ throwIfLockdownEnabled();
+ return mVpns.get(user).addAddress(address, prefixLength);
+ }
+ }
+
+ @Override
+ public boolean removeVpnAddress(String address, int prefixLength) {
+ int user = UserHandle.getUserId(mDeps.getCallingUid());
+ synchronized (mVpns) {
+ throwIfLockdownEnabled();
+ return mVpns.get(user).removeAddress(address, prefixLength);
+ }
+ }
+
+ @Override
+ public boolean setUnderlyingNetworksForVpn(Network[] networks) {
+ int user = UserHandle.getUserId(mDeps.getCallingUid());
+ final boolean success;
+ synchronized (mVpns) {
+ success = mVpns.get(user).setUnderlyingNetworks(networks);
+ }
+ return success;
+ }
+
+ /**
+ * Stores the given VPN profile based on the provisioning package name.
+ *
+ * <p>If there is already a VPN profile stored for the provisioning package, this call will
+ * overwrite the profile.
+ *
+ * <p>This is designed to serve the VpnManager only; settings-based VPN profiles are managed
+ * exclusively by the Settings app, and passed into the platform at startup time.
+ *
+ * @return {@code true} if user consent has already been granted, {@code false} otherwise.
+ * @hide
+ */
+ @Override
+ public boolean provisionVpnProfile(@NonNull VpnProfile profile, @NonNull String packageName) {
+ final int user = UserHandle.getUserId(mDeps.getCallingUid());
+ synchronized (mVpns) {
+ return mVpns.get(user).provisionVpnProfile(packageName, profile, mKeyStore);
+ }
+ }
+
+ /**
+ * Deletes the stored VPN profile for the provisioning package
+ *
+ * <p>If there are no profiles for the given package, this method will silently succeed.
+ *
+ * <p>This is designed to serve the VpnManager only; settings-based VPN profiles are managed
+ * exclusively by the Settings app, and passed into the platform at startup time.
+ *
+ * @hide
+ */
+ @Override
+ public void deleteVpnProfile(@NonNull String packageName) {
+ final int user = UserHandle.getUserId(mDeps.getCallingUid());
+ synchronized (mVpns) {
+ mVpns.get(user).deleteVpnProfile(packageName, mKeyStore);
+ }
+ }
+
+ /**
+ * Starts the VPN based on the stored profile for the given package
+ *
+ * <p>This is designed to serve the VpnManager only; settings-based VPN profiles are managed
+ * exclusively by the Settings app, and passed into the platform at startup time.
+ *
+ * @throws IllegalArgumentException if no profile was found for the given package name.
+ * @hide
+ */
+ @Override
+ public void startVpnProfile(@NonNull String packageName) {
+ final int user = UserHandle.getUserId(mDeps.getCallingUid());
+ synchronized (mVpns) {
+ throwIfLockdownEnabled();
+ mVpns.get(user).startVpnProfile(packageName, mKeyStore);
+ }
+ }
+
+ /**
+ * Stops the Platform VPN if the provided package is running one.
+ *
+ * <p>This is designed to serve the VpnManager only; settings-based VPN profiles are managed
+ * exclusively by the Settings app, and passed into the platform at startup time.
+ *
+ * @hide
+ */
+ @Override
+ public void stopVpnProfile(@NonNull String packageName) {
+ final int user = UserHandle.getUserId(mDeps.getCallingUid());
+ synchronized (mVpns) {
+ mVpns.get(user).stopVpnProfile(packageName);
+ }
+ }
+
+ /**
+ * Start legacy VPN, controlling native daemons as needed. Creates a
+ * secondary thread to perform connection work, returning quickly.
+ */
+ @Override
+ public void startLegacyVpn(VpnProfile profile) {
+ int user = UserHandle.getUserId(mDeps.getCallingUid());
+ final LinkProperties egress = mCm.getActiveLinkProperties();
+ if (egress == null) {
+ throw new IllegalStateException("Missing active network connection");
+ }
+ synchronized (mVpns) {
+ throwIfLockdownEnabled();
+ mVpns.get(user).startLegacyVpn(profile, mKeyStore, null /* underlying */, egress);
+ }
+ }
+
+ /**
+ * Return the information of the ongoing legacy VPN. This method is used
+ * by VpnSettings and not available in ConnectivityManager. Permissions
+ * are checked in Vpn class.
+ */
+ @Override
+ public LegacyVpnInfo getLegacyVpnInfo(int userId) {
+ enforceCrossUserPermission(userId);
+
+ synchronized (mVpns) {
+ return mVpns.get(userId).getLegacyVpnInfo();
+ }
+ }
+
+ /**
+ * Returns the information of the ongoing VPN for {@code userId}. This method is used by
+ * VpnDialogs and not available in ConnectivityManager.
+ * Permissions are checked in Vpn class.
+ * @hide
+ */
+ @Override
+ public VpnConfig getVpnConfig(int userId) {
+ enforceCrossUserPermission(userId);
+ synchronized (mVpns) {
+ Vpn vpn = mVpns.get(userId);
+ if (vpn != null) {
+ return vpn.getVpnConfig();
+ } else {
+ return null;
+ }
+ }
+ }
+
+ private boolean isLockdownVpnEnabled() {
+ return mKeyStore.contains(Credentials.LOCKDOWN_VPN);
+ }
+
+ @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");
+ return false;
+ }
+
+ synchronized (mVpns) {
+ // Tear down existing lockdown if profile was removed
+ mLockdownEnabled = isLockdownVpnEnabled();
+ if (!mLockdownEnabled) {
+ setLockdownTracker(null);
+ return true;
+ }
+
+ byte[] profileTag = mKeyStore.get(Credentials.LOCKDOWN_VPN);
+ if (profileTag == null) {
+ loge("Lockdown VPN configured but cannot be read from keystore");
+ return false;
+ }
+ String profileName = new String(profileTag);
+ final VpnProfile profile = VpnProfile.decode(
+ profileName, mKeyStore.get(Credentials.VPN + profileName));
+ if (profile == null) {
+ loge("Lockdown VPN configured invalid profile " + profileName);
+ setLockdownTracker(null);
+ return true;
+ }
+ int user = UserHandle.getUserId(mDeps.getCallingUid());
+ Vpn vpn = mVpns.get(user);
+ if (vpn == null) {
+ logw("VPN for user " + user + " not ready yet. Skipping lockdown");
+ return false;
+ }
+ setLockdownTracker(
+ new LockdownVpnTracker(mContext, mHandler, mKeyStore, vpn, profile));
+ }
+
+ return true;
+ }
+
+ /**
+ * Internally set new {@link LockdownVpnTracker}, shutting down any existing
+ * {@link LockdownVpnTracker}. Can be {@code null} to disable lockdown.
+ */
+ @GuardedBy("mVpns")
+ private void setLockdownTracker(LockdownVpnTracker tracker) {
+ // Shutdown any existing tracker
+ final LockdownVpnTracker existing = mLockdownTracker;
+ // TODO: Add a trigger when the always-on VPN enable/disable to reevaluate and send the
+ // necessary onBlockedStatusChanged callbacks.
+ mLockdownTracker = null;
+ if (existing != null) {
+ existing.shutdown();
+ }
+
+ if (tracker != null) {
+ mLockdownTracker = tracker;
+ mLockdownTracker.init();
+ }
+ }
+
+ /**
+ * Throws if there is any currently running, always-on Legacy VPN.
+ *
+ * <p>The LockdownVpnTracker and mLockdownEnabled both track whether an always-on Legacy VPN is
+ * running across the entire system. Tracking for app-based VPNs is done on a per-user,
+ * per-package basis in Vpn.java
+ */
+ @GuardedBy("mVpns")
+ private void throwIfLockdownEnabled() {
+ if (mLockdownEnabled) {
+ throw new IllegalStateException("Unavailable in lockdown mode");
+ }
+ }
+
+ /**
+ * Starts the always-on VPN {@link VpnService} for user {@param userId}, which should perform
+ * some setup and then call {@code establish()} to connect.
+ *
+ * @return {@code true} if the service was started, the service was already connected, or there
+ * was no always-on VPN to start. {@code false} otherwise.
+ */
+ private boolean startAlwaysOnVpn(int userId) {
+ synchronized (mVpns) {
+ Vpn vpn = mVpns.get(userId);
+ if (vpn == null) {
+ // Shouldn't happen as all code paths that point here should have checked the Vpn
+ // exists already.
+ Log.wtf(TAG, "User " + userId + " has no Vpn configuration");
+ return false;
+ }
+
+ return vpn.startAlwaysOnVpn(mKeyStore);
+ }
+ }
+
+ @Override
+ public boolean isAlwaysOnVpnPackageSupported(int userId, String packageName) {
+ enforceSettingsPermission();
+ enforceCrossUserPermission(userId);
+
+ synchronized (mVpns) {
+ Vpn vpn = mVpns.get(userId);
+ if (vpn == null) {
+ logw("User " + userId + " has no Vpn configuration");
+ return false;
+ }
+ return vpn.isAlwaysOnPackageSupported(packageName, mKeyStore);
+ }
+ }
+
+ @Override
+ public boolean setAlwaysOnVpnPackage(
+ int userId, String packageName, boolean lockdown, List<String> lockdownAllowlist) {
+ enforceControlAlwaysOnVpnPermission();
+ enforceCrossUserPermission(userId);
+
+ synchronized (mVpns) {
+ // Can't set always-on VPN if legacy VPN is already in lockdown mode.
+ if (isLockdownVpnEnabled()) {
+ return false;
+ }
+
+ Vpn vpn = mVpns.get(userId);
+ if (vpn == null) {
+ logw("User " + userId + " has no Vpn configuration");
+ return false;
+ }
+ if (!vpn.setAlwaysOnPackage(packageName, lockdown, lockdownAllowlist, mKeyStore)) {
+ return false;
+ }
+ if (!startAlwaysOnVpn(userId)) {
+ vpn.setAlwaysOnPackage(null, false, null, mKeyStore);
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public String getAlwaysOnVpnPackage(int userId) {
+ enforceControlAlwaysOnVpnPermission();
+ enforceCrossUserPermission(userId);
+
+ synchronized (mVpns) {
+ Vpn vpn = mVpns.get(userId);
+ if (vpn == null) {
+ logw("User " + userId + " has no Vpn configuration");
+ return null;
+ }
+ return vpn.getAlwaysOnPackage();
+ }
+ }
+
+ @Override
+ public boolean isVpnLockdownEnabled(int userId) {
+ enforceControlAlwaysOnVpnPermission();
+ enforceCrossUserPermission(userId);
+
+ synchronized (mVpns) {
+ Vpn vpn = mVpns.get(userId);
+ if (vpn == null) {
+ logw("User " + userId + " has no Vpn configuration");
+ return false;
+ }
+ return vpn.getLockdown();
+ }
+ }
+
+ @Override
+ public List<String> getVpnLockdownAllowlist(int userId) {
+ enforceControlAlwaysOnVpnPermission();
+ enforceCrossUserPermission(userId);
+
+ synchronized (mVpns) {
+ Vpn vpn = mVpns.get(userId);
+ if (vpn == null) {
+ logw("User " + userId + " has no Vpn configuration");
+ return null;
+ }
+ return vpn.getLockdownAllowlist();
+ }
+ }
+
+ @GuardedBy("mVpns")
+ private Vpn getVpnIfOwner() {
+ return getVpnIfOwner(mDeps.getCallingUid());
+ }
+
+ // TODO: stop calling into Vpn.java and get this information from data in this class.
+ @GuardedBy("mVpns")
+ private Vpn getVpnIfOwner(int uid) {
+ final int user = UserHandle.getUserId(uid);
+
+ final Vpn vpn = mVpns.get(user);
+ if (vpn == null) {
+ return null;
+ } else {
+ final UnderlyingNetworkInfo info = vpn.getUnderlyingNetworkInfo();
+ return (info == null || info.ownerUid != uid) ? null : vpn;
+ }
+ }
+
+ private void registerReceivers() {
+ // Set up the listener for user state for creating user VPNs.
+ // Should run on mHandler to avoid any races.
+ IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(Intent.ACTION_USER_STARTED);
+ intentFilter.addAction(Intent.ACTION_USER_STOPPED);
+ intentFilter.addAction(Intent.ACTION_USER_ADDED);
+ intentFilter.addAction(Intent.ACTION_USER_REMOVED);
+ intentFilter.addAction(Intent.ACTION_USER_UNLOCKED);
+
+ mUserAllContext.registerReceiver(
+ mIntentReceiver,
+ intentFilter,
+ null /* broadcastPermission */,
+ mHandler);
+ mContext.createContextAsUser(UserHandle.SYSTEM, 0 /* flags */).registerReceiver(
+ mUserPresentReceiver,
+ new IntentFilter(Intent.ACTION_USER_PRESENT),
+ null /* broadcastPermission */,
+ mHandler /* scheduler */);
+
+ // Listen to package add and removal events for all users.
+ intentFilter = new IntentFilter();
+ intentFilter.addAction(Intent.ACTION_PACKAGE_REPLACED);
+ intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+ intentFilter.addDataScheme("package");
+ mUserAllContext.registerReceiver(
+ mIntentReceiver,
+ intentFilter,
+ null /* broadcastPermission */,
+ mHandler);
+
+ // Listen to lockdown VPN reset.
+ intentFilter = new IntentFilter();
+ intentFilter.addAction(LockdownVpnTracker.ACTION_LOCKDOWN_RESET);
+ mUserAllContext.registerReceiver(
+ mIntentReceiver, intentFilter, NETWORK_STACK, mHandler);
+ }
+
+ private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ ensureRunningOnHandlerThread();
+ final String action = intent.getAction();
+ final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
+ final int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
+ final Uri packageData = intent.getData();
+ final String packageName =
+ packageData != null ? packageData.getSchemeSpecificPart() : null;
+
+ if (LockdownVpnTracker.ACTION_LOCKDOWN_RESET.equals(action)) {
+ onVpnLockdownReset();
+ }
+
+ // UserId should be filled for below intents, check the existence.
+ if (userId == UserHandle.USER_NULL) return;
+
+ if (Intent.ACTION_USER_STARTED.equals(action)) {
+ onUserStarted(userId);
+ } else if (Intent.ACTION_USER_STOPPED.equals(action)) {
+ onUserStopped(userId);
+ } else if (Intent.ACTION_USER_ADDED.equals(action)) {
+ onUserAdded(userId);
+ } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
+ onUserRemoved(userId);
+ } else if (Intent.ACTION_USER_UNLOCKED.equals(action)) {
+ onUserUnlocked(userId);
+ } else if (Intent.ACTION_PACKAGE_REPLACED.equals(action)) {
+ onPackageReplaced(packageName, uid);
+ } else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
+ final boolean isReplacing = intent.getBooleanExtra(
+ Intent.EXTRA_REPLACING, false);
+ onPackageRemoved(packageName, uid, isReplacing);
+ } else {
+ Log.wtf(TAG, "received unexpected intent: " + action);
+ }
+ }
+ };
+
+ private BroadcastReceiver mUserPresentReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ ensureRunningOnHandlerThread();
+ // Try creating lockdown tracker, since user present usually means
+ // unlocked keystore.
+ updateLockdownVpn();
+ // Use the same context that registered receiver before to unregister it. Because use
+ // different context to unregister receiver will cause exception.
+ context.unregisterReceiver(this);
+ }
+ };
+
+ private void onUserStarted(int userId) {
+ synchronized (mVpns) {
+ Vpn userVpn = mVpns.get(userId);
+ if (userVpn != null) {
+ loge("Starting user already has a VPN");
+ return;
+ }
+ userVpn = new Vpn(mHandler.getLooper(), mContext, mNMS, mNetd, userId, mKeyStore);
+ mVpns.put(userId, userVpn);
+ if (mUserManager.getUserInfo(userId).isPrimary() && isLockdownVpnEnabled()) {
+ updateLockdownVpn();
+ }
+ }
+ }
+
+ private void onUserStopped(int userId) {
+ synchronized (mVpns) {
+ Vpn userVpn = mVpns.get(userId);
+ if (userVpn == null) {
+ loge("Stopped user has no VPN");
+ return;
+ }
+ userVpn.onUserStopped();
+ mVpns.delete(userId);
+ }
+ }
+
+ @Override
+ public boolean isCallerCurrentAlwaysOnVpnApp() {
+ synchronized (mVpns) {
+ Vpn vpn = getVpnIfOwner();
+ return vpn != null && vpn.getAlwaysOn();
+ }
+ }
+
+ @Override
+ public boolean isCallerCurrentAlwaysOnVpnLockdownApp() {
+ synchronized (mVpns) {
+ Vpn vpn = getVpnIfOwner();
+ return vpn != null && vpn.getLockdown();
+ }
+ }
+
+
+ private void onUserAdded(int userId) {
+ synchronized (mVpns) {
+ final int vpnsSize = mVpns.size();
+ for (int i = 0; i < vpnsSize; i++) {
+ Vpn vpn = mVpns.valueAt(i);
+ vpn.onUserAdded(userId);
+ }
+ }
+ }
+
+ private void onUserRemoved(int userId) {
+ synchronized (mVpns) {
+ final int vpnsSize = mVpns.size();
+ for (int i = 0; i < vpnsSize; i++) {
+ Vpn vpn = mVpns.valueAt(i);
+ vpn.onUserRemoved(userId);
+ }
+ }
+ }
+
+ private void onPackageReplaced(String packageName, int uid) {
+ if (TextUtils.isEmpty(packageName) || uid < 0) {
+ Log.wtf(TAG, "Invalid package in onPackageReplaced: " + packageName + " | " + uid);
+ return;
+ }
+ final int userId = UserHandle.getUserId(uid);
+ synchronized (mVpns) {
+ final Vpn vpn = mVpns.get(userId);
+ if (vpn == null) {
+ return;
+ }
+ // Legacy always-on VPN won't be affected since the package name is not set.
+ if (TextUtils.equals(vpn.getAlwaysOnPackage(), packageName)) {
+ log("Restarting always-on VPN package " + packageName + " for user "
+ + userId);
+ vpn.startAlwaysOnVpn(mKeyStore);
+ }
+ }
+ }
+
+ private void onPackageRemoved(String packageName, int uid, boolean isReplacing) {
+ if (TextUtils.isEmpty(packageName) || uid < 0) {
+ Log.wtf(TAG, "Invalid package in onPackageRemoved: " + packageName + " | " + uid);
+ return;
+ }
+
+ final int userId = UserHandle.getUserId(uid);
+ synchronized (mVpns) {
+ final Vpn vpn = mVpns.get(userId);
+ if (vpn == null) {
+ return;
+ }
+ // Legacy always-on VPN won't be affected since the package name is not set.
+ if (TextUtils.equals(vpn.getAlwaysOnPackage(), packageName) && !isReplacing) {
+ log("Removing always-on VPN package " + packageName + " for user "
+ + userId);
+ vpn.setAlwaysOnPackage(null, false, null, mKeyStore);
+ }
+ }
+ }
+
+ private void onUserUnlocked(int userId) {
+ synchronized (mVpns) {
+ // User present may be sent because of an unlock, which might mean an unlocked keystore.
+ if (mUserManager.getUserInfo(userId).isPrimary() && isLockdownVpnEnabled()) {
+ updateLockdownVpn();
+ } else {
+ startAlwaysOnVpn(userId);
+ }
+ }
+ }
+
+ private void onVpnLockdownReset() {
+ synchronized (mVpns) {
+ if (mLockdownTracker != null) mLockdownTracker.reset();
+ }
+ }
+
+
+ @Override
+ public void factoryReset() {
+ enforceSettingsPermission();
+
+ if (mUserManager.hasUserRestriction(UserManager.DISALLOW_NETWORK_RESET)
+ || mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_VPN)) {
+ return;
+ }
+
+ // Remove always-on package
+ final int userId = UserHandle.getCallingUserId();
+ synchronized (mVpns) {
+ final String alwaysOnPackage = getAlwaysOnVpnPackage(userId);
+ if (alwaysOnPackage != null) {
+ setAlwaysOnVpnPackage(userId, null, false, null);
+ setVpnPackageAuthorization(alwaysOnPackage, userId, VpnManager.TYPE_VPN_NONE);
+ }
+
+ // Turn Always-on VPN off
+ if (mLockdownEnabled && userId == UserHandle.USER_SYSTEM) {
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ mKeyStore.delete(Credentials.LOCKDOWN_VPN);
+ mLockdownEnabled = false;
+ setLockdownTracker(null);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ // Turn VPN off
+ VpnConfig vpnConfig = getVpnConfig(userId);
+ if (vpnConfig != null) {
+ if (vpnConfig.legacy) {
+ prepareVpn(VpnConfig.LEGACY_VPN, VpnConfig.LEGACY_VPN, userId);
+ } else {
+ // Prevent this app (packagename = vpnConfig.user) from initiating
+ // VPN connections in the future without user intervention.
+ setVpnPackageAuthorization(
+ vpnConfig.user, userId, VpnManager.TYPE_VPN_NONE);
+
+ prepareVpn(null, VpnConfig.LEGACY_VPN, userId);
+ }
+ }
+ }
+ }
+
+ private void ensureRunningOnHandlerThread() {
+ if (mHandler.getLooper().getThread() != Thread.currentThread()) {
+ throw new IllegalStateException(
+ "Not running on VpnManagerService thread: "
+ + Thread.currentThread().getName());
+ }
+ }
+
+ private void enforceControlAlwaysOnVpnPermission() {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.CONTROL_ALWAYS_ON_VPN,
+ "VpnManagerService");
+ }
+
+ /**
+ * Require that the caller is either in the same user or has appropriate permission to interact
+ * across users.
+ *
+ * @param userId Target user for whatever operation the current IPC is supposed to perform.
+ */
+ private void enforceCrossUserPermission(int userId) {
+ if (userId == UserHandle.getCallingUserId()) {
+ // Not a cross-user call.
+ return;
+ }
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.INTERACT_ACROSS_USERS_FULL,
+ "VpnManagerService");
+ }
+
+ private void enforceSettingsPermission() {
+ enforceAnyPermissionOf(mContext,
+ android.Manifest.permission.NETWORK_SETTINGS,
+ NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK);
+ }
+
+ private static void log(String s) {
+ Log.d(TAG, s);
+ }
+
+ private static void logw(String s) {
+ Log.w(TAG, s);
+ }
+
+ private static void loge(String s) {
+ Log.e(TAG, s);
+ }
+}
diff --git a/services/core/java/com/android/server/accounts/OWNERS b/services/core/java/com/android/server/accounts/OWNERS
index ea5fd36702f9..8dcc04a27af6 100644
--- a/services/core/java/com/android/server/accounts/OWNERS
+++ b/services/core/java/com/android/server/accounts/OWNERS
@@ -3,7 +3,6 @@ dementyev@google.com
sandrakwan@google.com
hackbod@google.com
svetoslavganov@google.com
-moltmann@google.com
fkupolov@google.com
yamasani@google.com
omakoto@google.com
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 8f1e4e945bcb..126d04f794f5 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -13318,6 +13318,7 @@ public class ActivityManagerService extends IActivityManager.Stub
long[] miscPss = new long[Debug.MemoryInfo.NUM_OTHER_STATS];
long[] miscSwapPss = new long[Debug.MemoryInfo.NUM_OTHER_STATS];
long[] miscRss = new long[Debug.MemoryInfo.NUM_OTHER_STATS];
+ long[] memtrackTmp = new long[4];
long oomPss[] = new long[DUMP_MEM_OOM_LABEL.length];
long oomSwapPss[] = new long[DUMP_MEM_OOM_LABEL.length];
@@ -13330,6 +13331,8 @@ public class ActivityManagerService extends IActivityManager.Stub
long totalRss = 0;
long cachedPss = 0;
long cachedSwapPss = 0;
+ long totalMemtrackGraphics = 0;
+ long totalMemtrackGl = 0;
boolean hasSwapPss = false;
Debug.MemoryInfo mi = null;
@@ -13352,6 +13355,8 @@ public class ActivityManagerService extends IActivityManager.Stub
final int reportType;
final long startTime;
final long endTime;
+ long memtrackGraphics = 0;
+ long memtrackGl = 0;
if (opts.dumpDetails || (!brief && !opts.oomOnly)) {
reportType = ProcessStats.ADD_PSS_EXTERNAL_SLOW;
startTime = SystemClock.currentThreadTimeMillis();
@@ -13363,7 +13368,7 @@ public class ActivityManagerService extends IActivityManager.Stub
} else {
reportType = ProcessStats.ADD_PSS_EXTERNAL;
startTime = SystemClock.currentThreadTimeMillis();
- long pss = Debug.getPss(pid, tmpLong, null);
+ long pss = Debug.getPss(pid, tmpLong, memtrackTmp);
if (pss == 0) {
continue;
}
@@ -13371,6 +13376,8 @@ public class ActivityManagerService extends IActivityManager.Stub
endTime = SystemClock.currentThreadTimeMillis();
mi.dalvikPrivateDirty = (int) tmpLong[0];
mi.dalvikRss = (int) tmpLong[2];
+ memtrackGraphics = memtrackTmp[1];
+ memtrackGl = memtrackTmp[2];
}
if (!opts.isCheckinRequest && opts.dumpDetails) {
pw.println("\n** MEMINFO in pid " + pid + " [" + r.processName + "] **");
@@ -13435,6 +13442,8 @@ public class ActivityManagerService extends IActivityManager.Stub
totalPss += myTotalPss;
totalSwapPss += myTotalSwapPss;
totalRss += myTotalRss;
+ totalMemtrackGraphics += memtrackGraphics;
+ totalMemtrackGl += memtrackGl;
MemItem pssItem = new MemItem(r.processName + " (pid " + pid +
(hasActivities ? " / activities)" : ")"), r.processName, myTotalPss,
myTotalSwapPss, myTotalRss, pid, hasActivities);
@@ -13500,6 +13509,8 @@ public class ActivityManagerService extends IActivityManager.Stub
for (int i=0; i<N; i++) {
ProcessCpuTracker.Stats st = mProcessCpuTracker.getStats(i);
if (st.vsize > 0 && procMemsMap.indexOfKey(st.pid) < 0) {
+ long memtrackGraphics = 0;
+ long memtrackGl = 0;
if (mi == null) {
mi = new Debug.MemoryInfo();
}
@@ -13508,13 +13519,15 @@ public class ActivityManagerService extends IActivityManager.Stub
continue;
}
} else {
- long pss = Debug.getPss(st.pid, tmpLong, null);
+ long pss = Debug.getPss(st.pid, tmpLong, memtrackTmp);
if (pss == 0) {
continue;
}
mi.nativePss = (int) pss;
mi.nativePrivateDirty = (int) tmpLong[0];
mi.nativeRss = (int) tmpLong[2];
+ memtrackGraphics = memtrackTmp[1];
+ memtrackGl = memtrackTmp[2];
}
final long myTotalPss = mi.getTotalPss();
@@ -13524,6 +13537,8 @@ public class ActivityManagerService extends IActivityManager.Stub
totalSwapPss += myTotalSwapPss;
totalRss += myTotalRss;
nativeProcTotalPss += myTotalPss;
+ totalMemtrackGraphics += memtrackGraphics;
+ totalMemtrackGl += memtrackGl;
MemItem pssItem = new MemItem(st.name + " (pid " + st.pid + ")",
st.name, myTotalPss, mi.getSummaryTotalSwapPss(), myTotalRss,
@@ -13720,13 +13735,13 @@ public class ActivityManagerService extends IActivityManager.Stub
long kernelUsed = memInfo.getKernelUsedSizeKb();
final long ionHeap = Debug.getIonHeapsSizeKb();
final long ionPool = Debug.getIonPoolsSizeKb();
+ final long dmabufMapped = Debug.getDmabufMappedSizeKb();
if (ionHeap >= 0 && ionPool >= 0) {
- final long ionMapped = Debug.getIonMappedSizeKb();
- final long ionUnmapped = ionHeap - ionMapped;
+ final long ionUnmapped = ionHeap - dmabufMapped;
pw.print(" ION: ");
pw.print(stringifyKBSize(ionHeap + ionPool));
pw.print(" (");
- pw.print(stringifyKBSize(ionMapped));
+ pw.print(stringifyKBSize(dmabufMapped));
pw.print(" mapped + ");
pw.print(stringifyKBSize(ionUnmapped));
pw.print(" unmapped + ");
@@ -13735,11 +13750,52 @@ public class ActivityManagerService extends IActivityManager.Stub
// Note: mapped ION memory is not accounted in PSS due to VM_PFNMAP flag being
// set on ION VMAs, therefore consider the entire ION heap as used kernel memory
kernelUsed += ionHeap;
+ } else {
+ final long totalExportedDmabuf = Debug.getDmabufTotalExportedKb();
+ if (totalExportedDmabuf >= 0) {
+ final long dmabufUnmapped = totalExportedDmabuf - dmabufMapped;
+ pw.print("DMA-BUF: ");
+ pw.print(stringifyKBSize(totalExportedDmabuf));
+ pw.print(" (");
+ pw.print(stringifyKBSize(dmabufMapped));
+ pw.print(" mapped + ");
+ pw.print(stringifyKBSize(dmabufUnmapped));
+ pw.println(" unmapped)");
+ // Account unmapped dmabufs as part of kernel memory allocations
+ kernelUsed += dmabufUnmapped;
+ // Replace memtrack HAL reported Graphics category with mapped dmabufs
+ totalPss -= totalMemtrackGraphics;
+ totalPss += dmabufMapped;
+ }
+ final long totalDmabufHeapPool = Debug.getDmabufHeapPoolsSizeKb();
+ if (totalDmabufHeapPool >= 0) {
+ pw.print("DMA-BUF Heaps pool: ");
+ pw.println(stringifyKBSize(totalDmabufHeapPool));
+ }
}
final long gpuUsage = Debug.getGpuTotalUsageKb();
if (gpuUsage >= 0) {
- pw.print(" GPU: "); pw.println(stringifyKBSize(gpuUsage));
+ final long gpuDmaBufUsage = Debug.getGpuDmaBufUsageKb();
+ if (gpuDmaBufUsage >= 0) {
+ final long gpuPrivateUsage = gpuUsage - gpuDmaBufUsage;
+ pw.print(" GPU: ");
+ pw.print(stringifyKBSize(gpuUsage));
+ pw.print(" (");
+ pw.print(stringifyKBSize(gpuDmaBufUsage));
+ pw.print(" dmabuf + ");
+ pw.print(stringifyKBSize(gpuPrivateUsage));
+ pw.println(" private)");
+ // Replace memtrack HAL reported GL category with private GPU allocations and
+ // account it as part of kernel memory allocations
+ totalPss -= totalMemtrackGl;
+ kernelUsed += gpuPrivateUsage;
+ } else {
+ pw.print(" GPU: "); pw.println(stringifyKBSize(gpuUsage));
+ }
}
+
+ // Note: ION/DMA-BUF heap pools are reclaimable and hence, they are included as part of
+ // memInfo.getCachedSizeKb().
final long lostRAM = memInfo.getTotalSizeKb() - (totalPss - totalSwapPss)
- memInfo.getFreeSizeKb() - memInfo.getCachedSizeKb()
- kernelUsed - memInfo.getZramTotalSizeKb();
@@ -14343,7 +14399,7 @@ public class ActivityManagerService extends IActivityManager.Stub
infoMap.put(mi.pid, mi);
}
updateCpuStatsNow();
- long[] memtrackTmp = new long[1];
+ long[] memtrackTmp = new long[4];
long[] swaptrackTmp = new long[2];
final List<ProcessCpuTracker.Stats> stats;
// Get a list of Stats that have vsize > 0
@@ -14371,6 +14427,8 @@ public class ActivityManagerService extends IActivityManager.Stub
long totalPss = 0;
long totalSwapPss = 0;
long totalMemtrack = 0;
+ long totalMemtrackGraphics = 0;
+ long totalMemtrackGl = 0;
for (int i=0, N=memInfos.size(); i<N; i++) {
ProcessMemInfo mi = memInfos.get(i);
if (mi.pss == 0) {
@@ -14381,6 +14439,8 @@ public class ActivityManagerService extends IActivityManager.Stub
totalPss += mi.pss;
totalSwapPss += mi.swapPss;
totalMemtrack += mi.memtrack;
+ totalMemtrackGraphics += memtrackTmp[1];
+ totalMemtrackGl += memtrackTmp[2];
}
Collections.sort(memInfos, new Comparator<ProcessMemInfo>() {
@Override public int compare(ProcessMemInfo lhs, ProcessMemInfo rhs) {
@@ -14539,25 +14599,64 @@ public class ActivityManagerService extends IActivityManager.Stub
final long ionHeap = Debug.getIonHeapsSizeKb();
final long ionPool = Debug.getIonPoolsSizeKb();
if (ionHeap >= 0 && ionPool >= 0) {
- final long ionMapped = Debug.getIonMappedSizeKb();
- final long ionUnmapped = ionHeap - ionMapped;
memInfoBuilder.append(" ION: ");
memInfoBuilder.append(stringifyKBSize(ionHeap + ionPool));
memInfoBuilder.append("\n");
// Note: mapped ION memory is not accounted in PSS due to VM_PFNMAP flag being
// set on ION VMAs, therefore consider the entire ION heap as used kernel memory
kernelUsed += ionHeap;
+ } else {
+ final long totalExportedDmabuf = Debug.getDmabufTotalExportedKb();
+ if (totalExportedDmabuf >= 0) {
+ final long dmabufMapped = Debug.getDmabufMappedSizeKb();
+ final long dmabufUnmapped = totalExportedDmabuf - dmabufMapped;
+ memInfoBuilder.append("DMA-BUF: ");
+ memInfoBuilder.append(stringifyKBSize(totalExportedDmabuf));
+ memInfoBuilder.append("\n");
+ // Account unmapped dmabufs as part of kernel memory allocations
+ kernelUsed += dmabufUnmapped;
+ // Replace memtrack HAL reported Graphics category with mapped dmabufs
+ totalPss -= totalMemtrackGraphics;
+ totalPss += dmabufMapped;
+ }
+ final long totalDmabufHeapPool = Debug.getDmabufHeapPoolsSizeKb();
+ if (totalDmabufHeapPool >= 0) {
+ memInfoBuilder.append("DMA-BUF Heaps pool: ");
+ memInfoBuilder.append(stringifyKBSize(totalDmabufHeapPool));
+ memInfoBuilder.append("\n");
+ }
}
+
final long gpuUsage = Debug.getGpuTotalUsageKb();
if (gpuUsage >= 0) {
- memInfoBuilder.append(" GPU: ");
- memInfoBuilder.append(stringifyKBSize(gpuUsage));
- memInfoBuilder.append("\n");
+ final long gpuDmaBufUsage = Debug.getGpuDmaBufUsageKb();
+ if (gpuDmaBufUsage >= 0) {
+ final long gpuPrivateUsage = gpuUsage - gpuDmaBufUsage;
+ memInfoBuilder.append(" GPU: ");
+ memInfoBuilder.append(stringifyKBSize(gpuUsage));
+ memInfoBuilder.append(" (");
+ memInfoBuilder.append(stringifyKBSize(gpuDmaBufUsage));
+ memInfoBuilder.append(" dmabuf + ");
+ memInfoBuilder.append(stringifyKBSize(gpuPrivateUsage));
+ memInfoBuilder.append(" private)\n");
+ // Replace memtrack HAL reported GL category with private GPU allocations and
+ // account it as part of kernel memory allocations
+ totalPss -= totalMemtrackGl;
+ kernelUsed += gpuPrivateUsage;
+ } else {
+ memInfoBuilder.append(" GPU: ");
+ memInfoBuilder.append(stringifyKBSize(gpuUsage));
+ memInfoBuilder.append("\n");
+ }
+
}
memInfoBuilder.append(" Used RAM: ");
memInfoBuilder.append(stringifyKBSize(
totalPss - cachedPss + kernelUsed));
memInfoBuilder.append("\n");
+
+ // Note: ION/DMA-BUF heap pools are reclaimable and hence, they are included as part of
+ // memInfo.getCachedSizeKb().
memInfoBuilder.append(" Lost RAM: ");
memInfoBuilder.append(stringifyKBSize(memInfo.getTotalSizeKb()
- (totalPss - totalSwapPss) - memInfo.getFreeSizeKb() - memInfo.getCachedSizeKb()
diff --git a/services/core/java/com/android/server/compat/CompatChange.java b/services/core/java/com/android/server/compat/CompatChange.java
index e3757dfc6a59..df83df9a73fb 100644
--- a/services/core/java/com/android/server/compat/CompatChange.java
+++ b/services/core/java/com/android/server/compat/CompatChange.java
@@ -16,15 +16,24 @@
package com.android.server.compat;
+import static android.app.compat.PackageOverride.VALUE_DISABLED;
+import static android.app.compat.PackageOverride.VALUE_ENABLED;
+import static android.app.compat.PackageOverride.VALUE_UNDEFINED;
+
import android.annotation.Nullable;
+import android.app.compat.PackageOverride;
import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledSince;
+import android.content.Context;
import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
import com.android.internal.compat.CompatibilityChangeInfo;
+import com.android.internal.compat.OverrideAllowedState;
import com.android.server.compat.config.Change;
import com.android.server.compat.overrides.ChangeOverrides;
import com.android.server.compat.overrides.OverrideValue;
+import com.android.server.compat.overrides.RawOverrideValue;
import java.util.HashMap;
import java.util.List;
@@ -36,7 +45,7 @@ import java.util.Map;
* <p>A compatibility change has a default setting, determined by the {@code enableAfterTargetSdk}
* and {@code disabled} constructor parameters. If a change is {@code disabled}, this overrides any
* target SDK criteria set. These settings can be overridden for a specific package using
- * {@link #addPackageOverride(String, boolean)}.
+ * {@link #addPackageOverrideInternal(String, boolean)}.
*
* <p>Note, this class is not thread safe so callers must ensure thread safety.
*/
@@ -63,8 +72,8 @@ public final class CompatChange extends CompatibilityChangeInfo {
ChangeListener mListener = null;
- private Map<String, Boolean> mPackageOverrides;
- private Map<String, Boolean> mDeferredOverrides;
+ private Map<String, Boolean> mEvaluatedOverrides;
+ private Map<String, PackageOverride> mRawOverrides;
public CompatChange(long changeId) {
this(changeId, null, -1, -1, false, false, null, false);
@@ -113,18 +122,26 @@ public final class CompatChange extends CompatibilityChangeInfo {
* @param pname Package name to enable the change for.
* @param enabled Whether or not to enable the change.
*/
- void addPackageOverride(String pname, boolean enabled) {
+ private void addPackageOverrideInternal(String pname, boolean enabled) {
if (getLoggingOnly()) {
throw new IllegalArgumentException(
"Can't add overrides for a logging only change " + toString());
}
- if (mPackageOverrides == null) {
- mPackageOverrides = new HashMap<>();
+ if (mEvaluatedOverrides == null) {
+ mEvaluatedOverrides = new HashMap<>();
}
- mPackageOverrides.put(pname, enabled);
+ mEvaluatedOverrides.put(pname, enabled);
notifyListener(pname);
}
+ private void removePackageOverrideInternal(String pname) {
+ if (mEvaluatedOverrides != null) {
+ if (mEvaluatedOverrides.remove(pname) != null) {
+ notifyListener(pname);
+ }
+ }
+ }
+
/**
* Tentatively set the state of this change for a given package name.
* The override will only take effect after that package is installed, if applicable.
@@ -132,17 +149,19 @@ public final class CompatChange extends CompatibilityChangeInfo {
* <p>Note, this method is not thread safe so callers must ensure thread safety.
*
* @param packageName Package name to tentatively enable the change for.
- * @param enabled Whether or not to enable the change.
+ * @param override The package override to be set
*/
- void addPackageDeferredOverride(String packageName, boolean enabled) {
+ void addPackageOverride(String packageName, PackageOverride override,
+ OverrideAllowedState allowedState, Context context) {
if (getLoggingOnly()) {
throw new IllegalArgumentException(
"Can't add overrides for a logging only change " + toString());
}
- if (mDeferredOverrides == null) {
- mDeferredOverrides = new HashMap<>();
+ if (mRawOverrides == null) {
+ mRawOverrides = new HashMap<>();
}
- mDeferredOverrides.put(packageName, enabled);
+ mRawOverrides.put(packageName, override);
+ recheckOverride(packageName, allowedState, context);
}
/**
@@ -157,24 +176,44 @@ public final class CompatChange extends CompatibilityChangeInfo {
* @return {@code true} if the recheck yielded a result that requires invalidating caches
* (a deferred override was consolidated or a regular override was removed).
*/
- boolean recheckOverride(String packageName, boolean allowed) {
- // A deferred override now is allowed by the policy, so promote it to a regular override.
- if (hasDeferredOverride(packageName) && allowed) {
- boolean overrideValue = mDeferredOverrides.remove(packageName);
- addPackageOverride(packageName, overrideValue);
- return true;
+ boolean recheckOverride(String packageName, OverrideAllowedState allowedState,
+ Context context) {
+ boolean allowed = (allowedState.state == OverrideAllowedState.ALLOWED);
+
+ Long version = null;
+ try {
+ ApplicationInfo applicationInfo = context.getPackageManager().getApplicationInfo(
+ packageName, 0);
+ version = applicationInfo.longVersionCode;
+ } catch (PackageManager.NameNotFoundException e) {
+ // Do nothing
}
- // A previously set override is no longer allowed by the policy, so make it deferred.
- if (hasOverride(packageName) && !allowed) {
- boolean overrideValue = mPackageOverrides.remove(packageName);
- addPackageDeferredOverride(packageName, overrideValue);
- // Notify because the override was removed.
- notifyListener(packageName);
- return true;
+
+ // If the app is not installed or no longer has raw overrides, evaluate to false
+ if (version == null || !hasRawOverride(packageName) || !allowed) {
+ removePackageOverrideInternal(packageName);
+ return false;
}
- return false;
+
+ // Evaluate the override based on its version
+ int overrideValue = mRawOverrides.get(packageName).evaluate(version);
+ switch (overrideValue) {
+ case VALUE_UNDEFINED:
+ removePackageOverrideInternal(packageName);
+ break;
+ case VALUE_ENABLED:
+ addPackageOverrideInternal(packageName, true);
+ break;
+ case VALUE_DISABLED:
+ addPackageOverrideInternal(packageName, false);
+ break;
+ }
+ return true;
}
+ boolean hasPackageOverride(String pname) {
+ return mRawOverrides != null && mRawOverrides.containsKey(pname);
+ }
/**
* Remove any package override for the given package name, restoring the default behaviour.
*
@@ -182,15 +221,13 @@ public final class CompatChange extends CompatibilityChangeInfo {
*
* @param pname Package name to reset to defaults for.
*/
- void removePackageOverride(String pname) {
- if (mPackageOverrides != null) {
- if (mPackageOverrides.remove(pname) != null) {
- notifyListener(pname);
- }
- }
- if (mDeferredOverrides != null) {
- mDeferredOverrides.remove(pname);
+ boolean removePackageOverride(String pname, OverrideAllowedState allowedState,
+ Context context) {
+ if (mRawOverrides != null && (mRawOverrides.remove(pname) != null)) {
+ recheckOverride(pname, allowedState, context);
+ return true;
}
+ return false;
}
/**
@@ -204,8 +241,8 @@ public final class CompatChange extends CompatibilityChangeInfo {
if (app == null) {
return defaultValue();
}
- if (mPackageOverrides != null && mPackageOverrides.containsKey(app.packageName)) {
- return mPackageOverrides.get(app.packageName);
+ if (mEvaluatedOverrides != null && mEvaluatedOverrides.containsKey(app.packageName)) {
+ return mEvaluatedOverrides.get(app.packageName);
}
if (getDisabled()) {
return false;
@@ -223,8 +260,16 @@ public final class CompatChange extends CompatibilityChangeInfo {
* @return {@code true} if the change should be enabled for the package.
*/
boolean willBeEnabled(String packageName) {
- if (hasDeferredOverride(packageName)) {
- return mDeferredOverrides.get(packageName);
+ if (hasRawOverride(packageName)) {
+ int eval = mRawOverrides.get(packageName).evaluateForAllVersions();
+ switch (eval) {
+ case VALUE_ENABLED:
+ return true;
+ case VALUE_DISABLED:
+ return false;
+ case VALUE_UNDEFINED:
+ return defaultValue();
+ }
}
return defaultValue();
}
@@ -243,8 +288,8 @@ public final class CompatChange extends CompatibilityChangeInfo {
* @param packageName name of the package
* @return true if there is such override
*/
- boolean hasOverride(String packageName) {
- return mPackageOverrides != null && mPackageOverrides.containsKey(packageName);
+ private boolean hasOverride(String packageName) {
+ return mEvaluatedOverrides != null && mEvaluatedOverrides.containsKey(packageName);
}
/**
@@ -252,65 +297,77 @@ public final class CompatChange extends CompatibilityChangeInfo {
* @param packageName name of the package
* @return true if there is such a deferred override
*/
- boolean hasDeferredOverride(String packageName) {
- return mDeferredOverrides != null && mDeferredOverrides.containsKey(packageName);
- }
-
- /**
- * Checks whether a change has any package overrides.
- * @return true if the change has at least one deferred override
- */
- boolean hasAnyPackageOverride() {
- return mDeferredOverrides != null && !mDeferredOverrides.isEmpty();
- }
-
- /**
- * Checks whether a change has any deferred overrides.
- * @return true if the change has at least one deferred override
- */
- boolean hasAnyDeferredOverride() {
- return mPackageOverrides != null && !mPackageOverrides.isEmpty();
+ private boolean hasRawOverride(String packageName) {
+ return mRawOverrides != null && mRawOverrides.containsKey(packageName);
}
void loadOverrides(ChangeOverrides changeOverrides) {
- if (mDeferredOverrides == null) {
- mDeferredOverrides = new HashMap<>();
+ if (mRawOverrides == null) {
+ mRawOverrides = new HashMap<>();
}
- mDeferredOverrides.clear();
- for (OverrideValue override : changeOverrides.getDeferred().getOverrideValue()) {
- mDeferredOverrides.put(override.getPackageName(), override.getEnabled());
+ mRawOverrides.clear();
+
+ if (mEvaluatedOverrides == null) {
+ mEvaluatedOverrides = new HashMap<>();
}
+ mEvaluatedOverrides.clear();
- if (mPackageOverrides == null) {
- mPackageOverrides = new HashMap<>();
+ // Load deferred overrides for backwards compatibility
+ if (changeOverrides.getDeferred() != null) {
+ for (OverrideValue override : changeOverrides.getDeferred().getOverrideValue()) {
+ mRawOverrides.put(override.getPackageName(),
+ new PackageOverride.Builder().setEnabled(
+ override.getEnabled()).build());
+ }
+ }
+
+ // Load validated overrides. For backwards compatibility, we also add them to raw overrides.
+ if (changeOverrides.getValidated() != null) {
+ for (OverrideValue override : changeOverrides.getValidated().getOverrideValue()) {
+ mEvaluatedOverrides.put(override.getPackageName(), override.getEnabled());
+ mRawOverrides.put(override.getPackageName(),
+ new PackageOverride.Builder().setEnabled(
+ override.getEnabled()).build());
+ }
}
- mPackageOverrides.clear();
- for (OverrideValue override : changeOverrides.getValidated().getOverrideValue()) {
- mPackageOverrides.put(override.getPackageName(), override.getEnabled());
+
+ // Load raw overrides
+ if (changeOverrides.getRaw() != null) {
+ for (RawOverrideValue override : changeOverrides.getRaw().getRawOverrideValue()) {
+ PackageOverride packageOverride = new PackageOverride.Builder()
+ .setMinVersionCode(override.getMinVersionCode())
+ .setMaxVersionCode(override.getMaxVersionCode())
+ .setEnabled(override.getEnabled())
+ .build();
+ mRawOverrides.put(override.getPackageName(), packageOverride);
+ }
}
}
ChangeOverrides saveOverrides() {
- if (!hasAnyDeferredOverride() && !hasAnyPackageOverride()) {
+ if (mRawOverrides == null || mRawOverrides.isEmpty()) {
return null;
}
ChangeOverrides changeOverrides = new ChangeOverrides();
changeOverrides.setChangeId(getId());
- ChangeOverrides.Deferred deferredOverrides = new ChangeOverrides.Deferred();
- List<OverrideValue> deferredList = deferredOverrides.getOverrideValue();
- if (mDeferredOverrides != null) {
- for (Map.Entry<String, Boolean> entry : mDeferredOverrides.entrySet()) {
- OverrideValue override = new OverrideValue();
+ ChangeOverrides.Raw rawOverrides = new ChangeOverrides.Raw();
+ List<RawOverrideValue> rawList = rawOverrides.getRawOverrideValue();
+ if (mRawOverrides != null) {
+ for (Map.Entry<String, PackageOverride> entry : mRawOverrides.entrySet()) {
+ RawOverrideValue override = new RawOverrideValue();
override.setPackageName(entry.getKey());
- override.setEnabled(entry.getValue());
- deferredList.add(override);
+ override.setMinVersionCode(entry.getValue().getMinVersionCode());
+ override.setMaxVersionCode(entry.getValue().getMaxVersionCode());
+ override.setEnabled(entry.getValue().getEnabled());
+ rawList.add(override);
}
}
- changeOverrides.setDeferred(deferredOverrides);
+ changeOverrides.setRaw(rawOverrides);
+
ChangeOverrides.Validated validatedOverrides = new ChangeOverrides.Validated();
List<OverrideValue> validatedList = validatedOverrides.getOverrideValue();
- if (mPackageOverrides != null) {
- for (Map.Entry<String, Boolean> entry : mPackageOverrides.entrySet()) {
+ if (mEvaluatedOverrides != null) {
+ for (Map.Entry<String, Boolean> entry : mEvaluatedOverrides.entrySet()) {
OverrideValue override = new OverrideValue();
override.setPackageName(entry.getKey());
override.setEnabled(entry.getValue());
@@ -337,11 +394,11 @@ public final class CompatChange extends CompatibilityChangeInfo {
if (getLoggingOnly()) {
sb.append("; loggingOnly");
}
- if (mPackageOverrides != null && mPackageOverrides.size() > 0) {
- sb.append("; packageOverrides=").append(mPackageOverrides);
+ if (mEvaluatedOverrides != null && mEvaluatedOverrides.size() > 0) {
+ sb.append("; packageOverrides=").append(mEvaluatedOverrides);
}
- if (mDeferredOverrides != null && mDeferredOverrides.size() > 0) {
- sb.append("; deferredOverrides=").append(mDeferredOverrides);
+ if (mRawOverrides != null && mRawOverrides.size() > 0) {
+ sb.append("; rawOverrides=").append(mRawOverrides);
}
if (getOverridable()) {
sb.append("; overridable");
diff --git a/services/core/java/com/android/server/compat/CompatConfig.java b/services/core/java/com/android/server/compat/CompatConfig.java
index 6b77b9d4ce39..422991e082a9 100644
--- a/services/core/java/com/android/server/compat/CompatConfig.java
+++ b/services/core/java/com/android/server/compat/CompatConfig.java
@@ -17,6 +17,7 @@
package com.android.server.compat;
import android.app.compat.ChangeIdStateCache;
+import android.app.compat.PackageOverride;
import android.compat.Compatibility.ChangeConfig;
import android.content.Context;
import android.content.pm.ApplicationInfo;
@@ -31,6 +32,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.compat.AndroidBuildClassifier;
import com.android.internal.compat.CompatibilityChangeConfig;
import com.android.internal.compat.CompatibilityChangeInfo;
+import com.android.internal.compat.CompatibilityOverrideConfig;
import com.android.internal.compat.IOverrideValidator;
import com.android.internal.compat.OverrideAllowedState;
import com.android.server.compat.config.Change;
@@ -70,11 +72,13 @@ final class CompatConfig {
private final LongSparseArray<CompatChange> mChanges = new LongSparseArray<>();
private final OverrideValidatorImpl mOverrideValidator;
+ private Context mContext;
private File mOverridesFile;
@VisibleForTesting
CompatConfig(AndroidBuildClassifier androidBuildClassifier, Context context) {
mOverrideValidator = new OverrideValidatorImpl(androidBuildClassifier, context, this);
+ mContext = context;
}
static CompatConfig create(AndroidBuildClassifier androidBuildClassifier, Context context) {
@@ -210,17 +214,33 @@ final class CompatConfig {
* @throws IllegalStateException if overriding is not allowed
*/
boolean addOverride(long changeId, String packageName, boolean enabled) {
- boolean alreadyKnown = addOverrideUnsafe(changeId, packageName, enabled);
+ boolean alreadyKnown = addOverrideUnsafe(changeId, packageName,
+ new PackageOverride.Builder().setEnabled(enabled).build());
saveOverrides();
invalidateCache();
return alreadyKnown;
}
/**
- * Unsafe version of {@link #addOverride(long, String, boolean)}.
- * It does not invalidate the cache nor save the overrides.
+ * 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.
+ *
+ * @param overrides list of overrides to default changes config.
+ * @param packageName app for which the overrides will be applied.
*/
- private boolean addOverrideUnsafe(long changeId, String packageName, boolean enabled) {
+ void addOverrides(CompatibilityOverrideConfig overrides, String packageName) {
+ synchronized (mChanges) {
+ for (Long changeId : overrides.overrides.keySet()) {
+ addOverrideUnsafe(changeId, packageName, overrides.overrides.get(changeId));
+ }
+ saveOverrides();
+ invalidateCache();
+ }
+ }
+
+ private boolean addOverrideUnsafe(long changeId, String packageName,
+ PackageOverride overrides) {
boolean alreadyKnown = true;
OverrideAllowedState allowedState =
mOverrideValidator.getOverrideAllowedState(changeId, packageName);
@@ -232,17 +252,8 @@ final class CompatConfig {
c = new CompatChange(changeId);
addChange(c);
}
- switch (allowedState.state) {
- case OverrideAllowedState.ALLOWED:
- c.addPackageOverride(packageName, enabled);
- break;
- case OverrideAllowedState.DEFERRED_VERIFICATION:
- c.addPackageDeferredOverride(packageName, enabled);
- break;
- default:
- throw new IllegalStateException("Should only be able to override changes that "
- + "are allowed or can be deferred.");
- }
+ c.addPackageOverride(packageName, overrides, allowedState, mContext);
+ invalidateCache();
}
return alreadyKnown;
}
@@ -311,47 +322,20 @@ final class CompatConfig {
* It does not invalidate the cache nor save the overrides.
*/
private boolean removeOverrideUnsafe(long changeId, String packageName) {
- boolean overrideExists = false;
synchronized (mChanges) {
CompatChange c = mChanges.get(changeId);
if (c != null) {
- // Always allow removing a deferred override.
- if (c.hasDeferredOverride(packageName)) {
- c.removePackageOverride(packageName);
- overrideExists = true;
- } else if (c.hasOverride(packageName)) {
- // Regular overrides need to pass the policy.
- overrideExists = true;
- OverrideAllowedState allowedState =
- mOverrideValidator.getOverrideAllowedState(changeId, packageName);
+ OverrideAllowedState allowedState =
+ mOverrideValidator.getOverrideAllowedState(changeId, packageName);
+ if (c.hasPackageOverride(packageName)) {
allowedState.enforce(changeId, packageName);
- c.removePackageOverride(packageName);
+ c.removePackageOverride(packageName, allowedState, mContext);
+ invalidateCache();
+ return true;
}
}
}
- return overrideExists;
- }
-
- /**
- * 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.
- *
- * @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) {
- synchronized (mChanges) {
- for (Long changeId : overrides.enabledChanges()) {
- addOverrideUnsafe(changeId, packageName, true);
- }
- for (Long changeId : overrides.disabledChanges()) {
- addOverrideUnsafe(changeId, packageName, false);
-
- }
- saveOverrides();
- invalidateCache();
- }
+ return false;
}
/**
@@ -402,7 +386,8 @@ final class CompatConfig {
int enableTargetSdkChangesForPackage(String packageName, int targetSdkVersion) {
long[] changes = getAllowedChangesSinceTargetSdkForPackage(packageName, targetSdkVersion);
for (long changeId : changes) {
- addOverrideUnsafe(changeId, packageName, true);
+ addOverrideUnsafe(changeId, packageName,
+ new PackageOverride.Builder().setEnabled(true).build());
}
saveOverrides();
invalidateCache();
@@ -418,7 +403,8 @@ final class CompatConfig {
int disableTargetSdkChangesForPackage(String packageName, int targetSdkVersion) {
long[] changes = getAllowedChangesSinceTargetSdkForPackage(packageName, targetSdkVersion);
for (long changeId : changes) {
- addOverrideUnsafe(changeId, packageName, false);
+ addOverrideUnsafe(changeId, packageName,
+ new PackageOverride.Builder().setEnabled(false).build());
}
saveOverrides();
invalidateCache();
@@ -615,8 +601,7 @@ final class CompatConfig {
CompatChange c = mChanges.valueAt(idx);
OverrideAllowedState allowedState =
mOverrideValidator.getOverrideAllowedState(c.getId(), packageName);
- boolean allowedOverride = (allowedState.state == OverrideAllowedState.ALLOWED);
- shouldInvalidateCache |= c.recheckOverride(packageName, allowedOverride);
+ shouldInvalidateCache |= c.recheckOverride(packageName, allowedState, mContext);
}
if (shouldInvalidateCache) {
invalidateCache();
diff --git a/services/core/java/com/android/server/compat/PlatformCompat.java b/services/core/java/com/android/server/compat/PlatformCompat.java
index 6b2a1c950e38..edfc8b8f31b0 100644
--- a/services/core/java/com/android/server/compat/PlatformCompat.java
+++ b/services/core/java/com/android/server/compat/PlatformCompat.java
@@ -25,6 +25,7 @@ import static android.os.Process.SYSTEM_UID;
import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.IActivityManager;
+import android.app.compat.PackageOverride;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -43,6 +44,7 @@ import com.android.internal.compat.AndroidBuildClassifier;
import com.android.internal.compat.ChangeReporter;
import com.android.internal.compat.CompatibilityChangeConfig;
import com.android.internal.compat.CompatibilityChangeInfo;
+import com.android.internal.compat.CompatibilityOverrideConfig;
import com.android.internal.compat.IOverrideValidator;
import com.android.internal.compat.IPlatformCompat;
import com.android.internal.util.DumpUtils;
@@ -51,6 +53,8 @@ import com.android.server.LocalServices;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
/**
* System server internal API for gating and reporting compatibility changes.
@@ -161,6 +165,22 @@ public class PlatformCompat extends IPlatformCompat.Stub {
@Override
public void setOverrides(CompatibilityChangeConfig overrides, String packageName) {
checkCompatChangeOverridePermission();
+ Map<Long, PackageOverride> overridesMap = new HashMap<>();
+ for (long change : overrides.enabledChanges()) {
+ overridesMap.put(change, new PackageOverride.Builder().setEnabled(true).build());
+ }
+ for (long change : overrides.disabledChanges()) {
+ overridesMap.put(change, new PackageOverride.Builder().setEnabled(false)
+ .build());
+ }
+ mCompatConfig.addOverrides(new CompatibilityOverrideConfig(overridesMap), packageName);
+ killPackage(packageName);
+ }
+
+ @Override
+ public void setOverridesFromInstaller(CompatibilityOverrideConfig overrides,
+ String packageName) {
+ checkCompatChangeOverridePermission();
mCompatConfig.addOverrides(overrides, packageName);
killPackage(packageName);
}
@@ -168,7 +188,15 @@ public class PlatformCompat extends IPlatformCompat.Stub {
@Override
public void setOverridesForTest(CompatibilityChangeConfig overrides, String packageName) {
checkCompatChangeOverridePermission();
- mCompatConfig.addOverrides(overrides, packageName);
+ Map<Long, PackageOverride> overridesMap = new HashMap<>();
+ for (long change : overrides.enabledChanges()) {
+ overridesMap.put(change, new PackageOverride.Builder().setEnabled(true).build());
+ }
+ for (long change : overrides.disabledChanges()) {
+ overridesMap.put(change, new PackageOverride.Builder().setEnabled(false)
+ .build());
+ }
+ mCompatConfig.addOverrides(new CompatibilityOverrideConfig(overridesMap), packageName);
}
@Override
diff --git a/services/core/java/com/android/server/connectivity/IpConnectivityEventBuilder.java b/services/core/java/com/android/server/connectivity/IpConnectivityEventBuilder.java
index 397af7ba2991..61b11a5851a9 100644
--- a/services/core/java/com/android/server/connectivity/IpConnectivityEventBuilder.java
+++ b/services/core/java/com/android/server/connectivity/IpConnectivityEventBuilder.java
@@ -16,7 +16,6 @@
package com.android.server.connectivity;
-import static android.net.NetworkCapabilities.MAX_TRANSPORT;
import static android.net.NetworkCapabilities.TRANSPORT_BLUETOOTH;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET;
@@ -25,15 +24,14 @@ import static android.net.NetworkCapabilities.TRANSPORT_VPN;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI_AWARE;
-import android.net.ConnectivityManager;
import android.net.ConnectivityMetricsEvent;
import android.net.metrics.ApfProgramEvent;
import android.net.metrics.ApfStats;
+import android.net.metrics.ConnectStats;
import android.net.metrics.DefaultNetworkEvent;
import android.net.metrics.DhcpClientEvent;
import android.net.metrics.DhcpErrorEvent;
import android.net.metrics.DnsEvent;
-import android.net.metrics.ConnectStats;
import android.net.metrics.IpManagerEvent;
import android.net.metrics.IpReachabilityEvent;
import android.net.metrics.NetworkEvent;
@@ -41,12 +39,13 @@ import android.net.metrics.RaEvent;
import android.net.metrics.ValidationProbeEvent;
import android.net.metrics.WakeupStats;
import android.os.Parcelable;
-import android.util.SparseArray;
import android.util.SparseIntArray;
+
import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass;
import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.IpConnectivityEvent;
import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.IpConnectivityLog;
import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.Pair;
+
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@@ -361,29 +360,22 @@ final public class IpConnectivityEventBuilder {
return IpConnectivityLogClass.UNKNOWN;
case 1:
int t = Long.numberOfTrailingZeros(transports);
- return transportToLinkLayer(t);
+ return TRANSPORT_LINKLAYER_MAP.get(t, IpConnectivityLogClass.UNKNOWN);
default:
return IpConnectivityLogClass.MULTIPLE;
}
}
- private static int transportToLinkLayer(int transport) {
- if (0 <= transport && transport < TRANSPORT_LINKLAYER_MAP.length) {
- return TRANSPORT_LINKLAYER_MAP[transport];
- }
- return IpConnectivityLogClass.UNKNOWN;
- }
-
- private static final int[] TRANSPORT_LINKLAYER_MAP = new int[MAX_TRANSPORT + 1];
+ private static final SparseIntArray TRANSPORT_LINKLAYER_MAP = new SparseIntArray();
static {
- TRANSPORT_LINKLAYER_MAP[TRANSPORT_CELLULAR] = IpConnectivityLogClass.CELLULAR;
- TRANSPORT_LINKLAYER_MAP[TRANSPORT_WIFI] = IpConnectivityLogClass.WIFI;
- TRANSPORT_LINKLAYER_MAP[TRANSPORT_BLUETOOTH] = IpConnectivityLogClass.BLUETOOTH;
- TRANSPORT_LINKLAYER_MAP[TRANSPORT_ETHERNET] = IpConnectivityLogClass.ETHERNET;
- TRANSPORT_LINKLAYER_MAP[TRANSPORT_VPN] = IpConnectivityLogClass.UNKNOWN;
- TRANSPORT_LINKLAYER_MAP[TRANSPORT_WIFI_AWARE] = IpConnectivityLogClass.WIFI_NAN;
- TRANSPORT_LINKLAYER_MAP[TRANSPORT_LOWPAN] = IpConnectivityLogClass.LOWPAN;
- };
+ TRANSPORT_LINKLAYER_MAP.append(TRANSPORT_CELLULAR, IpConnectivityLogClass.CELLULAR);
+ TRANSPORT_LINKLAYER_MAP.append(TRANSPORT_WIFI, IpConnectivityLogClass.WIFI);
+ TRANSPORT_LINKLAYER_MAP.append(TRANSPORT_BLUETOOTH, IpConnectivityLogClass.BLUETOOTH);
+ TRANSPORT_LINKLAYER_MAP.append(TRANSPORT_ETHERNET, IpConnectivityLogClass.ETHERNET);
+ TRANSPORT_LINKLAYER_MAP.append(TRANSPORT_VPN, IpConnectivityLogClass.UNKNOWN);
+ TRANSPORT_LINKLAYER_MAP.append(TRANSPORT_WIFI_AWARE, IpConnectivityLogClass.WIFI_NAN);
+ TRANSPORT_LINKLAYER_MAP.append(TRANSPORT_LOWPAN, IpConnectivityLogClass.LOWPAN);
+ }
private static int ifnameToLinkLayer(String ifname) {
// Do not try to catch all interface names with regexes, instead only catch patterns that
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index bff1a5c99dd2..c05e25367d03 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -717,8 +717,9 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
mNumBackgroundNetworkRequests += delta;
break;
- case TRACK_DEFAULT:
case LISTEN:
+ case TRACK_DEFAULT:
+ case TRACK_SYSTEM_DEFAULT:
break;
case NONE:
diff --git a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
index 3d71b0a269c9..508739f2e1e0 100644
--- a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
+++ b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
@@ -79,7 +79,6 @@ public class NetworkNotificationManager {
// server.
public static final String NOTIFICATION_CHANNEL_NETWORK_STATUS = "NETWORK_STATUS";
public static final String NOTIFICATION_CHANNEL_NETWORK_ALERTS = "NETWORK_ALERTS";
- public static final String NOTIFICATION_CHANNEL_VPN = "VPN";
// The context is for the current user (system server)
private final Context mContext;
@@ -161,13 +160,20 @@ public class NetworkNotificationManager {
if (nai != null) {
transportType = approximateTransportType(nai);
final String extraInfo = nai.networkInfo.getExtraInfo();
- name = TextUtils.isEmpty(extraInfo) ? nai.networkCapabilities.getSsid() : extraInfo;
+ if (nai.linkProperties != null && nai.linkProperties.getCaptivePortalData() != null
+ && !TextUtils.isEmpty(nai.linkProperties.getCaptivePortalData()
+ .getVenueFriendlyName())) {
+ name = nai.linkProperties.getCaptivePortalData().getVenueFriendlyName();
+ } else {
+ name = TextUtils.isEmpty(extraInfo)
+ ? WifiInfo.sanitizeSsid(nai.networkCapabilities.getSsid()) : extraInfo;
+ }
// Only notify for Internet-capable networks.
if (!nai.networkCapabilities.hasCapability(NET_CAPABILITY_INTERNET)) return;
} else {
// Legacy notifications.
transportType = TRANSPORT_CELLULAR;
- name = null;
+ name = "";
}
// Clear any previous notification with lower priority, otherwise return. http://b/63676954.
@@ -193,35 +199,30 @@ public class NetworkNotificationManager {
final CharSequence details;
int icon = getIcon(transportType);
if (notifyType == NotificationType.NO_INTERNET && transportType == TRANSPORT_WIFI) {
- title = r.getString(R.string.wifi_no_internet,
- WifiInfo.sanitizeSsid(nai.networkCapabilities.getSsid()));
+ title = r.getString(R.string.wifi_no_internet, name);
details = r.getString(R.string.wifi_no_internet_detailed);
} else if (notifyType == NotificationType.PRIVATE_DNS_BROKEN) {
if (transportType == TRANSPORT_CELLULAR) {
title = r.getString(R.string.mobile_no_internet);
} else if (transportType == TRANSPORT_WIFI) {
- title = r.getString(R.string.wifi_no_internet,
- WifiInfo.sanitizeSsid(nai.networkCapabilities.getSsid()));
+ title = r.getString(R.string.wifi_no_internet, name);
} else {
title = r.getString(R.string.other_networks_no_internet);
}
details = r.getString(R.string.private_dns_broken_detailed);
} else if (notifyType == NotificationType.PARTIAL_CONNECTIVITY
&& transportType == TRANSPORT_WIFI) {
- title = r.getString(R.string.network_partial_connectivity,
- WifiInfo.sanitizeSsid(nai.networkCapabilities.getSsid()));
+ title = r.getString(R.string.network_partial_connectivity, name);
details = r.getString(R.string.network_partial_connectivity_detailed);
} else if (notifyType == NotificationType.LOST_INTERNET &&
transportType == TRANSPORT_WIFI) {
- title = r.getString(R.string.wifi_no_internet,
- WifiInfo.sanitizeSsid(nai.networkCapabilities.getSsid()));
+ title = r.getString(R.string.wifi_no_internet, name);
details = r.getString(R.string.wifi_no_internet_detailed);
} else if (notifyType == NotificationType.SIGN_IN) {
switch (transportType) {
case TRANSPORT_WIFI:
title = r.getString(R.string.wifi_available_sign_in, 0);
- details = r.getString(R.string.network_available_sign_in_detailed,
- WifiInfo.sanitizeSsid(nai.networkCapabilities.getSsid()));
+ details = r.getString(R.string.network_available_sign_in_detailed, name);
break;
case TRANSPORT_CELLULAR:
title = r.getString(R.string.network_available_sign_in, 0);
diff --git a/services/core/java/com/android/server/connectivity/QosCallbackTracker.java b/services/core/java/com/android/server/connectivity/QosCallbackTracker.java
index 87b4c162a2cc..7ef315c469ae 100644
--- a/services/core/java/com/android/server/connectivity/QosCallbackTracker.java
+++ b/services/core/java/com/android/server/connectivity/QosCallbackTracker.java
@@ -27,7 +27,7 @@ import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.telephony.data.EpsBearerQosSessionAttributes;
-import android.util.Slog;
+import android.util.Log;
import com.android.internal.util.CollectionUtils;
import com.android.server.ConnectivityService;
@@ -260,18 +260,18 @@ public class QosCallbackTracker {
}
private static void log(final String msg) {
- Slog.d(TAG, msg);
+ Log.d(TAG, msg);
}
private static void logw(final String msg) {
- Slog.w(TAG, msg);
+ Log.w(TAG, msg);
}
private static void loge(final String msg) {
- Slog.e(TAG, msg);
+ Log.e(TAG, msg);
}
private static void logwtf(final String msg) {
- Slog.wtf(TAG, msg);
+ Log.wtf(TAG, msg);
}
}
diff --git a/services/core/java/com/android/server/connectivity/TcpKeepaliveController.java b/services/core/java/com/android/server/connectivity/TcpKeepaliveController.java
index b5f20d70db7f..c480594b8c60 100644
--- a/services/core/java/com/android/server/connectivity/TcpKeepaliveController.java
+++ b/services/core/java/com/android/server/connectivity/TcpKeepaliveController.java
@@ -41,7 +41,6 @@ import android.os.Handler;
import android.os.MessageQueue;
import android.os.Messenger;
import android.system.ErrnoException;
-import android.system.Int32Ref;
import android.system.Os;
import android.util.Log;
import android.util.SparseArray;
@@ -306,9 +305,8 @@ public class TcpKeepaliveController {
private static boolean isReceiveQueueEmpty(FileDescriptor fd)
throws ErrnoException {
- Int32Ref result = new Int32Ref(-1);
- Os.ioctlInt(fd, SIOCINQ, result);
- if (result.value != 0) {
+ final int result = Os.ioctlInt(fd, SIOCINQ);
+ if (result != 0) {
Log.e(TAG, "Read queue has data");
return false;
}
@@ -317,9 +315,8 @@ public class TcpKeepaliveController {
private static boolean isSendQueueEmpty(FileDescriptor fd)
throws ErrnoException {
- Int32Ref result = new Int32Ref(-1);
- Os.ioctlInt(fd, SIOCOUTQ, result);
- if (result.value != 0) {
+ final int result = Os.ioctlInt(fd, SIOCOUTQ);
+ if (result != 0) {
Log.e(TAG, "Write queue has data");
return false;
}
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index fc2c7e01efde..a769e88f77d7 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -21,10 +21,10 @@ import static android.net.ConnectivityManager.NETID_UNSET;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
import static android.net.RouteInfo.RTN_THROW;
import static android.net.RouteInfo.RTN_UNREACHABLE;
+import static android.net.VpnManager.NOTIFICATION_CHANNEL_VPN;
import static com.android.internal.util.Preconditions.checkArgument;
import static com.android.internal.util.Preconditions.checkNotNull;
-import static com.android.server.connectivity.NetworkNotificationManager.NOTIFICATION_CHANNEL_VPN;
import android.Manifest;
import android.annotation.NonNull;
@@ -74,6 +74,7 @@ import android.net.UidRangeParcel;
import android.net.UnderlyingNetworkInfo;
import android.net.VpnManager;
import android.net.VpnService;
+import android.net.VpnTransportInfo;
import android.net.ipsec.ike.ChildSessionCallback;
import android.net.ipsec.ike.ChildSessionConfiguration;
import android.net.ipsec.ike.ChildSessionParams;
@@ -171,6 +172,12 @@ public class Vpn {
*/
@VisibleForTesting static final int MAX_VPN_PROFILE_SIZE_BYTES = 1 << 17; // 128kB
+ /**
+ * Network score that VPNs will announce to ConnectivityService.
+ * TODO: remove when the network scoring refactor lands.
+ */
+ private static final int VPN_DEFAULT_SCORE = 101;
+
// TODO: create separate trackers for each unique VPN to support
// automated reconnection
@@ -435,6 +442,7 @@ public class Vpn {
mNetworkCapabilities.addTransportType(NetworkCapabilities.TRANSPORT_VPN);
mNetworkCapabilities.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN);
mNetworkCapabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED);
+ mNetworkCapabilities.setTransportInfo(new VpnTransportInfo(VpnManager.TYPE_VPN_NONE));
loadAlwaysOnPackage(keyStore);
}
@@ -494,6 +502,11 @@ public class Vpn {
updateAlwaysOnNotification(detailedState);
}
+ private void resetNetworkCapabilities() {
+ mNetworkCapabilities.setUids(null);
+ mNetworkCapabilities.setTransportInfo(new VpnTransportInfo(VpnManager.TYPE_VPN_NONE));
+ }
+
/**
* Chooses whether to force all connections to go though VPN.
*
@@ -518,6 +531,11 @@ public class Vpn {
}
}
+ /** Returns the package name that is currently prepared. */
+ public String getPackage() {
+ return mPackage;
+ }
+
/**
* Check whether to prevent all traffic outside of a VPN even when the VPN is not connected.
*
@@ -928,7 +946,7 @@ public class Vpn {
agentDisconnect();
jniReset(mInterface);
mInterface = null;
- mNetworkCapabilities.setUids(null);
+ resetNetworkCapabilities();
}
// Revoke the connection or stop the VpnRunner.
@@ -999,6 +1017,8 @@ public class Vpn {
case VpnManager.TYPE_VPN_SERVICE:
toChange = new String[] {AppOpsManager.OPSTR_ACTIVATE_VPN};
break;
+ case VpnManager.TYPE_VPN_LEGACY:
+ return false;
default:
Log.wtf(TAG, "Unrecognized VPN type while granting authorization");
return false;
@@ -1029,6 +1049,8 @@ public class Vpn {
return isVpnServicePreConsented(context, packageName);
case VpnManager.TYPE_VPN_PLATFORM:
return isVpnProfilePreConsented(context, packageName);
+ case VpnManager.TYPE_VPN_LEGACY:
+ return VpnConfig.LEGACY_VPN.equals(packageName);
default:
return false;
}
@@ -1211,6 +1233,8 @@ public class Vpn {
mNetworkCapabilities.setUids(createUserAndRestrictedProfilesRanges(mUserId,
mConfig.allowedApplications, mConfig.disallowedApplications));
+ mNetworkCapabilities.setTransportInfo(new VpnTransportInfo(getActiveVpnType()));
+
// Only apps targeting Q and above can explicitly declare themselves as metered.
// These VPNs are assumed metered unless they state otherwise.
if (mIsPackageTargetingAtLeastQ && mConfig.isMetered) {
@@ -1220,8 +1244,7 @@ public class Vpn {
}
mNetworkAgent = new NetworkAgent(mContext, mLooper, NETWORKTYPE /* logtag */,
- mNetworkCapabilities, lp,
- ConnectivityConstants.VPN_DEFAULT_SCORE, networkAgentConfig, mNetworkProvider) {
+ mNetworkCapabilities, lp, VPN_DEFAULT_SCORE, networkAgentConfig, mNetworkProvider) {
@Override
public void unwanted() {
// We are user controlled, not driven by NetworkRequest.
@@ -1735,7 +1758,7 @@ public class Vpn {
private void cleanupVpnStateLocked() {
mStatusIntent = null;
- mNetworkCapabilities.setUids(null);
+ resetNetworkCapabilities();
mConfig = null;
mInterface = null;
@@ -1846,22 +1869,18 @@ public class Vpn {
}
/**
- * Gets the currently running App-based VPN type
+ * Gets the currently running VPN type
*
- * @return the {@link VpnManager.VpnType}. {@link VpnManager.TYPE_VPN_NONE} if not running an
- * app-based VPN. While VpnService-based VPNs are always app VPNs and LegacyVpn is always
+ * @return the {@link VpnManager.VpnType}. {@link VpnManager.TYPE_VPN_NONE} if not running a
+ * VPN. While VpnService-based VPNs are always app VPNs and LegacyVpn is always
* Settings-based, the Platform VPNs can be initiated by both apps and Settings.
*/
- public synchronized int getActiveAppVpnType() {
- if (VpnConfig.LEGACY_VPN.equals(mPackage)) {
- return VpnManager.TYPE_VPN_NONE;
- }
-
- if (mVpnRunner != null && mVpnRunner instanceof IkeV2VpnRunner) {
- return VpnManager.TYPE_VPN_PLATFORM;
- } else {
- return VpnManager.TYPE_VPN_SERVICE;
- }
+ public synchronized int getActiveVpnType() {
+ if (!mNetworkInfo.isConnectedOrConnecting()) return VpnManager.TYPE_VPN_NONE;
+ if (mVpnRunner == null) return VpnManager.TYPE_VPN_SERVICE;
+ return mVpnRunner instanceof IkeV2VpnRunner
+ ? VpnManager.TYPE_VPN_PLATFORM
+ : VpnManager.TYPE_VPN_LEGACY;
}
private void updateAlwaysOnNotification(DetailedState networkState) {
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 5d1c4e6715f1..16d4f94277cb 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -555,7 +555,7 @@ public class HdmiControlService extends SystemService {
private void bootCompleted() {
// on boot, if device is interactive, set HDMI CEC state as powered on as well
if (mPowerManager.isInteractive() && isPowerStandbyOrTransient()) {
- onWakeUp();
+ mPowerStatus = HdmiControlManager.POWER_STATUS_ON;
}
}
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index c005af4e9696..a589fedaec72 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -280,6 +280,7 @@ public class LockSettingsService extends ILockSettings.Stub {
super.onBootPhase(phase);
if (phase == PHASE_ACTIVITY_MANAGER_READY) {
mLockSettingsService.migrateOldDataAfterSystemReady();
+ mLockSettingsService.loadEscrowData();
}
}
@@ -832,11 +833,15 @@ public class LockSettingsService extends ILockSettings.Stub {
mSpManager.initWeaverService();
getAuthSecretHal();
mDeviceProvisionedObserver.onSystemReady();
- mRebootEscrowManager.loadRebootEscrowDataIfAvailable();
+
// TODO: maybe skip this for split system user mode.
mStorage.prefetchUser(UserHandle.USER_SYSTEM);
}
+ private void loadEscrowData() {
+ mRebootEscrowManager.loadRebootEscrowDataIfAvailable(mHandler);
+ }
+
private void getAuthSecretHal() {
try {
mAuthSecretService = IAuthSecret.getService(/* retry */ true);
@@ -2381,10 +2386,17 @@ public class LockSettingsService extends ILockSettings.Stub {
public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
String[] args, ShellCallback callback, ResultReceiver resultReceiver) {
enforceShell();
+ final int origPid = Binder.getCallingPid();
+ final int origUid = Binder.getCallingUid();
+
+ // The original identity is an opaque integer.
final long origId = Binder.clearCallingIdentity();
+ Slog.e(TAG, "Caller pid " + origPid + " Caller uid " + origUid);
try {
- (new LockSettingsShellCommand(new LockPatternUtils(mContext))).exec(
- this, in, out, err, args, callback, resultReceiver);
+ final LockSettingsShellCommand command =
+ new LockSettingsShellCommand(new LockPatternUtils(mContext), mContext, origPid,
+ origUid);
+ command.exec(this, in, out, err, args, callback, resultReceiver);
} finally {
Binder.restoreCallingIdentity(origId);
}
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java b/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java
index 7b767b86f0d4..8d38bfede942 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java
@@ -23,8 +23,11 @@ import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PATTE
import android.app.ActivityManager;
import android.app.admin.PasswordMetrics;
+import android.content.Context;
import android.os.ShellCommand;
+import android.os.SystemProperties;
import android.text.TextUtils;
+import android.util.Slog;
import com.android.internal.widget.LockPatternUtils;
import com.android.internal.widget.LockPatternUtils.RequestThrottledException;
@@ -45,15 +48,25 @@ class LockSettingsShellCommand extends ShellCommand {
private static final String COMMAND_VERIFY = "verify";
private static final String COMMAND_GET_DISABLED = "get-disabled";
private static final String COMMAND_REMOVE_CACHE = "remove-cache";
+ private static final String COMMAND_SET_ROR_PROVIDER_PACKAGE =
+ "set-resume-on-reboot-provider-package";
private static final String COMMAND_HELP = "help";
private int mCurrentUserId;
private final LockPatternUtils mLockPatternUtils;
+ private final Context mContext;
+ private final int mCallingPid;
+ private final int mCallingUid;
+
private String mOld = "";
private String mNew = "";
- LockSettingsShellCommand(LockPatternUtils lockPatternUtils) {
+ LockSettingsShellCommand(LockPatternUtils lockPatternUtils, Context context, int callingPid,
+ int callingUid) {
mLockPatternUtils = lockPatternUtils;
+ mCallingPid = callingPid;
+ mCallingUid = callingUid;
+ mContext = context;
}
@Override
@@ -70,6 +83,7 @@ class LockSettingsShellCommand extends ShellCommand {
case COMMAND_HELP:
case COMMAND_GET_DISABLED:
case COMMAND_SET_DISABLED:
+ case COMMAND_SET_ROR_PROVIDER_PACKAGE:
break;
default:
getErrPrintWriter().println(
@@ -82,6 +96,9 @@ class LockSettingsShellCommand extends ShellCommand {
case COMMAND_REMOVE_CACHE:
runRemoveCache();
return 0;
+ case COMMAND_SET_ROR_PROVIDER_PACKAGE:
+ runSetResumeOnRebootProviderPackage();
+ return 0;
case COMMAND_HELP:
onHelp();
return 0;
@@ -173,6 +190,10 @@ class LockSettingsShellCommand extends ShellCommand {
pw.println(" remove-cache [--user USER_ID]");
pw.println(" Removes cached unified challenge for the managed profile.");
pw.println("");
+ pw.println(" set-resume-on-reboot-provider-package <package_name>");
+ pw.println(" Sets the package name for server based resume on reboot service "
+ + "provider.");
+ pw.println("");
}
}
@@ -258,6 +279,17 @@ class LockSettingsShellCommand extends ShellCommand {
return true;
}
+ private boolean runSetResumeOnRebootProviderPackage() {
+ final String packageName = mNew;
+ String name = ResumeOnRebootServiceProvider.PROP_ROR_PROVIDER_PACKAGE;
+ Slog.i(TAG, "Setting " + name + " to " + packageName);
+
+ mContext.enforcePermission(android.Manifest.permission.BIND_RESUME_ON_REBOOT_SERVICE,
+ mCallingPid, mCallingUid, TAG);
+ SystemProperties.set(name, packageName);
+ return true;
+ }
+
private boolean runClear() {
LockscreenCredential none = LockscreenCredential.createNone();
if (!isNewCredentialSufficient(none)) {
diff --git a/services/core/java/com/android/server/locksettings/RebootEscrowData.java b/services/core/java/com/android/server/locksettings/RebootEscrowData.java
index 38eeb88e63b0..af0774c6c3fa 100644
--- a/services/core/java/com/android/server/locksettings/RebootEscrowData.java
+++ b/services/core/java/com/android/server/locksettings/RebootEscrowData.java
@@ -35,6 +35,12 @@ class RebootEscrowData {
*/
private static final int CURRENT_VERSION = 2;
+ /**
+ * This is the legacy version of the escrow data format for R builds. The escrow data is only
+ * encrypted by the escrow key, without additional wrap of another key from keystore.
+ */
+ private static final int LEGACY_SINGLE_ENCRYPTED_VERSION = 1;
+
private RebootEscrowData(byte spVersion, byte[] syntheticPassword, byte[] blob,
RebootEscrowKey key) {
mSpVersion = spVersion;
@@ -64,6 +70,19 @@ class RebootEscrowData {
return mKey;
}
+ private static byte[] decryptBlobCurrentVersion(SecretKey kk, RebootEscrowKey ks,
+ DataInputStream dis) throws IOException {
+ if (kk == null) {
+ throw new IOException("Failed to find wrapper key in keystore, cannot decrypt the"
+ + " escrow data");
+ }
+
+ // Decrypt the blob with the key from keystore first, then decrypt again with the reboot
+ // escrow key.
+ byte[] ksEncryptedBlob = AesEncryptionUtil.decrypt(kk, dis);
+ return AesEncryptionUtil.decrypt(ks.getKey(), ksEncryptedBlob);
+ }
+
static RebootEscrowData fromEncryptedData(RebootEscrowKey ks, byte[] blob, SecretKey kk)
throws IOException {
Objects.requireNonNull(ks);
@@ -71,17 +90,20 @@ class RebootEscrowData {
DataInputStream dis = new DataInputStream(new ByteArrayInputStream(blob));
int version = dis.readInt();
- if (version != CURRENT_VERSION) {
- throw new IOException("Unsupported version " + version);
- }
byte spVersion = dis.readByte();
-
- // Decrypt the blob with the key from keystore first, then decrypt again with the reboot
- // escrow key.
- byte[] ksEncryptedBlob = AesEncryptionUtil.decrypt(kk, dis);
- final byte[] syntheticPassword = AesEncryptionUtil.decrypt(ks.getKey(), ksEncryptedBlob);
-
- return new RebootEscrowData(spVersion, syntheticPassword, blob, ks);
+ switch (version) {
+ case CURRENT_VERSION: {
+ byte[] syntheticPassword = decryptBlobCurrentVersion(kk, ks, dis);
+ return new RebootEscrowData(spVersion, syntheticPassword, blob, ks);
+ }
+ case LEGACY_SINGLE_ENCRYPTED_VERSION: {
+ // Decrypt the blob with the escrow key directly.
+ byte[] syntheticPassword = AesEncryptionUtil.decrypt(ks.getKey(), dis);
+ return new RebootEscrowData(spVersion, syntheticPassword, blob, ks);
+ }
+ default:
+ throw new IOException("Unsupported version " + version);
+ }
}
static RebootEscrowData fromSyntheticPassword(RebootEscrowKey ks, byte spVersion,
diff --git a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
index 06962d414009..30ea5556b41c 100644
--- a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
+++ b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
@@ -21,6 +21,7 @@ import android.annotation.NonNull;
import android.annotation.UserIdInt;
import android.content.Context;
import android.content.pm.UserInfo;
+import android.os.Handler;
import android.os.SystemClock;
import android.os.UserManager;
import android.provider.DeviceConfig;
@@ -39,6 +40,7 @@ import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;
+import java.util.Objects;
import javax.crypto.SecretKey;
@@ -76,6 +78,13 @@ class RebootEscrowManager {
private static final int BOOT_COUNT_TOLERANCE = 5;
/**
+ * The default retry specs for loading reboot escrow data. We will attempt to retry loading
+ * escrow data on temporarily errors, e.g. unavailable network.
+ */
+ private static final int DEFAULT_LOAD_ESCROW_DATA_RETRY_COUNT = 3;
+ private static final int DEFAULT_LOAD_ESCROW_DATA_RETRY_INTERVAL_SECONDS = 30;
+
+ /**
* Logs events for later debugging in bugreports.
*/
private final RebootEscrowEventLog mEventLog;
@@ -137,6 +146,7 @@ class RebootEscrowManager {
RebootEscrowProviderInterface rebootEscrowProvider;
if (DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_OTA,
"server_based_ror_enabled", false)) {
+ Slog.i(TAG, "Using server based resume on reboot");
rebootEscrowProvider = new RebootEscrowProviderServerBasedImpl(mContext, mStorage);
} else {
rebootEscrowProvider = new RebootEscrowProviderHalImpl();
@@ -148,6 +158,14 @@ class RebootEscrowManager {
return null;
}
+ void post(Handler handler, Runnable runnable) {
+ handler.post(runnable);
+ }
+
+ void postDelayed(Handler handler, Runnable runnable, long delayMillis) {
+ handler.postDelayed(runnable, delayMillis);
+ }
+
public Context getContext() {
return mContext;
}
@@ -199,7 +217,18 @@ class RebootEscrowManager {
mKeyStoreManager = injector.getKeyStoreManager();
}
- void loadRebootEscrowDataIfAvailable() {
+ private void onGetRebootEscrowKeyFailed(List<UserInfo> users) {
+ Slog.w(TAG, "Had reboot escrow data for users, but no key; removing escrow storage.");
+ for (UserInfo user : users) {
+ mStorage.removeRebootEscrow(user.id);
+ }
+
+ // Clear the old key in keystore.
+ mKeyStoreManager.clearKeyStoreEncryptionKey();
+ onEscrowRestoreComplete(false);
+ }
+
+ void loadRebootEscrowDataIfAvailable(Handler retryHandler) {
List<UserInfo> users = mUserManager.getUsers();
List<UserInfo> rebootEscrowUsers = new ArrayList<>();
for (UserInfo user : users) {
@@ -212,17 +241,53 @@ class RebootEscrowManager {
return;
}
+ mInjector.post(retryHandler, () -> loadRebootEscrowDataWithRetry(
+ retryHandler, 0, users, rebootEscrowUsers));
+ }
+
+ void scheduleLoadRebootEscrowDataOrFail(Handler retryHandler, int attemptNumber,
+ List<UserInfo> users, List<UserInfo> rebootEscrowUsers) {
+ Objects.requireNonNull(retryHandler);
+
+ final int retryLimit = DeviceConfig.getInt(DeviceConfig.NAMESPACE_OTA,
+ "load_escrow_data_retry_count", DEFAULT_LOAD_ESCROW_DATA_RETRY_COUNT);
+ final int retryIntervalInSeconds = DeviceConfig.getInt(DeviceConfig.NAMESPACE_OTA,
+ "load_escrow_data_retry_interval_seconds",
+ DEFAULT_LOAD_ESCROW_DATA_RETRY_INTERVAL_SECONDS);
+
+ if (attemptNumber < retryLimit) {
+ Slog.i(TAG, "Scheduling loadRebootEscrowData retry number: " + attemptNumber);
+ mInjector.postDelayed(retryHandler, () -> loadRebootEscrowDataWithRetry(
+ retryHandler, attemptNumber, users, rebootEscrowUsers),
+ retryIntervalInSeconds * 1000);
+ return;
+ }
+
+ Slog.w(TAG, "Failed to load reboot escrow data after " + attemptNumber + " attempts");
+ onGetRebootEscrowKeyFailed(users);
+ }
+
+ void loadRebootEscrowDataWithRetry(Handler retryHandler, int attemptNumber,
+ List<UserInfo> users, List<UserInfo> rebootEscrowUsers) {
// Fetch the key from keystore to decrypt the escrow data & escrow key; this key is
// generated before reboot. Note that we will clear the escrow key even if the keystore key
// is null.
SecretKey kk = mKeyStoreManager.getKeyStoreEncryptionKey();
- RebootEscrowKey escrowKey = getAndClearRebootEscrowKey(kk);
- if (kk == null || escrowKey == null) {
- Slog.w(TAG, "Had reboot escrow data for users, but no key; removing escrow storage.");
- for (UserInfo user : users) {
- mStorage.removeRebootEscrow(user.id);
- }
- onEscrowRestoreComplete(false);
+ if (kk == null) {
+ Slog.i(TAG, "Failed to load the key for resume on reboot from key store.");
+ }
+
+ RebootEscrowKey escrowKey;
+ try {
+ escrowKey = getAndClearRebootEscrowKey(kk);
+ } catch (IOException e) {
+ scheduleLoadRebootEscrowDataOrFail(retryHandler, attemptNumber + 1, users,
+ rebootEscrowUsers);
+ return;
+ }
+
+ if (escrowKey == null) {
+ onGetRebootEscrowKeyFailed(users);
return;
}
@@ -249,7 +314,7 @@ class RebootEscrowManager {
}
}
- private RebootEscrowKey getAndClearRebootEscrowKey(SecretKey kk) {
+ private RebootEscrowKey getAndClearRebootEscrowKey(SecretKey kk) throws IOException {
RebootEscrowProviderInterface rebootEscrowProvider = mInjector.getRebootEscrowProvider();
if (rebootEscrowProvider == null) {
Slog.w(TAG,
diff --git a/services/core/java/com/android/server/locksettings/RebootEscrowProviderHalImpl.java b/services/core/java/com/android/server/locksettings/RebootEscrowProviderHalImpl.java
index 6c1040b596c8..4b00772088f2 100644
--- a/services/core/java/com/android/server/locksettings/RebootEscrowProviderHalImpl.java
+++ b/services/core/java/com/android/server/locksettings/RebootEscrowProviderHalImpl.java
@@ -33,7 +33,7 @@ import javax.crypto.SecretKey;
* An implementation of the {@link RebootEscrowProviderInterface} by calling the RebootEscrow HAL.
*/
class RebootEscrowProviderHalImpl implements RebootEscrowProviderInterface {
- private static final String TAG = "RebootEscrowProvider";
+ private static final String TAG = "RebootEscrowProviderHal";
private final Injector mInjector;
diff --git a/services/core/java/com/android/server/locksettings/RebootEscrowProviderInterface.java b/services/core/java/com/android/server/locksettings/RebootEscrowProviderInterface.java
index 857ad5fc312a..af6faad3c76e 100644
--- a/services/core/java/com/android/server/locksettings/RebootEscrowProviderInterface.java
+++ b/services/core/java/com/android/server/locksettings/RebootEscrowProviderInterface.java
@@ -16,6 +16,8 @@
package com.android.server.locksettings;
+import java.io.IOException;
+
import javax.crypto.SecretKey;
/**
@@ -33,9 +35,10 @@ public interface RebootEscrowProviderInterface {
/**
* Returns the stored RebootEscrowKey, and clears the storage. If the stored key is encrypted,
- * use the input key to decrypt the RebootEscrowKey. Returns null on failure.
+ * use the input key to decrypt the RebootEscrowKey. Returns null on failure. Throws an
+ * IOException if the failure is non-fatal, and a retry may succeed.
*/
- RebootEscrowKey getAndClearRebootEscrowKey(SecretKey decryptionKey);
+ RebootEscrowKey getAndClearRebootEscrowKey(SecretKey decryptionKey) throws IOException;
/**
* Clears the stored RebootEscrowKey.
diff --git a/services/core/java/com/android/server/locksettings/RebootEscrowProviderServerBasedImpl.java b/services/core/java/com/android/server/locksettings/RebootEscrowProviderServerBasedImpl.java
index ba1a680ba7fb..b3b45460899d 100644
--- a/services/core/java/com/android/server/locksettings/RebootEscrowProviderServerBasedImpl.java
+++ b/services/core/java/com/android/server/locksettings/RebootEscrowProviderServerBasedImpl.java
@@ -35,7 +35,7 @@ import javax.crypto.SecretKey;
* encrypt & decrypt the blob.
*/
class RebootEscrowProviderServerBasedImpl implements RebootEscrowProviderInterface {
- private static final String TAG = "RebootEscrowProvider";
+ private static final String TAG = "RebootEscrowProviderServerBased";
// Timeout for service binding
private static final long DEFAULT_SERVICE_TIMEOUT_IN_SECONDS = 10;
@@ -50,6 +50,8 @@ class RebootEscrowProviderServerBasedImpl implements RebootEscrowProviderInterfa
private final Injector mInjector;
+ private byte[] mServerBlob;
+
static class Injector {
private ResumeOnRebootServiceConnection mServiceConnection = null;
@@ -124,17 +126,25 @@ class RebootEscrowProviderServerBasedImpl implements RebootEscrowProviderInterfa
}
@Override
- public RebootEscrowKey getAndClearRebootEscrowKey(SecretKey decryptionKey) {
- byte[] serverBlob = mStorage.readRebootEscrowServerBlob();
+ public RebootEscrowKey getAndClearRebootEscrowKey(SecretKey decryptionKey) throws IOException {
+ if (mServerBlob == null) {
+ mServerBlob = mStorage.readRebootEscrowServerBlob();
+ }
// Delete the server blob in storage.
mStorage.removeRebootEscrowServerBlob();
- if (serverBlob == null) {
+ if (mServerBlob == null) {
Slog.w(TAG, "Failed to read reboot escrow server blob from storage");
return null;
}
+ if (decryptionKey == null) {
+ Slog.w(TAG, "Failed to decrypt the escrow key; decryption key from keystore is"
+ + " null.");
+ return null;
+ }
+ Slog.i(TAG, "Loaded reboot escrow server blob from storage");
try {
- byte[] escrowKeyBytes = unwrapServerBlob(serverBlob, decryptionKey);
+ byte[] escrowKeyBytes = unwrapServerBlob(mServerBlob, decryptionKey);
if (escrowKeyBytes == null) {
Slog.w(TAG, "Decrypted reboot escrow key bytes should not be null");
return null;
@@ -145,7 +155,7 @@ class RebootEscrowProviderServerBasedImpl implements RebootEscrowProviderInterfa
}
return RebootEscrowKey.fromKeyBytes(escrowKeyBytes);
- } catch (TimeoutException | RemoteException | IOException e) {
+ } catch (TimeoutException | RemoteException e) {
Slog.w(TAG, "Failed to decrypt the server blob ", e);
return null;
}
diff --git a/services/core/java/com/android/server/locksettings/ResumeOnRebootServiceProvider.java b/services/core/java/com/android/server/locksettings/ResumeOnRebootServiceProvider.java
index a1e18bd5a6bd..9c471b85eb76 100644
--- a/services/core/java/com/android/server/locksettings/ResumeOnRebootServiceProvider.java
+++ b/services/core/java/com/android/server/locksettings/ResumeOnRebootServiceProvider.java
@@ -31,6 +31,7 @@ import android.os.IBinder;
import android.os.ParcelableException;
import android.os.RemoteCallback;
import android.os.RemoteException;
+import android.os.SystemProperties;
import android.os.UserHandle;
import android.provider.DeviceConfig;
import android.service.resumeonreboot.IResumeOnRebootService;
@@ -55,6 +56,10 @@ public class ResumeOnRebootServiceProvider {
Manifest.permission.BIND_RESUME_ON_REBOOT_SERVICE;
private static final String TAG = "ResumeOnRebootServiceProvider";
+ // The system property name that overrides the default service provider package name.
+ static final String PROP_ROR_PROVIDER_PACKAGE =
+ "persist.sys.resume_on_reboot_provider_package";
+
private final Context mContext;
private final PackageManager mPackageManager;
@@ -72,12 +77,19 @@ public class ResumeOnRebootServiceProvider {
private ServiceInfo resolveService() {
Intent intent = new Intent();
intent.setAction(ResumeOnRebootService.SERVICE_INTERFACE);
- if (PROVIDER_PACKAGE != null && !PROVIDER_PACKAGE.equals("")) {
- intent.setPackage(PROVIDER_PACKAGE);
+ int queryFlag = PackageManager.GET_SERVICES;
+ String testAppName = SystemProperties.get(PROP_ROR_PROVIDER_PACKAGE, "");
+ if (!testAppName.isEmpty()) {
+ Slog.i(TAG, "Using test app: " + testAppName);
+ intent.setPackage(testAppName);
+ } else {
+ queryFlag |= PackageManager.MATCH_SYSTEM_ONLY;
+ if (PROVIDER_PACKAGE != null && !PROVIDER_PACKAGE.equals("")) {
+ intent.setPackage(PROVIDER_PACKAGE);
+ }
}
- List<ResolveInfo> resolvedIntents =
- mPackageManager.queryIntentServices(intent, PackageManager.MATCH_SYSTEM_ONLY);
+ List<ResolveInfo> resolvedIntents = mPackageManager.queryIntentServices(intent, queryFlag);
for (ResolveInfo resolvedInfo : resolvedIntents) {
if (resolvedInfo.serviceInfo != null
&& PROVIDER_REQUIRED_PERMISSION.equals(resolvedInfo.serviceInfo.permission)) {
@@ -120,6 +132,7 @@ public class ResumeOnRebootServiceProvider {
if (mServiceConnection != null) {
mContext.unbindService(mServiceConnection);
}
+ mBinder = null;
}
/** Bind to the service */
diff --git a/services/core/java/com/android/server/net/LockdownVpnTracker.java b/services/core/java/com/android/server/net/LockdownVpnTracker.java
index 6d1c68039ee5..3cc32bef0e67 100644
--- a/services/core/java/com/android/server/net/LockdownVpnTracker.java
+++ b/services/core/java/com/android/server/net/LockdownVpnTracker.java
@@ -16,10 +16,10 @@
package com.android.server.net;
-import static android.net.ConnectivityManager.TYPE_NONE;
+import static android.net.NetworkCapabilities.TRANSPORT_VPN;
+import static android.net.VpnManager.NOTIFICATION_CHANNEL_VPN;
import static android.provider.Settings.ACTION_VPN_SETTINGS;
-import static com.android.server.connectivity.NetworkNotificationManager.NOTIFICATION_CHANNEL_VPN;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -28,43 +28,37 @@ import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
+import android.net.ConnectivityManager;
import android.net.LinkAddress;
import android.net.LinkProperties;
+import android.net.Network;
import android.net.NetworkInfo;
-import android.net.NetworkInfo.DetailedState;
-import android.net.NetworkInfo.State;
+import android.net.NetworkRequest;
import android.os.Handler;
import android.security.KeyStore;
import android.text.TextUtils;
import android.util.Log;
import com.android.internal.R;
-import com.android.internal.annotations.GuardedBy;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.internal.net.VpnConfig;
import com.android.internal.net.VpnProfile;
-import com.android.server.ConnectivityService;
-import com.android.server.EventLogTags;
import com.android.server.connectivity.Vpn;
import java.util.List;
import java.util.Objects;
/**
- * State tracker for lockdown mode. Watches for normal {@link NetworkInfo} to be
- * connected and kicks off VPN connection, managing any required {@code netd}
- * firewall rules.
+ * State tracker for legacy lockdown VPN. Watches for physical networks to be
+ * connected and kicks off VPN connection.
*/
public class LockdownVpnTracker {
private static final String TAG = "LockdownVpnTracker";
- /** Number of VPN attempts before waiting for user intervention. */
- private static final int MAX_ERROR_COUNT = 4;
-
public static final String ACTION_LOCKDOWN_RESET = "com.android.server.action.LOCKDOWN_RESET";
@NonNull private final Context mContext;
- @NonNull private final ConnectivityService mConnService;
+ @NonNull private final ConnectivityManager mCm;
@NonNull private final NotificationManager mNotificationManager;
@NonNull private final Handler mHandler;
@NonNull private final Vpn mVpn;
@@ -76,19 +70,73 @@ public class LockdownVpnTracker {
@NonNull private final PendingIntent mConfigIntent;
@NonNull private final PendingIntent mResetIntent;
+ @NonNull private final NetworkCallback mDefaultNetworkCallback = new NetworkCallback();
+ @NonNull private final VpnNetworkCallback mVpnNetworkCallback = new VpnNetworkCallback();
+
+ private class NetworkCallback extends ConnectivityManager.NetworkCallback {
+ private Network mNetwork = null;
+ private LinkProperties mLinkProperties = null;
+
+ @Override
+ public void onLinkPropertiesChanged(Network network, LinkProperties lp) {
+ boolean networkChanged = false;
+ if (!network.equals(mNetwork)) {
+ // The default network just changed.
+ mNetwork = network;
+ networkChanged = true;
+ }
+ mLinkProperties = lp;
+ // Backwards compatibility: previously, LockdownVpnTracker only responded to connects
+ // and disconnects, not LinkProperties changes on existing networks.
+ if (networkChanged) {
+ synchronized (mStateLock) {
+ handleStateChangedLocked();
+ }
+ }
+ }
+
+ @Override
+ public void onLost(Network network) {
+ // The default network has gone down.
+ mNetwork = null;
+ mLinkProperties = null;
+ synchronized (mStateLock) {
+ handleStateChangedLocked();
+ }
+ }
+
+ public Network getNetwork() {
+ return mNetwork;
+ }
+
+ public LinkProperties getLinkProperties() {
+ return mLinkProperties;
+ }
+ }
+
+ private class VpnNetworkCallback extends NetworkCallback {
+ @Override
+ public void onAvailable(Network network) {
+ synchronized (mStateLock) {
+ handleStateChangedLocked();
+ }
+ }
+ @Override
+ public void onLost(Network network) {
+ onAvailable(network);
+ }
+ }
+
@Nullable
private String mAcceptedEgressIface;
- private int mErrorCount;
-
public LockdownVpnTracker(@NonNull Context context,
- @NonNull ConnectivityService connService,
@NonNull Handler handler,
@NonNull KeyStore keyStore,
@NonNull Vpn vpn,
@NonNull VpnProfile profile) {
mContext = Objects.requireNonNull(context);
- mConnService = Objects.requireNonNull(connService);
+ mCm = mContext.getSystemService(ConnectivityManager.class);
mHandler = Objects.requireNonNull(handler);
mVpn = Objects.requireNonNull(vpn);
mProfile = Objects.requireNonNull(profile);
@@ -110,24 +158,20 @@ public class LockdownVpnTracker {
* connection when ready, or setting firewall rules once VPN is connected.
*/
private void handleStateChangedLocked() {
-
- final NetworkInfo egressInfo = mConnService.getActiveNetworkInfoUnfiltered();
- final LinkProperties egressProp = mConnService.getActiveLinkProperties();
+ final Network network = mDefaultNetworkCallback.getNetwork();
+ final LinkProperties egressProp = mDefaultNetworkCallback.getLinkProperties();
final NetworkInfo vpnInfo = mVpn.getNetworkInfo();
final VpnConfig vpnConfig = mVpn.getLegacyVpnConfig();
// Restart VPN when egress network disconnected or changed
- final boolean egressDisconnected = egressInfo == null
- || State.DISCONNECTED.equals(egressInfo.getState());
+ final boolean egressDisconnected = (network == null);
final boolean egressChanged = egressProp == null
|| !TextUtils.equals(mAcceptedEgressIface, egressProp.getInterfaceName());
- final int egressType = (egressInfo == null) ? TYPE_NONE : egressInfo.getType();
final String egressIface = (egressProp == null) ?
null : egressProp.getInterfaceName();
- Log.d(TAG, "handleStateChanged: egress=" + egressType
- + " " + mAcceptedEgressIface + "->" + egressIface);
+ Log.d(TAG, "handleStateChanged: egress=" + mAcceptedEgressIface + "->" + egressIface);
if (egressDisconnected || egressChanged) {
mAcceptedEgressIface = null;
@@ -138,46 +182,49 @@ public class LockdownVpnTracker {
return;
}
- if (vpnInfo.getDetailedState() == DetailedState.FAILED) {
- EventLogTags.writeLockdownVpnError(egressType);
- }
-
- if (mErrorCount > MAX_ERROR_COUNT) {
- showNotification(R.string.vpn_lockdown_error, R.drawable.vpn_disconnected);
-
- } else if (egressInfo.isConnected() && !vpnInfo.isConnectedOrConnecting()) {
- if (mProfile.isValidLockdownProfile()) {
- Log.d(TAG, "Active network connected; starting VPN");
- EventLogTags.writeLockdownVpnConnecting(egressType);
- showNotification(R.string.vpn_lockdown_connecting, R.drawable.vpn_disconnected);
-
- mAcceptedEgressIface = egressProp.getInterfaceName();
- try {
- // Use the privileged method because Lockdown VPN is initiated by the system, so
- // no additional permission checks are necessary.
- mVpn.startLegacyVpnPrivileged(mProfile, mKeyStore, null, egressProp);
- } catch (IllegalStateException e) {
- mAcceptedEgressIface = null;
- Log.e(TAG, "Failed to start VPN", e);
- showNotification(R.string.vpn_lockdown_error, R.drawable.vpn_disconnected);
- }
- } else {
+ // At this point, |network| is known to be non-null.
+ if (!vpnInfo.isConnectedOrConnecting()) {
+ if (!mProfile.isValidLockdownProfile()) {
Log.e(TAG, "Invalid VPN profile; requires IP-based server and DNS");
showNotification(R.string.vpn_lockdown_error, R.drawable.vpn_disconnected);
+ return;
}
+ Log.d(TAG, "Active network connected; starting VPN");
+ showNotification(R.string.vpn_lockdown_connecting, R.drawable.vpn_disconnected);
+
+ mAcceptedEgressIface = egressIface;
+ try {
+ // Use the privileged method because Lockdown VPN is initiated by the system, so
+ // no additional permission checks are necessary.
+ //
+ // Pass in the underlying network here because the legacy VPN is, in fact, tightly
+ // coupled to a given underlying network and cannot provide mobility. This makes
+ // things marginally more correct in two ways:
+ //
+ // 1. When the legacy lockdown VPN connects, LegacyTypeTracker broadcasts an extra
+ // CONNECTED broadcast for the underlying network type. The underlying type comes
+ // from here. LTT *could* assume that the underlying network is the default
+ // network, but that might introduce a race condition if, say, the VPN starts
+ // connecting on cell, but when the connection succeeds and the agent is
+ // registered, the default network is now wifi.
+ // 2. If no underlying network is passed in, then CS will assume the underlying
+ // network is the system default. So, if the VPN is up and underlying network
+ // (e.g., wifi) disconnects, CS will inform apps that the VPN's capabilities have
+ // changed to match the new default network (e.g., cell).
+ mVpn.startLegacyVpnPrivileged(mProfile, mKeyStore, network, egressProp);
+ } catch (IllegalStateException e) {
+ mAcceptedEgressIface = null;
+ Log.e(TAG, "Failed to start VPN", e);
+ showNotification(R.string.vpn_lockdown_error, R.drawable.vpn_disconnected);
+ }
} else if (vpnInfo.isConnected() && vpnConfig != null) {
final String iface = vpnConfig.interfaze;
final List<LinkAddress> sourceAddrs = vpnConfig.addresses;
Log.d(TAG, "VPN connected using iface=" + iface
+ ", sourceAddr=" + sourceAddrs.toString());
- EventLogTags.writeLockdownVpnConnected(egressType);
showNotification(R.string.vpn_lockdown_connected, R.drawable.vpn_connected);
-
- final NetworkInfo clone = new NetworkInfo(egressInfo);
- augmentNetworkInfo(clone);
- mConnService.sendConnectedBroadcast(clone);
}
}
@@ -192,7 +239,15 @@ public class LockdownVpnTracker {
mVpn.setEnableTeardown(false);
mVpn.setLockdown(true);
+ mCm.setLegacyLockdownVpnEnabled(true);
handleStateChangedLocked();
+
+ mCm.registerSystemDefaultNetworkCallback(mDefaultNetworkCallback, mHandler);
+ final NetworkRequest vpnRequest = new NetworkRequest.Builder()
+ .clearCapabilities()
+ .addTransportType(TRANSPORT_VPN)
+ .build();
+ mCm.registerNetworkCallback(vpnRequest, mVpnNetworkCallback, mHandler);
}
public void shutdown() {
@@ -205,20 +260,21 @@ public class LockdownVpnTracker {
Log.d(TAG, "shutdownLocked()");
mAcceptedEgressIface = null;
- mErrorCount = 0;
mVpn.stopVpnRunnerPrivileged();
mVpn.setLockdown(false);
+ mCm.setLegacyLockdownVpnEnabled(false);
hideNotification();
mVpn.setEnableTeardown(true);
+ mCm.unregisterNetworkCallback(mDefaultNetworkCallback);
+ mCm.unregisterNetworkCallback(mVpnNetworkCallback);
}
/**
* Reset VPN lockdown tracker. Called by ConnectivityService when receiving
* {@link #ACTION_LOCKDOWN_RESET} pending intent.
*/
- @GuardedBy("mConnService.mVpns")
public void reset() {
Log.d(TAG, "reset()");
synchronized (mStateLock) {
@@ -229,28 +285,6 @@ public class LockdownVpnTracker {
}
}
- public void onNetworkInfoChanged() {
- synchronized (mStateLock) {
- handleStateChangedLocked();
- }
- }
-
- public void onVpnStateChanged(NetworkInfo info) {
- if (info.getDetailedState() == DetailedState.FAILED) {
- mErrorCount++;
- }
- synchronized (mStateLock) {
- handleStateChangedLocked();
- }
- }
-
- public void augmentNetworkInfo(NetworkInfo info) {
- if (info.isConnected()) {
- final NetworkInfo vpnInfo = mVpn.getNetworkInfo();
- info.setDetailedState(vpnInfo.getDetailedState(), vpnInfo.getReason(), null);
- }
- }
-
private void showNotification(int titleRes, int iconRes) {
final Notification.Builder builder =
new Notification.Builder(mContext, NOTIFICATION_CHANNEL_VPN)
diff --git a/services/core/java/com/android/server/pm/BackgroundDexOptService.java b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
index 48ec9b4b502d..acec93cac34d 100644
--- a/services/core/java/com/android/server/pm/BackgroundDexOptService.java
+++ b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
@@ -241,7 +241,7 @@ public class BackgroundDexOptService extends JobService {
// trade-off worth doing to save boot time work.
int result = pm.performDexOptWithStatus(new DexoptOptions(
pkg,
- PackageManagerService.REASON_BOOT,
+ PackageManagerService.REASON_POST_BOOT,
DexoptOptions.DEXOPT_BOOT_COMPLETE));
if (result == PackageDexOptimizer.DEX_OPT_PERFORMED) {
updatedPackages.add(pkg);
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index 79607351b18a..4a2fb5da5e70 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -687,7 +687,8 @@ public class PackageDexOptimizer {
boolean generateCompactDex = true;
switch (compilationReason) {
case PackageManagerService.REASON_FIRST_BOOT:
- case PackageManagerService.REASON_BOOT:
+ case PackageManagerService.REASON_BOOT_AFTER_OTA:
+ case PackageManagerService.REASON_POST_BOOT:
case PackageManagerService.REASON_INSTALL:
generateCompactDex = false;
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index a7b9622ab3c0..febbfbce9e6c 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -676,17 +676,18 @@ public class PackageManagerService extends IPackageManager.Stub
// Compilation reasons.
public static final int REASON_UNKNOWN = -1;
public static final int REASON_FIRST_BOOT = 0;
- public static final int REASON_BOOT = 1;
- public static final int REASON_INSTALL = 2;
- public static final int REASON_INSTALL_FAST = 3;
- public static final int REASON_INSTALL_BULK = 4;
- public static final int REASON_INSTALL_BULK_SECONDARY = 5;
- public static final int REASON_INSTALL_BULK_DOWNGRADED = 6;
- public static final int REASON_INSTALL_BULK_SECONDARY_DOWNGRADED = 7;
- public static final int REASON_BACKGROUND_DEXOPT = 8;
- public static final int REASON_AB_OTA = 9;
- public static final int REASON_INACTIVE_PACKAGE_DOWNGRADE = 10;
- public static final int REASON_SHARED = 11;
+ public static final int REASON_BOOT_AFTER_OTA = 1;
+ public static final int REASON_POST_BOOT = 2;
+ public static final int REASON_INSTALL = 3;
+ public static final int REASON_INSTALL_FAST = 4;
+ public static final int REASON_INSTALL_BULK = 5;
+ public static final int REASON_INSTALL_BULK_SECONDARY = 6;
+ public static final int REASON_INSTALL_BULK_DOWNGRADED = 7;
+ public static final int REASON_INSTALL_BULK_SECONDARY_DOWNGRADED = 8;
+ public static final int REASON_BACKGROUND_DEXOPT = 9;
+ public static final int REASON_AB_OTA = 10;
+ public static final int REASON_INACTIVE_PACKAGE_DOWNGRADE = 11;
+ public static final int REASON_SHARED = 12;
public static final int REASON_LAST = REASON_SHARED;
@@ -9664,10 +9665,7 @@ public class PackageManagerService extends IPackageManager.Stub
// first boot, as they do not have profile data.
boolean causeFirstBoot = isFirstBoot() || mIsPreNUpgrade;
- // We need to re-extract after a pruned cache, as AoT-ed files will be out of date.
- boolean causePrunedCache = VMRuntime.didPruneDalvikCache();
-
- if (!causeUpgrade && !causeFirstBoot && !causePrunedCache) {
+ if (!causeUpgrade && !causeFirstBoot) {
return;
}
@@ -9684,7 +9682,7 @@ public class PackageManagerService extends IPackageManager.Stub
final long startTime = System.nanoTime();
final int[] stats = performDexOptUpgrade(pkgs, mIsPreNUpgrade /* showDialog */,
- causeFirstBoot ? REASON_FIRST_BOOT : REASON_BOOT,
+ causeFirstBoot ? REASON_FIRST_BOOT : REASON_BOOT_AFTER_OTA,
false /* bootComplete */);
final int elapsedTimeSeconds =
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java b/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java
index 9cd55a6bb07e..636db111be88 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java
@@ -29,7 +29,8 @@ public class PackageManagerServiceCompilerMapping {
// Names for compilation reasons.
public static final String REASON_STRINGS[] = {
"first-boot",
- "boot",
+ "boot-after-ota",
+ "post-boot",
"install",
"install-fast",
"install-bulk",
diff --git a/services/core/java/com/android/server/pm/dex/ArtManagerService.java b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
index 6e145b5ecbe4..7de5c9467930 100644
--- a/services/core/java/com/android/server/pm/dex/ArtManagerService.java
+++ b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
@@ -587,7 +587,7 @@ public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub {
private static final int TRON_COMPILATION_REASON_ERROR = 0;
private static final int TRON_COMPILATION_REASON_UNKNOWN = 1;
private static final int TRON_COMPILATION_REASON_FIRST_BOOT = 2;
- private static final int TRON_COMPILATION_REASON_BOOT = 3;
+ private static final int TRON_COMPILATION_REASON_BOOT_DEPRECATED_SINCE_S = 3;
private static final int TRON_COMPILATION_REASON_INSTALL = 4;
private static final int TRON_COMPILATION_REASON_BG_DEXOPT = 5;
private static final int TRON_COMPILATION_REASON_AB_OTA = 6;
@@ -605,6 +605,8 @@ public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub {
private static final int TRON_COMPILATION_REASON_INSTALL_BULK_DOWNGRADED_WITH_DM = 18;
private static final int
TRON_COMPILATION_REASON_INSTALL_BULK_SECONDARY_DOWNGRADED_WITH_DM = 19;
+ private static final int TRON_COMPILATION_REASON_BOOT_AFTER_OTA = 20;
+ private static final int TRON_COMPILATION_REASON_POST_BOOT = 21;
// The annotation to add as a suffix to the compilation reason when dexopt was
// performed with dex metadata.
@@ -618,7 +620,8 @@ public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub {
case "unknown" : return TRON_COMPILATION_REASON_UNKNOWN;
case "error" : return TRON_COMPILATION_REASON_ERROR;
case "first-boot" : return TRON_COMPILATION_REASON_FIRST_BOOT;
- case "boot" : return TRON_COMPILATION_REASON_BOOT;
+ case "boot-after-ota": return TRON_COMPILATION_REASON_BOOT_AFTER_OTA;
+ case "post-boot" : return TRON_COMPILATION_REASON_POST_BOOT;
case "install" : return TRON_COMPILATION_REASON_INSTALL;
case "bg-dexopt" : return TRON_COMPILATION_REASON_BG_DEXOPT;
case "ab-ota" : return TRON_COMPILATION_REASON_AB_OTA;
diff --git a/services/core/java/com/android/server/pm/parsing/library/AndroidNetIpSecIkeUpdater.java b/services/core/java/com/android/server/pm/parsing/library/AndroidNetIpSecIkeUpdater.java
new file mode 100644
index 000000000000..6cdd4df824a8
--- /dev/null
+++ b/services/core/java/com/android/server/pm/parsing/library/AndroidNetIpSecIkeUpdater.java
@@ -0,0 +1,35 @@
+/*
+ * 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 com.android.server.pm.parsing.library;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.pm.parsing.pkg.ParsedPackage;
+
+/**
+ * Updates a package to remove dependency on android.net.ipsec.ike library.
+ *
+ * @hide
+ */
+@VisibleForTesting
+public class AndroidNetIpSecIkeUpdater extends PackageSharedLibraryUpdater {
+
+ private static final String LIBRARY_NAME = "android.net.ipsec.ike";
+
+ @Override
+ public void updatePackage(ParsedPackage parsedPackage, boolean isUpdatedSystemApp) {
+ removeLibrary(parsedPackage, LIBRARY_NAME);
+ }
+}
diff --git a/services/core/java/com/android/server/pm/parsing/library/PackageBackwardCompatibility.java b/services/core/java/com/android/server/pm/parsing/library/PackageBackwardCompatibility.java
index 1405a7d613f1..8a8a302734b1 100644
--- a/services/core/java/com/android/server/pm/parsing/library/PackageBackwardCompatibility.java
+++ b/services/core/java/com/android/server/pm/parsing/library/PackageBackwardCompatibility.java
@@ -45,6 +45,9 @@ public class PackageBackwardCompatibility extends PackageSharedLibraryUpdater {
static {
final List<PackageSharedLibraryUpdater> packageUpdaters = new ArrayList<>();
+ // Remove android.net.ipsec.ike library, it is added to boot classpath since Android S.
+ packageUpdaters.add(new AndroidNetIpSecIkeUpdater());
+
// Remove com.google.android.maps library.
packageUpdaters.add(new ComGoogleAndroidMapsUpdater());
diff --git a/services/core/java/com/android/server/pm/permission/OWNERS b/services/core/java/com/android/server/pm/permission/OWNERS
index 0e88862e01b1..e05ef482ec08 100644
--- a/services/core/java/com/android/server/pm/permission/OWNERS
+++ b/services/core/java/com/android/server/pm/permission/OWNERS
@@ -1,4 +1,3 @@
-moltmann@google.com
zhanghai@google.com
per-file DefaultPermissionGrantPolicy.java = hackbod@android.com
per-file DefaultPermissionGrantPolicy.java = jsharkey@android.com
@@ -7,5 +6,4 @@ per-file DefaultPermissionGrantPolicy.java = toddke@google.com
per-file DefaultPermissionGrantPolicy.java = yamasani@google.com
per-file DefaultPermissionGrantPolicy.java = patb@google.com
per-file DefaultPermissionGrantPolicy.java = eugenesusla@google.com
-per-file DefaultPermissionGrantPolicy.java = moltmann@google.com
per-file DefaultPermissionGrantPolicy.java = zhanghai@google.com
diff --git a/services/core/java/com/android/server/role/OWNERS b/services/core/java/com/android/server/role/OWNERS
index b94d98827d71..31e3549d9111 100644
--- a/services/core/java/com/android/server/role/OWNERS
+++ b/services/core/java/com/android/server/role/OWNERS
@@ -1,5 +1,4 @@
svetoslavganov@google.com
-moltmann@google.com
zhanghai@google.com
evanseverson@google.com
eugenesusla@google.com
diff --git a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
index 2503e812f9e1..37d13fb86dc0 100644
--- a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
+++ b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
@@ -125,10 +125,11 @@ import java.util.concurrent.TimeUnit;
public class VcnGatewayConnection extends StateMachine {
private static final String TAG = VcnGatewayConnection.class.getSimpleName();
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ static final InetAddress DUMMY_ADDR = InetAddresses.parseNumericAddress("192.0.2.0");
+
private static final int[] MERGED_CAPABILITIES =
new int[] {NET_CAPABILITY_NOT_METERED, NET_CAPABILITY_NOT_ROAMING};
-
- private static final InetAddress DUMMY_ADDR = InetAddresses.parseNumericAddress("192.0.2.0");
private static final int ARG_NOT_PRESENT = Integer.MIN_VALUE;
private static final String DISCONNECT_REASON_INTERNAL_ERROR = "Uncaught exception: ";
@@ -412,11 +413,11 @@ public class VcnGatewayConnection extends StateMachine {
@NonNull private final VcnGatewayConnectionConfig mConnectionConfig;
@NonNull private final VcnGatewayStatusCallback mGatewayStatusCallback;
@NonNull private final Dependencies mDeps;
-
@NonNull private final VcnUnderlyingNetworkTrackerCallback mUnderlyingNetworkTrackerCallback;
@NonNull private final IpSecManager mIpSecManager;
- @NonNull private final IpSecTunnelInterface mTunnelIface;
+
+ @Nullable private IpSecTunnelInterface mTunnelIface = null;
/** Running state of this VcnGatewayConnection. */
private boolean mIsRunning = true;
@@ -526,20 +527,6 @@ public class VcnGatewayConnection extends StateMachine {
mUnderlyingNetworkTrackerCallback);
mIpSecManager = mVcnContext.getContext().getSystemService(IpSecManager.class);
- IpSecTunnelInterface iface;
- try {
- iface =
- mIpSecManager.createIpSecTunnelInterface(
- DUMMY_ADDR, DUMMY_ADDR, new Network(-1));
- } catch (IOException | ResourceUnavailableException e) {
- teardownAsynchronously();
- mTunnelIface = null;
-
- return;
- }
-
- mTunnelIface = iface;
-
addState(mDisconnectedState);
addState(mDisconnectingState);
addState(mConnectingState);
@@ -1117,6 +1104,18 @@ public class VcnGatewayConnection extends StateMachine {
class ConnectedState extends ConnectedStateBase {
@Override
protected void enterState() throws Exception {
+ if (mTunnelIface == null) {
+ try {
+ // Requires a real Network object in order to be created; doing this any earlier
+ // means not having a real Network object, or picking an incorrect Network.
+ mTunnelIface =
+ mIpSecManager.createIpSecTunnelInterface(
+ DUMMY_ADDR, DUMMY_ADDR, mUnderlying.network);
+ } catch (IOException | ResourceUnavailableException e) {
+ teardownAsynchronously();
+ }
+ }
+
// Successful connection, clear failed attempt counter
mFailedAttempts = 0;
}
@@ -1434,6 +1433,11 @@ public class VcnGatewayConnection extends StateMachine {
}
@VisibleForTesting(visibility = Visibility.PRIVATE)
+ void setTunnelInterface(IpSecTunnelInterface tunnelIface) {
+ mTunnelIface = tunnelIface;
+ }
+
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
UnderlyingNetworkTrackerCallback getUnderlyingNetworkTrackerCallback() {
return mUnderlyingNetworkTrackerCallback;
}
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index 87c766d961a2..0e2549e164d4 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -28,6 +28,7 @@ cc_library_static {
"com_android_server_am_BatteryStatsService.cpp",
"com_android_server_ConsumerIrService.cpp",
"com_android_server_devicepolicy_CryptoTestHelper.cpp",
+ "com_android_server_connectivity_Vpn.cpp",
"com_android_server_gpu_GpuService.cpp",
"com_android_server_HardwarePropertiesManagerService.cpp",
"com_android_server_input_InputManagerService.cpp",
diff --git a/packages/Connectivity/service/jni/com_android_server_connectivity_Vpn.cpp b/services/core/jni/com_android_server_connectivity_Vpn.cpp
index ea5e7183c905..ea5e7183c905 100644
--- a/packages/Connectivity/service/jni/com_android_server_connectivity_Vpn.cpp
+++ b/services/core/jni/com_android_server_connectivity_Vpn.cpp
diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp
index ccf685c1abd7..1e6f05322223 100644
--- a/services/core/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -40,6 +40,7 @@ int register_android_server_UsbHostManager(JNIEnv* env);
int register_android_server_vr_VrManagerService(JNIEnv* env);
int register_android_server_VibratorService(JNIEnv* env);
int register_android_server_location_GnssLocationProvider(JNIEnv* env);
+int register_android_server_connectivity_Vpn(JNIEnv* env);
int register_android_server_devicepolicy_CryptoTestHelper(JNIEnv*);
int register_android_server_tv_TvUinputBridge(JNIEnv* env);
int register_android_server_tv_TvInputHal(JNIEnv* env);
@@ -91,6 +92,7 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
register_android_server_VibratorService(env);
register_android_server_SystemServer(env);
register_android_server_location_GnssLocationProvider(env);
+ register_android_server_connectivity_Vpn(env);
register_android_server_devicepolicy_CryptoTestHelper(env);
register_android_server_ConsumerIrService(env);
register_android_server_BatteryStatsService(env);
diff --git a/services/core/xsd/platform-compat/overrides/platform-compat-overrides.xsd b/services/core/xsd/platform-compat/overrides/platform-compat-overrides.xsd
index e27e1b8ca89d..1406dbb12e02 100644
--- a/services/core/xsd/platform-compat/overrides/platform-compat-overrides.xsd
+++ b/services/core/xsd/platform-compat/overrides/platform-compat-overrides.xsd
@@ -27,6 +27,13 @@
<xs:attribute type="xs:boolean" name="enabled" use="required" />
</xs:complexType>
+ <xs:complexType name="raw-override-value">
+ <xs:attribute type="xs:string" name="packageName" use="required" />
+ <xs:attribute type="xs:long" name="minVersionCode" />
+ <xs:attribute type="xs:long" name="maxVersionCode" />
+ <xs:attribute type="xs:boolean" name="enabled" use="required" />
+ </xs:complexType>
+
<xs:complexType name="change-overrides">
<xs:attribute type="xs:long" name="changeId" use="required"/>
<xs:element name="validated">
@@ -43,6 +50,13 @@
</xs:sequence>
</xs:complexType>
</xs:element>
+ <xs:element name="raw">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="raw-override-value" type="raw-override-value" maxOccurs="unbounded" minOccurs="0" />
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
</xs:complexType>
<xs:element name="overrides">
diff --git a/services/core/xsd/platform-compat/overrides/schema/current.txt b/services/core/xsd/platform-compat/overrides/schema/current.txt
index 08b82072747b..a5ccffcfbb2b 100644
--- a/services/core/xsd/platform-compat/overrides/schema/current.txt
+++ b/services/core/xsd/platform-compat/overrides/schema/current.txt
@@ -5,9 +5,11 @@ package com.android.server.compat.overrides {
ctor public ChangeOverrides();
method public long getChangeId();
method public com.android.server.compat.overrides.ChangeOverrides.Deferred getDeferred();
+ method public com.android.server.compat.overrides.ChangeOverrides.Raw getRaw();
method public com.android.server.compat.overrides.ChangeOverrides.Validated getValidated();
method public void setChangeId(long);
method public void setDeferred(com.android.server.compat.overrides.ChangeOverrides.Deferred);
+ method public void setRaw(com.android.server.compat.overrides.ChangeOverrides.Raw);
method public void setValidated(com.android.server.compat.overrides.ChangeOverrides.Validated);
}
@@ -16,6 +18,11 @@ package com.android.server.compat.overrides {
method public java.util.List<com.android.server.compat.overrides.OverrideValue> getOverrideValue();
}
+ public static class ChangeOverrides.Raw {
+ ctor public ChangeOverrides.Raw();
+ method public java.util.List<com.android.server.compat.overrides.RawOverrideValue> getRawOverrideValue();
+ }
+
public static class ChangeOverrides.Validated {
ctor public ChangeOverrides.Validated();
method public java.util.List<com.android.server.compat.overrides.OverrideValue> getOverrideValue();
@@ -34,6 +41,18 @@ package com.android.server.compat.overrides {
method public java.util.List<com.android.server.compat.overrides.ChangeOverrides> getChangeOverrides();
}
+ public class RawOverrideValue {
+ ctor public RawOverrideValue();
+ method public boolean getEnabled();
+ method public long getMaxVersionCode();
+ method public long getMinVersionCode();
+ method public String getPackageName();
+ method public void setEnabled(boolean);
+ method public void setMaxVersionCode(long);
+ method public void setMinVersionCode(long);
+ method public void setPackageName(String);
+ }
+
public class XmlParser {
ctor public XmlParser();
method public static com.android.server.compat.overrides.Overrides read(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 43537d067bce..7565fe103b1e 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -7158,7 +7158,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
final int userId = mInjector.userHandleGetCallingUserId();
return mInjector.binderWithCleanCallingIdentity(
- () -> mInjector.getConnectivityManager().getVpnLockdownWhitelist(userId));
+ () -> mInjector.getConnectivityManager().getVpnLockdownAllowlist(userId));
}
private void forceWipeDeviceNoLock(boolean wipeExtRequested, String reason, boolean wipeEuicc) {
diff --git a/services/java/com/android/server/SystemConfigService.java b/services/java/com/android/server/SystemConfigService.java
index 1801f3bca30e..a2768c637d79 100644
--- a/services/java/com/android/server/SystemConfigService.java
+++ b/services/java/com/android/server/SystemConfigService.java
@@ -21,6 +21,10 @@ import static java.util.stream.Collectors.toMap;
import android.Manifest;
import android.content.Context;
import android.os.ISystemConfig;
+import android.util.ArraySet;
+import android.util.SparseArray;
+
+import com.android.internal.util.ArrayUtils;
import java.util.ArrayList;
import java.util.List;
@@ -64,6 +68,22 @@ public class SystemConfigService extends SystemService {
return SystemConfig.getInstance()
.getDisabledUntilUsedPreinstalledCarrierAssociatedApps();
}
+
+ @Override
+ public int[] getSystemPermissionUids(String permissionName) {
+ mContext.enforceCallingOrSelfPermission(Manifest.permission.GET_RUNTIME_PERMISSIONS,
+ "getSystemPermissionUids requires GET_RUNTIME_PERMISSIONS");
+ final List<Integer> uids = new ArrayList<>();
+ final SparseArray<ArraySet<String>> systemPermissions =
+ SystemConfig.getInstance().getSystemPermissions();
+ for (int i = 0; i < systemPermissions.size(); i++) {
+ final ArraySet<String> permissions = systemPermissions.valueAt(i);
+ if (permissions != null && permissions.contains(permissionName)) {
+ uids.add(systemPermissions.keyAt(i));
+ }
+ }
+ return ArrayUtils.convertToIntArray(uids);
+ }
};
public SystemConfigService(Context context) {
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 62c3f43d2676..c665ca32bff0 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -1104,6 +1104,7 @@ public final class SystemServer {
IStorageManager storageManager = null;
NetworkManagementService networkManagement = null;
IpSecService ipSecService = null;
+ VpnManagerService vpnManager = null;
VcnManagementService vcnManagement = null;
NetworkStatsService networkStats = null;
NetworkPolicyManagerService networkPolicy = null;
@@ -1637,6 +1638,15 @@ public final class SystemServer {
networkPolicy.bindConnectivityManager(connectivity);
t.traceEnd();
+ t.traceBegin("StartVpnManagerService");
+ try {
+ vpnManager = VpnManagerService.create(context);
+ ServiceManager.addService(Context.VPN_MANAGEMENT_SERVICE, vpnManager);
+ } catch (Throwable e) {
+ reportWtf("starting VPN Manager Service", e);
+ }
+ t.traceEnd();
+
t.traceBegin("StartVcnManagementService");
try {
vcnManagement = VcnManagementService.create(context);
@@ -2338,6 +2348,7 @@ public final class SystemServer {
final MediaRouterService mediaRouterF = mediaRouter;
final MmsServiceBroker mmsServiceF = mmsService;
final IpSecService ipSecServiceF = ipSecService;
+ final VpnManagerService vpnManagerF = vpnManager;
final VcnManagementService vcnManagementF = vcnManagement;
final WindowManagerService windowManagerF = wm;
final ConnectivityManager connectivityF = (ConnectivityManager)
@@ -2445,6 +2456,15 @@ public final class SystemServer {
reportWtf("making Connectivity Service ready", e);
}
t.traceEnd();
+ t.traceBegin("MakeVpnManagerServiceReady");
+ try {
+ if (vpnManagerF != null) {
+ vpnManagerF.systemReady();
+ }
+ } catch (Throwable e) {
+ reportWtf("making VpnManagerService ready", e);
+ }
+ t.traceEnd();
t.traceBegin("MakeVcnManagementServiceReady");
try {
if (vcnManagementF != null) {
diff --git a/services/tests/servicestests/src/com/android/server/EntropyMixerTest.java b/services/tests/servicestests/src/com/android/server/EntropyMixerTest.java
index 50e7a0395a2a..58d6dae1637a 100644
--- a/services/tests/servicestests/src/com/android/server/EntropyMixerTest.java
+++ b/services/tests/servicestests/src/com/android/server/EntropyMixerTest.java
@@ -34,7 +34,7 @@ public class EntropyMixerTest extends AndroidTestCase {
assertEquals(0, FileUtils.readTextFile(file, 0, null).length());
// The constructor has the side effect of writing to file
- new EntropyMixer(getContext(), "/dev/null", file.getCanonicalPath(), "/dev/null");
+ new EntropyMixer(getContext(), "/dev/null", file.getCanonicalPath());
assertTrue(FileUtils.readTextFile(file, 0, null).length() > 0);
}
diff --git a/services/tests/servicestests/src/com/android/server/compat/ApplicationInfoBuilder.java b/services/tests/servicestests/src/com/android/server/compat/ApplicationInfoBuilder.java
index d0767ccb6f87..c165c661a625 100644
--- a/services/tests/servicestests/src/com/android/server/compat/ApplicationInfoBuilder.java
+++ b/services/tests/servicestests/src/com/android/server/compat/ApplicationInfoBuilder.java
@@ -22,6 +22,7 @@ class ApplicationInfoBuilder {
private boolean mIsDebuggable;
private int mTargetSdk;
private String mPackageName;
+ private long mVersionCode;
private ApplicationInfoBuilder() {
mTargetSdk = -1;
@@ -46,6 +47,11 @@ class ApplicationInfoBuilder {
return this;
}
+ ApplicationInfoBuilder withVersionCode(Long versionCode) {
+ mVersionCode = versionCode;
+ return this;
+ }
+
ApplicationInfo build() {
final ApplicationInfo applicationInfo = new ApplicationInfo();
if (mIsDebuggable) {
@@ -53,6 +59,7 @@ class ApplicationInfoBuilder {
}
applicationInfo.packageName = mPackageName;
applicationInfo.targetSdkVersion = mTargetSdk;
+ applicationInfo.longVersionCode = mVersionCode;
return applicationInfo;
}
}
diff --git a/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java b/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
index a53ff9bc7fdc..8b0e948579fb 100644
--- a/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
@@ -18,6 +18,7 @@ package com.android.server.compat;
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
@@ -25,6 +26,7 @@ import static org.mockito.Mockito.when;
import static org.testng.Assert.assertThrows;
import android.app.compat.ChangeIdStateCache;
+import android.app.compat.PackageOverride;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
@@ -33,6 +35,7 @@ import android.content.pm.PackageManager.NameNotFoundException;
import androidx.test.runner.AndroidJUnit4;
import com.android.internal.compat.AndroidBuildClassifier;
+import com.android.internal.compat.CompatibilityOverrideConfig;
import org.junit.Before;
import org.junit.Test;
@@ -46,6 +49,7 @@ import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
+import java.util.Collections;
import java.util.UUID;
@RunWith(AndroidJUnit4.class)
@@ -83,6 +87,8 @@ public class CompatConfigTest {
when(mBuildClassifier.isDebuggableBuild()).thenReturn(true);
when(mBuildClassifier.isFinalBuild()).thenReturn(false);
ChangeIdStateCache.disable();
+ when(mPackageManager.getApplicationInfo(anyString(), anyInt()))
+ .thenThrow(new NameNotFoundException());
}
@Test
@@ -163,6 +169,10 @@ public class CompatConfigTest {
CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
.addDisabledChangeWithId(1234L)
.build();
+ ApplicationInfo info = ApplicationInfoBuilder.create()
+ .withPackageName("com.some.package").build();
+ when(mPackageManager.getApplicationInfo(eq("com.some.package"), anyInt()))
+ .thenReturn(info);
compatConfig.addOverride(1234L, "com.some.package", true);
@@ -177,6 +187,10 @@ public class CompatConfigTest {
CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
.addEnabledChangeWithId(1234L)
.build();
+ ApplicationInfo info = ApplicationInfoBuilder.create()
+ .withPackageName("com.some.package").build();
+ when(mPackageManager.getApplicationInfo(eq("com.some.package"), anyInt()))
+ .thenReturn(info);
compatConfig.addOverride(1234L, "com.some.package", false);
@@ -191,6 +205,10 @@ public class CompatConfigTest {
CompatConfig compatConfig = new CompatConfig(mBuildClassifier, mContext);
compatConfig.forceNonDebuggableFinalForTest(false);
+ ApplicationInfo info = ApplicationInfoBuilder.create()
+ .withPackageName("com.some.package").build();
+ when(mPackageManager.getApplicationInfo(eq("com.some.package"), anyInt()))
+ .thenReturn(info);
compatConfig.addOverride(1234L, "com.some.package", false);
@@ -265,6 +283,71 @@ public class CompatConfigTest {
}
@Test
+ public void testOverrideWithAppVersion() throws Exception {
+ ApplicationInfo applicationInfo = ApplicationInfoBuilder.create()
+ .withPackageName("com.installed.foo")
+ .withVersionCode(100L)
+ .debuggable().build();
+ when(mPackageManager.getApplicationInfo(eq("com.installed.foo"), anyInt()))
+ .thenReturn(applicationInfo);
+ CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
+ .addDisabledChangeWithId(1234L).build();
+ when(mBuildClassifier.isDebuggableBuild()).thenReturn(false);
+ when(mBuildClassifier.isFinalBuild()).thenReturn(true);
+
+ // Add override that doesn't include the installed app version
+ CompatibilityOverrideConfig config = new CompatibilityOverrideConfig(
+ Collections.singletonMap(1234L,
+ new PackageOverride.Builder()
+ .setMaxVersionCode(99L)
+ .setEnabled(true)
+ .build()));
+ compatConfig.addOverrides(config, "com.installed.foo");
+ assertThat(compatConfig.isChangeEnabled(1234L, applicationInfo)).isFalse();
+
+ // Add override that does include the installed app version
+ config = new CompatibilityOverrideConfig(
+ Collections.singletonMap(1234L,
+ new PackageOverride.Builder()
+ .setMinVersionCode(100L)
+ .setMaxVersionCode(100L)
+ .setEnabled(true)
+ .build()));
+ compatConfig.addOverrides(config, "com.installed.foo");
+ assertThat(compatConfig.isChangeEnabled(1234L, applicationInfo)).isTrue();
+ }
+
+ @Test
+ public void testApplyDeferredOverridesAfterInstallingAppVersion() throws Exception {
+ ApplicationInfo applicationInfo = ApplicationInfoBuilder.create()
+ .withPackageName("com.notinstalled.foo")
+ .withVersionCode(100L)
+ .debuggable().build();
+ when(mPackageManager.getApplicationInfo(eq("com.notinstalled.foo"), anyInt()))
+ .thenThrow(new NameNotFoundException());
+ CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
+ .addDisabledChangeWithId(1234L).build();
+ when(mBuildClassifier.isDebuggableBuild()).thenReturn(false);
+ when(mBuildClassifier.isFinalBuild()).thenReturn(true);
+
+ // Add override before the app is available.
+ CompatibilityOverrideConfig config = new CompatibilityOverrideConfig(
+ Collections.singletonMap(1234L, new PackageOverride.Builder()
+ .setMaxVersionCode(99L)
+ .setEnabled(true)
+ .build()));
+ compatConfig.addOverrides(config, "com.notinstalled.foo");
+ assertThat(compatConfig.isChangeEnabled(1234L, applicationInfo)).isFalse();
+
+ // Pretend the app is now installed.
+ when(mPackageManager.getApplicationInfo(eq("com.notinstalled.foo"), anyInt()))
+ .thenReturn(applicationInfo);
+
+ compatConfig.recheckOverrides("com.notinstalled.foo");
+ assertThat(compatConfig.isChangeEnabled(1234L, applicationInfo)).isFalse();
+ }
+
+ @Test
public void testApplyDeferredOverrideClearsOverrideAfterUninstall() throws Exception {
ApplicationInfo applicationInfo = ApplicationInfoBuilder.create()
.withPackageName("com.installedapp.foo")
@@ -384,6 +467,8 @@ public class CompatConfigTest {
ApplicationInfo applicationInfo = ApplicationInfoBuilder.create()
.withPackageName("com.some.package")
.build();
+ when(mPackageManager.getApplicationInfo(eq("com.some.package"), anyInt()))
+ .thenReturn(applicationInfo);
assertThat(compatConfig.addOverride(1234L, "com.some.package", false)).isTrue();
assertThat(compatConfig.isChangeEnabled(1234L, applicationInfo)).isFalse();
@@ -404,6 +489,8 @@ public class CompatConfigTest {
.withPackageName("foo.bar")
.withTargetSdk(2)
.build();
+ when(mPackageManager.getApplicationInfo(eq("foo.bar"), anyInt()))
+ .thenReturn(applicationInfo);
assertThat(compatConfig.isChangeEnabled(3, applicationInfo)).isFalse();
assertThat(compatConfig.isChangeEnabled(4, applicationInfo)).isFalse();
@@ -425,7 +512,8 @@ public class CompatConfigTest {
.withPackageName("foo.bar")
.withTargetSdk(2)
.build();
-
+ when(mPackageManager.getApplicationInfo(eq("foo.bar"), anyInt()))
+ .thenReturn(applicationInfo);
assertThat(compatConfig.enableTargetSdkChangesForPackage("foo.bar", 3)).isEqualTo(1);
assertThat(compatConfig.isChangeEnabled(3, applicationInfo)).isTrue();
assertThat(compatConfig.isChangeEnabled(4, applicationInfo)).isFalse();
@@ -533,22 +621,114 @@ public class CompatConfigTest {
+ " <override-value packageName=\"foo.bar\" enabled=\"true\">\n"
+ " </override-value>\n"
+ " </validated>\n"
- + " <deferred>\n"
- + " </deferred>\n"
+ + " <raw>\n"
+ + " <raw-override-value packageName=\"foo.bar\" "
+ + "minVersionCode=\"-9223372036854775808\" "
+ + "maxVersionCode=\"9223372036854775807\" enabled=\"true\">\n"
+ + " </raw-override-value>\n"
+ + " </raw>\n"
+ " </change-overrides>\n"
+ " <change-overrides changeId=\"2\">\n"
+ " <validated>\n"
+ " </validated>\n"
- + " <deferred>\n"
- + " <override-value packageName=\"bar.baz\" enabled=\"false\">\n"
- + " </override-value>\n"
- + " </deferred>\n"
+ + " <raw>\n"
+ + " <raw-override-value packageName=\"bar.baz\" "
+ + "minVersionCode=\"-9223372036854775808\" "
+ + "maxVersionCode=\"9223372036854775807\" enabled=\"false\">\n"
+ + " </raw-override-value>\n"
+ + " </raw>\n"
+ + " </change-overrides>\n"
+ + "</overrides>\n");
+ }
+
+ @Test
+ public void testSaveOverridesWithRanges() throws Exception {
+ File overridesFile = new File(createTempDir(), "overrides.xml");
+ CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
+ .addDisabledChangeWithId(1L)
+ .addEnableSinceSdkChangeWithId(2, 2L)
+ .build();
+ compatConfig.forceNonDebuggableFinalForTest(true);
+ compatConfig.initOverrides(overridesFile);
+
+ compatConfig.addOverrides(new CompatibilityOverrideConfig(Collections.singletonMap(1L,
+ new PackageOverride.Builder()
+ .setMinVersionCode(99L)
+ .setMaxVersionCode(101L)
+ .setEnabled(true)
+ .build())), "foo.bar");
+
+ assertThat(readFile(overridesFile)).isEqualTo("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
+ + "<overrides>\n"
+ + " <change-overrides changeId=\"1\">\n"
+ + " <validated>\n"
+ + " </validated>\n"
+ + " <raw>\n"
+ + " <raw-override-value packageName=\"foo.bar\" "
+ + "minVersionCode=\"99\" maxVersionCode=\"101\" enabled=\"true\">\n"
+ + " </raw-override-value>\n"
+ + " </raw>\n"
+ " </change-overrides>\n"
+ "</overrides>\n");
}
@Test
- public void testLoadOverrides() throws Exception {
+ public void testLoadOverridesRaw() throws Exception {
+ File tempDir = createTempDir();
+ File overridesFile = new File(tempDir, "overrides.xml");
+ // Change 1 is enabled for foo.bar (validated)
+ // Change 2 is disabled for bar.baz (deferred)
+ String xmlData = "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
+ + "<overrides>\n"
+ + " <change-overrides changeId=\"1\">\n"
+ + " <validated>\n"
+ + " <override-value packageName=\"foo.bar\" enabled=\"true\">\n"
+ + " </override-value>\n"
+ + " </validated>\n"
+ + " <raw>\n"
+ + " <raw-override-value packageName=\"foo.bar\" "
+ + "minVersionCode=\"-9223372036854775808\" "
+ + "maxVersionCode=\"9223372036854775807\" enabled=\"true\">\n"
+ + " </raw-override-value>\n"
+ + " </raw>\n"
+ + " </change-overrides>\n"
+ + " <change-overrides changeId=\"2\">\n"
+ + " <validated>\n"
+ + " </validated>\n"
+ + " <raw>\n"
+ + " <raw-override-value packageName=\"bar.baz\" "
+ + "minVersionCode=\"-9223372036854775808\" "
+ + "maxVersionCode=\"9223372036854775807\" enabled=\"false\">\n"
+ + " </raw-override-value>\n"
+ + " </raw>\n"
+ + " </change-overrides>\n"
+ + "</overrides>\n";
+ writeToFile(tempDir, "overrides.xml", xmlData);
+ CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
+ .addDisabledChangeWithId(1L)
+ .addEnableSinceSdkChangeWithId(2, 2L)
+ .build();
+ compatConfig.forceNonDebuggableFinalForTest(true);
+ compatConfig.initOverrides(overridesFile);
+ ApplicationInfo applicationInfo = ApplicationInfoBuilder.create()
+ .withPackageName("foo.bar")
+ .withVersionCode(100L)
+ .debuggable()
+ .build();
+ when(mPackageManager.getApplicationInfo(eq("foo.bar"), anyInt()))
+ .thenReturn(applicationInfo);
+ when(mPackageManager.getApplicationInfo(eq("bar.baz"), anyInt()))
+ .thenThrow(new NameNotFoundException());
+
+ assertThat(compatConfig.isChangeEnabled(1L, applicationInfo)).isTrue();
+ assertThat(compatConfig.willChangeBeEnabled(2L, "bar.baz")).isFalse();
+
+ compatConfig.recheckOverrides("foo.bar");
+ assertThat(compatConfig.isChangeEnabled(1L, applicationInfo)).isTrue();
+ }
+
+ @Test
+ public void testLoadOverridesDeferred() throws Exception {
File tempDir = createTempDir();
File overridesFile = new File(tempDir, "overrides.xml");
// Change 1 is enabled for foo.bar (validated)
diff --git a/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java b/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java
index a1b2dc8bd82d..799b06734b54 100644
--- a/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java
+++ b/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java
@@ -196,6 +196,9 @@ public class PlatformCompatTest {
mPlatformCompat.registerListener(1, mListener1);
mPlatformCompat.registerListener(2, mListener1);
+ when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
+ .thenReturn(ApplicationInfoBuilder.create().withPackageName(PACKAGE_NAME).build());
+
mPlatformCompat.setOverrides(
CompatibilityChangeConfigBuilder.create().enable(1L).disable(2L).build(),
PACKAGE_NAME);
@@ -208,6 +211,9 @@ public class PlatformCompatTest {
mPlatformCompat.registerListener(1, mListener1);
mPlatformCompat.registerListener(2, mListener1);
+ when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
+ .thenReturn(ApplicationInfoBuilder.create().withPackageName(PACKAGE_NAME).build());
+
mPlatformCompat.setOverrides(
CompatibilityChangeConfigBuilder.create().enable(1L).disable(2L).build(),
PACKAGE_NAME);
@@ -219,6 +225,9 @@ public class PlatformCompatTest {
public void testListenerCalledOnSetOverridesTwoListeners() throws Exception {
mPlatformCompat.registerListener(1, mListener1);
+ when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
+ .thenReturn(ApplicationInfoBuilder.create().withPackageName(PACKAGE_NAME).build());
+
mPlatformCompat.setOverrides(
CompatibilityChangeConfigBuilder.create().enable(1L).disable(2L).build(),
PACKAGE_NAME);
@@ -244,6 +253,9 @@ public class PlatformCompatTest {
mPlatformCompat.registerListener(1, mListener1);
mPlatformCompat.registerListener(2, mListener1);
+ when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
+ .thenReturn(ApplicationInfoBuilder.create().withPackageName(PACKAGE_NAME).build());
+
mPlatformCompat.setOverrides(
CompatibilityChangeConfigBuilder.create().enable(1L).disable(2L).build(),
PACKAGE_NAME);
@@ -252,9 +264,12 @@ public class PlatformCompatTest {
}
@Test
- public void testListenerCalledOnSetOverridesTwoListenersForTest() throws Exception {
+ public void testListenerCalledOnSetOverridesForTestTwoListeners() throws Exception {
mPlatformCompat.registerListener(1, mListener1);
+ when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
+ .thenReturn(ApplicationInfoBuilder.create().withPackageName(PACKAGE_NAME).build());
+
mPlatformCompat.setOverrides(
CompatibilityChangeConfigBuilder.create().enable(1L).disable(2L).build(),
PACKAGE_NAME);
@@ -280,6 +295,9 @@ public class PlatformCompatTest {
mPlatformCompat.registerListener(1, mListener1);
mPlatformCompat.registerListener(2, mListener2);
+ when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
+ .thenReturn(ApplicationInfoBuilder.create().withPackageName(PACKAGE_NAME).build());
+
mPlatformCompat.setOverrides(
CompatibilityChangeConfigBuilder.create().enable(1L).build(),
PACKAGE_NAME);
@@ -299,6 +317,9 @@ public class PlatformCompatTest {
mPlatformCompat.registerListener(1, mListener1);
mPlatformCompat.registerListener(2, mListener2);
+ when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
+ .thenReturn(ApplicationInfoBuilder.create().withPackageName(PACKAGE_NAME).build());
+
mPlatformCompat.setOverrides(
CompatibilityChangeConfigBuilder.create().enable(1L).disable(2L).build(),
PACKAGE_NAME);
@@ -318,6 +339,9 @@ public class PlatformCompatTest {
mPlatformCompat.registerListener(1, mListener1);
mPlatformCompat.registerListener(2, mListener2);
+ when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
+ .thenReturn(ApplicationInfoBuilder.create().withPackageName(PACKAGE_NAME).build());
+
mPlatformCompat.setOverrides(
CompatibilityChangeConfigBuilder.create().enable(1L).build(),
PACKAGE_NAME);
@@ -336,6 +360,9 @@ public class PlatformCompatTest {
public void testListenerCalledOnClearOverrideDoesntExist() throws Exception {
mPlatformCompat.registerListener(1, mListener1);
+ when(mPackageManager.getApplicationInfo(eq(PACKAGE_NAME), anyInt()))
+ .thenReturn(ApplicationInfoBuilder.create().withPackageName(PACKAGE_NAME).build());
+
mPlatformCompat.clearOverride(1, PACKAGE_NAME);
// Listener not called when a non existing override is removed.
verify(mListener1, never()).onCompatChange(PACKAGE_NAME);
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsShellCommandTest.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsShellCommandTest.java
index 220569449ffb..336bbaeae2d9 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsShellCommandTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsShellCommandTest.java
@@ -42,6 +42,7 @@ import android.content.Context;
import android.os.Binder;
import android.os.Handler;
import android.os.Looper;
+import android.os.Process;
import android.os.ResultReceiver;
import android.os.ShellCallback;
import android.platform.test.annotations.Presubmit;
@@ -86,7 +87,8 @@ public class LockSettingsShellCommandTest {
MockitoAnnotations.initMocks(this);
final Context context = InstrumentationRegistry.getTargetContext();
mUserId = ActivityManager.getCurrentUser();
- mCommand = new LockSettingsShellCommand(mLockPatternUtils);
+ mCommand = new LockSettingsShellCommand(mLockPatternUtils, context, 0,
+ Process.SHELL_UID);
when(mLockPatternUtils.hasSecureLockScreen()).thenReturn(true);
}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowDataTest.java b/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowDataTest.java
index 32445fd1a47d..2eedc3251daa 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowDataTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowDataTest.java
@@ -19,19 +19,17 @@ package com.android.server.locksettings;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
-import android.security.keystore.KeyGenParameterSpec;
-import android.security.keystore.KeyProperties;
-
import androidx.test.runner.AndroidJUnit4;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import java.security.GeneralSecurityException;
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
-import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
+import javax.crypto.spec.SecretKeySpec;
/**
* atest FrameworksServicesTests:RebootEscrowDataTest
@@ -41,22 +39,18 @@ public class RebootEscrowDataTest {
private RebootEscrowKey mKey;
private SecretKey mKeyStoreEncryptionKey;
- private SecretKey generateNewRebootEscrowEncryptionKey() throws GeneralSecurityException {
- KeyGenerator generator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES);
- generator.init(new KeyGenParameterSpec.Builder(
- "reboot_escrow_data_test_key",
- KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
- .setKeySize(256)
- .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
- .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
- .build());
- return generator.generateKey();
- }
+ // Hex encoding of a randomly generated AES key for test.
+ private static final byte[] TEST_AES_KEY = new byte[] {
+ 0x44, 0x74, 0x61, 0x54, 0x29, 0x74, 0x37, 0x61,
+ 0x48, 0x19, 0x12, 0x54, 0x13, 0x13, 0x52, 0x31,
+ 0x70, 0x70, 0x75, 0x25, 0x27, 0x31, 0x49, 0x09,
+ 0x26, 0x52, 0x72, 0x63, 0x63, 0x61, 0x78, 0x23,
+ };
@Before
public void generateKey() throws Exception {
mKey = RebootEscrowKey.generate();
- mKeyStoreEncryptionKey = generateNewRebootEscrowEncryptionKey();
+ mKeyStoreEncryptionKey = new SecretKeySpec(TEST_AES_KEY, "AES");
}
private static byte[] getTestSp() {
@@ -114,4 +108,23 @@ public class RebootEscrowDataTest {
assertThat(decrypted, is(testSp));
}
+ @Test
+ public void fromEncryptedData_legacyVersion_success() throws Exception {
+ byte[] testSp = getTestSp();
+ byte[] ksEncryptedBlob = AesEncryptionUtil.encrypt(mKey.getKey(), testSp);
+
+ // Write a legacy blob encrypted only by k_s.
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ DataOutputStream dos = new DataOutputStream(bos);
+ dos.writeInt(1);
+ dos.writeByte(3);
+ dos.write(ksEncryptedBlob);
+ byte[] legacyBlob = bos.toByteArray();
+
+ RebootEscrowData actual = RebootEscrowData.fromEncryptedData(mKey, legacyBlob, null);
+
+ assertThat(actual.getSpVersion(), is((byte) 3));
+ assertThat(actual.getKey().getKeyBytes(), is(mKey.getKeyBytes()));
+ assertThat(actual.getSyntheticPassword(), is(testSp));
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java b/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java
index a4ba4c86a8fd..a896f1b0d60f 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java
@@ -43,6 +43,7 @@ import android.content.Context;
import android.content.ContextWrapper;
import android.content.pm.UserInfo;
import android.hardware.rebootescrow.IRebootEscrow;
+import android.os.Handler;
import android.os.RemoteException;
import android.os.ServiceSpecificException;
import android.os.UserManager;
@@ -155,6 +156,11 @@ public class RebootEscrowManagerTests {
}
@Override
+ void post(Handler handler, Runnable runnable) {
+ runnable.run();
+ }
+
+ @Override
public UserManager getUserManager() {
return mUserManager;
}
@@ -369,7 +375,7 @@ public class RebootEscrowManagerTests {
@Test
public void loadRebootEscrowDataIfAvailable_NothingAvailable_Success() throws Exception {
- mService.loadRebootEscrowDataIfAvailable();
+ mService.loadRebootEscrowDataIfAvailable(null);
}
@Test
@@ -401,7 +407,7 @@ public class RebootEscrowManagerTests {
doNothing().when(mInjected).reportMetric(metricsSuccessCaptor.capture());
when(mRebootEscrow.retrieveKey()).thenAnswer(invocation -> keyByteCaptor.getValue());
- mService.loadRebootEscrowDataIfAvailable();
+ mService.loadRebootEscrowDataIfAvailable(null);
verify(mRebootEscrow).retrieveKey();
assertTrue(metricsSuccessCaptor.getValue());
verify(mKeyStoreManager).clearKeyStoreEncryptionKey();
@@ -435,7 +441,7 @@ public class RebootEscrowManagerTests {
when(mServiceConnection.unwrap(any(), anyLong()))
.thenAnswer(invocation -> invocation.getArgument(0));
- mService.loadRebootEscrowDataIfAvailable();
+ mService.loadRebootEscrowDataIfAvailable(null);
verify(mServiceConnection).unwrap(any(), anyLong());
assertTrue(metricsSuccessCaptor.getValue());
verify(mKeyStoreManager).clearKeyStoreEncryptionKey();
@@ -466,7 +472,7 @@ public class RebootEscrowManagerTests {
when(mInjected.getBootCount()).thenReturn(10);
when(mRebootEscrow.retrieveKey()).thenReturn(new byte[32]);
- mService.loadRebootEscrowDataIfAvailable();
+ mService.loadRebootEscrowDataIfAvailable(null);
verify(mRebootEscrow).retrieveKey();
verify(mInjected, never()).reportMetric(anyBoolean());
}
@@ -493,7 +499,7 @@ public class RebootEscrowManagerTests {
when(mInjected.getBootCount()).thenReturn(10);
when(mRebootEscrow.retrieveKey()).thenReturn(new byte[32]);
- mService.loadRebootEscrowDataIfAvailable();
+ mService.loadRebootEscrowDataIfAvailable(null);
verify(mInjected, never()).reportMetric(anyBoolean());
}
@@ -527,7 +533,7 @@ public class RebootEscrowManagerTests {
when(mInjected.getBootCount()).thenReturn(10);
when(mRebootEscrow.retrieveKey()).thenAnswer(invocation -> keyByteCaptor.getValue());
- mService.loadRebootEscrowDataIfAvailable();
+ mService.loadRebootEscrowDataIfAvailable(null);
verify(mInjected).reportMetric(eq(true));
}
@@ -557,7 +563,7 @@ public class RebootEscrowManagerTests {
ArgumentCaptor<Boolean> metricsSuccessCaptor = ArgumentCaptor.forClass(Boolean.class);
doNothing().when(mInjected).reportMetric(metricsSuccessCaptor.capture());
when(mRebootEscrow.retrieveKey()).thenAnswer(invocation -> new byte[32]);
- mService.loadRebootEscrowDataIfAvailable();
+ mService.loadRebootEscrowDataIfAvailable(null);
verify(mRebootEscrow).retrieveKey();
assertFalse(metricsSuccessCaptor.getValue());
}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowProviderServerBasedImplTests.java b/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowProviderServerBasedImplTests.java
index bc1e025dd99f..28b737b412d2 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowProviderServerBasedImplTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowProviderServerBasedImplTests.java
@@ -30,6 +30,7 @@ import static org.mockito.Mockito.when;
import android.content.Context;
import android.content.ContextWrapper;
+import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
import androidx.test.InstrumentationRegistry;
@@ -42,7 +43,6 @@ import org.junit.runner.RunWith;
import org.mockito.stubbing.Answer;
import java.io.File;
-import java.io.IOException;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
@@ -130,7 +130,7 @@ public class RebootEscrowProviderServerBasedImplTests {
@Test
public void getAndClearRebootEscrowKey_ServiceConnectionException_failure() throws Exception {
when(mServiceConnection.wrapBlob(any(), anyLong(), anyLong())).thenAnswer(mFakeEncryption);
- doThrow(IOException.class).when(mServiceConnection).unwrap(any(), anyLong());
+ doThrow(RemoteException.class).when(mServiceConnection).unwrap(any(), anyLong());
assertTrue(mRebootEscrowProvider.hasRebootEscrowSupport());
mRebootEscrowProvider.storeRebootEscrowKey(mRebootEscrowKey, mKeyStoreEncryptionKey);
diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexoptOptionsTests.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexoptOptionsTests.java
index 22020ad45666..bc84e350a329 100644
--- a/services/tests/servicestests/src/com/android/server/pm/dex/DexoptOptionsTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexoptOptionsTests.java
@@ -96,7 +96,7 @@ public class DexoptOptionsTests {
int[] reasons = new int[] {
PackageManagerService.REASON_FIRST_BOOT,
- PackageManagerService.REASON_BOOT,
+ PackageManagerService.REASON_POST_BOOT,
PackageManagerService.REASON_INSTALL,
PackageManagerService.REASON_BACKGROUND_DEXOPT,
PackageManagerService.REASON_AB_OTA,
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/library/AndroidNetIpSecIkeUpdaterTest.java b/services/tests/servicestests/src/com/android/server/pm/parsing/library/AndroidNetIpSecIkeUpdaterTest.java
new file mode 100644
index 000000000000..70d85b6e0411
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/library/AndroidNetIpSecIkeUpdaterTest.java
@@ -0,0 +1,90 @@
+/*
+ * 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 com.android.server.pm.parsing.library;
+
+import android.os.Build;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.server.pm.parsing.pkg.AndroidPackage;
+import com.android.server.pm.parsing.pkg.PackageImpl;
+import com.android.server.pm.parsing.pkg.ParsedPackage;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Test for {@link AndroidNetIpSecIkeUpdater}
+ */
+@Presubmit
+@SmallTest
+@RunWith(JUnit4.class)
+public class AndroidNetIpSecIkeUpdaterTest extends PackageSharedLibraryUpdaterTest {
+
+ @Test
+ public void otherUsesLibraries() {
+ ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.O)
+ .addUsesLibrary("other")
+ .addUsesOptionalLibrary("optional")
+ .addUsesLibrary("android.net.ipsec.ike")
+ .hideAsParsed());
+ AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.O)
+ .addUsesLibrary("other")
+ .addUsesOptionalLibrary("optional")
+ .hideAsParsed())
+ .hideAsFinal();
+ checkBackwardsCompatibility(before, after);
+ }
+
+ @Test
+ public void in_usesLibraries() {
+ ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+ .addUsesLibrary("android.net.ipsec.ike")
+ .hideAsParsed());
+
+ AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+ .hideAsParsed())
+ .hideAsFinal();
+
+ checkBackwardsCompatibility(before, after);
+ }
+
+ @Test
+ public void in_usesOptionalLibraries() {
+ ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+ .addUsesOptionalLibrary("android.net.ipsec.ike")
+ .hideAsParsed());
+
+ AndroidPackage after = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+ .hideAsParsed())
+ .hideAsFinal();
+
+ checkBackwardsCompatibility(before, after);
+ }
+
+ private void checkBackwardsCompatibility(ParsedPackage before, AndroidPackage after) {
+ checkBackwardsCompatibility(before, after, AndroidNetIpSecIkeUpdater::new);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/pm/parsing/library/PackageBackwardCompatibilityTest.java b/services/tests/servicestests/src/com/android/server/pm/parsing/library/PackageBackwardCompatibilityTest.java
index 09c8142105cc..9768f176ea85 100644
--- a/services/tests/servicestests/src/com/android/server/pm/parsing/library/PackageBackwardCompatibilityTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/parsing/library/PackageBackwardCompatibilityTest.java
@@ -165,6 +165,23 @@ public class PackageBackwardCompatibilityTest extends PackageSharedLibraryUpdate
checkBackwardsCompatibility(before, ((ParsedPackage) after.hideAsParsed()).hideAsFinal());
}
+ /**
+ * Ensures that the {@link PackageBackwardCompatibility} uses a
+ * {@link AndroidNetIpSecIkeUpdater}.
+ */
+ @Test
+ public void android_net_ipsec_ike_in_usesLibraries() {
+ ParsedPackage before = ((ParsedPackage) PackageImpl.forTesting(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT)
+ .addUsesLibrary("android.net.ipsec.ike")
+ .hideAsParsed());
+
+ ParsingPackage after = PackageImpl.forTesting(PACKAGE_NAME)
+ .setTargetSdkVersion(Build.VERSION_CODES.CUR_DEVELOPMENT);
+
+ checkBackwardsCompatibility(before, ((ParsedPackage) after.hideAsParsed()).hideAsFinal());
+ }
+
private void checkBackwardsCompatibility(ParsedPackage before, AndroidPackage after) {
checkBackwardsCompatibility(before, after, PackageBackwardCompatibility::getInstance);
}
diff --git a/services/tests/servicestests/test-apps/ConnTestApp/OWNERS b/services/tests/servicestests/test-apps/ConnTestApp/OWNERS
new file mode 100644
index 000000000000..aa87958f1d53
--- /dev/null
+++ b/services/tests/servicestests/test-apps/ConnTestApp/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/net/OWNERS
diff --git a/services/usb/OWNERS b/services/usb/OWNERS
index 8ee72b577f3c..60172a36128e 100644
--- a/services/usb/OWNERS
+++ b/services/usb/OWNERS
@@ -1,6 +1,5 @@
badhri@google.com
elaurent@google.com
-moltmann@google.com
albertccwang@google.com
jameswei@google.com
howardyen@google.com \ No newline at end of file
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index a4ecb722bd2c..580513c12453 100755
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -1992,7 +1992,7 @@ public abstract class ConnectionService extends Service {
boolean isHandover = request.getExtras() != null && request.getExtras().getBoolean(
TelecomManager.EXTRA_IS_HANDOVER_CONNECTION, false);
boolean addSelfManaged = request.getExtras() != null && request.getExtras().getBoolean(
- PhoneAccount.EXTRA_ADD_SELF_MANAGED_CALLS_TO_INCALLSERVICE, false);
+ PhoneAccount.EXTRA_ADD_SELF_MANAGED_CALLS_TO_INCALLSERVICE, true);
Log.i(this, "createConnection, callManagerAccount: %s, callId: %s, request: %s, "
+ "isIncoming: %b, isUnknown: %b, isLegacyHandover: %b, isHandover: %b, "
+ " addSelfManaged: %b", callManagerAccount, callId, request, isIncoming,
diff --git a/telephony/java/android/telephony/data/IQualifiedNetworksService.aidl b/telephony/java/android/telephony/data/IQualifiedNetworksService.aidl
index 2904082616e7..ba2b62d14bec 100644
--- a/telephony/java/android/telephony/data/IQualifiedNetworksService.aidl
+++ b/telephony/java/android/telephony/data/IQualifiedNetworksService.aidl
@@ -17,7 +17,7 @@
package android.telephony.data;
import android.telephony.data.IQualifiedNetworksServiceCallback;
-import android.telephony.data.ApnThrottleStatus;
+import android.telephony.data.ThrottleStatus;
/**
* {@hide}
@@ -26,5 +26,5 @@ interface IQualifiedNetworksService
{
oneway void createNetworkAvailabilityProvider(int slotId, IQualifiedNetworksServiceCallback callback);
oneway void removeNetworkAvailabilityProvider(int slotId);
- oneway void reportApnThrottleStatusChanged(int slotId, in List<ApnThrottleStatus> statuses);
+ oneway void reportThrottleStatusChanged(int slotId, in List<ThrottleStatus> statuses);
}
diff --git a/telephony/java/android/telephony/data/QualifiedNetworksService.java b/telephony/java/android/telephony/data/QualifiedNetworksService.java
index 4af63b4cf981..4e85d8926f11 100644
--- a/telephony/java/android/telephony/data/QualifiedNetworksService.java
+++ b/telephony/java/android/telephony/data/QualifiedNetworksService.java
@@ -168,8 +168,8 @@ public abstract class QualifiedNetworksService extends Service {
*
* @param statuses the statuses that have changed
*/
- public void reportApnThrottleStatusChanged(@NonNull List<ApnThrottleStatus> statuses) {
- Log.d(TAG, "reportApnThrottleStatusChanged: statuses size=" + statuses.size());
+ public void reportThrottleStatusChanged(@NonNull List<ThrottleStatus> statuses) {
+ Log.d(TAG, "reportThrottleStatusChanged: statuses size=" + statuses.size());
}
/**
@@ -212,8 +212,8 @@ public abstract class QualifiedNetworksService extends Service {
break;
case QNS_APN_THROTTLE_STATUS_CHANGED:
if (provider != null) {
- List<ApnThrottleStatus> statuses = (List<ApnThrottleStatus>) message.obj;
- provider.reportApnThrottleStatusChanged(statuses);
+ List<ThrottleStatus> statuses = (List<ThrottleStatus>) message.obj;
+ provider.reportThrottleStatusChanged(statuses);
}
break;
@@ -307,8 +307,8 @@ public abstract class QualifiedNetworksService extends Service {
}
@Override
- public void reportApnThrottleStatusChanged(int slotIndex,
- List<ApnThrottleStatus> statuses) {
+ public void reportThrottleStatusChanged(int slotIndex,
+ List<ThrottleStatus> statuses) {
mHandler.obtainMessage(QNS_APN_THROTTLE_STATUS_CHANGED, slotIndex, 0, statuses)
.sendToTarget();
}
diff --git a/telephony/java/android/telephony/data/ApnThrottleStatus.aidl b/telephony/java/android/telephony/data/ThrottleStatus.aidl
index 46bc4abde159..f75f35709816 100644
--- a/telephony/java/android/telephony/data/ApnThrottleStatus.aidl
+++ b/telephony/java/android/telephony/data/ThrottleStatus.aidl
@@ -17,4 +17,4 @@
/** @hide */
package android.telephony.data;
-parcelable ApnThrottleStatus;
+parcelable ThrottleStatus;
diff --git a/telephony/java/android/telephony/data/ApnThrottleStatus.java b/telephony/java/android/telephony/data/ThrottleStatus.java
index 51461d17690a..0335c6868340 100644
--- a/telephony/java/android/telephony/data/ApnThrottleStatus.java
+++ b/telephony/java/android/telephony/data/ThrottleStatus.java
@@ -35,7 +35,7 @@ import java.util.Objects;
* @hide
*/
@SystemApi
-public final class ApnThrottleStatus implements Parcelable {
+public final class ThrottleStatus implements Parcelable {
/**
* The APN type is not throttled.
*/
@@ -43,14 +43,14 @@ public final class ApnThrottleStatus implements Parcelable {
/**
* The APN type is throttled until {@link android.os.SystemClock#elapsedRealtime()}
- * has reached {@link ApnThrottleStatus#getThrottleExpiryTimeMillis}
+ * has reached {@link ThrottleStatus#getThrottleExpiryTimeMillis}
*/
public static final int THROTTLE_TYPE_ELAPSED_TIME = 2;
/** {@hide} */
@IntDef(flag = true, prefix = {"THROTTLE_TYPE_"}, value = {
- ApnThrottleStatus.THROTTLE_TYPE_NONE,
- ApnThrottleStatus.THROTTLE_TYPE_ELAPSED_TIME,
+ ThrottleStatus.THROTTLE_TYPE_NONE,
+ ThrottleStatus.THROTTLE_TYPE_ELAPSED_TIME,
})
public @interface ThrottleType {
}
@@ -72,9 +72,9 @@ public final class ApnThrottleStatus implements Parcelable {
/** {@hide} */
@IntDef(flag = true, prefix = {"RETRY_TYPE_"}, value = {
- ApnThrottleStatus.RETRY_TYPE_NONE,
- ApnThrottleStatus.RETRY_TYPE_NEW_CONNECTION,
- ApnThrottleStatus.RETRY_TYPE_HANDOVER,
+ ThrottleStatus.RETRY_TYPE_NONE,
+ ThrottleStatus.RETRY_TYPE_NEW_CONNECTION,
+ ThrottleStatus.RETRY_TYPE_HANDOVER,
})
public @interface RetryType {
}
@@ -141,7 +141,7 @@ public final class ApnThrottleStatus implements Parcelable {
* {@link SystemClock#elapsedRealtime}.
*
* This value only applies when the throttle type is set to
- * {@link ApnThrottleStatus#THROTTLE_TYPE_ELAPSED_TIME}.
+ * {@link ThrottleStatus#THROTTLE_TYPE_ELAPSED_TIME}.
*
* A value of {@link Long#MAX_VALUE} implies that the APN type is throttled indefinitely.
*
@@ -152,7 +152,7 @@ public final class ApnThrottleStatus implements Parcelable {
return mThrottleExpiryTimeMillis;
}
- private ApnThrottleStatus(int slotIndex,
+ private ThrottleStatus(int slotIndex,
@AccessNetworkConstants.TransportType int transportType,
@Annotation.ApnType int apnTypes,
@ThrottleType int throttleType,
@@ -166,7 +166,7 @@ public final class ApnThrottleStatus implements Parcelable {
mRetryType = retryType;
}
- private ApnThrottleStatus(@NonNull Parcel source) {
+ private ThrottleStatus(@NonNull Parcel source) {
mSlotIndex = source.readInt();
mTransportType = source.readInt();
mApnType = source.readInt();
@@ -185,16 +185,16 @@ public final class ApnThrottleStatus implements Parcelable {
dest.writeInt(mThrottleType);
}
- public static final @NonNull Parcelable.Creator<ApnThrottleStatus> CREATOR =
- new Parcelable.Creator<ApnThrottleStatus>() {
+ public static final @NonNull Parcelable.Creator<ThrottleStatus> CREATOR =
+ new Parcelable.Creator<ThrottleStatus>() {
@Override
- public ApnThrottleStatus createFromParcel(@NonNull Parcel source) {
- return new ApnThrottleStatus(source);
+ public ThrottleStatus createFromParcel(@NonNull Parcel source) {
+ return new ThrottleStatus(source);
}
@Override
- public ApnThrottleStatus[] newArray(int size) {
- return new ApnThrottleStatus[size];
+ public ThrottleStatus[] newArray(int size) {
+ return new ThrottleStatus[size];
}
};
@@ -213,8 +213,8 @@ public final class ApnThrottleStatus implements Parcelable {
public boolean equals(Object obj) {
if (obj == null) {
return false;
- } else if (obj instanceof ApnThrottleStatus) {
- ApnThrottleStatus other = (ApnThrottleStatus) obj;
+ } else if (obj instanceof ThrottleStatus) {
+ ThrottleStatus other = (ThrottleStatus) obj;
return this.mSlotIndex == other.mSlotIndex
&& this.mApnType == other.mApnType
&& this.mRetryType == other.mRetryType
@@ -228,7 +228,7 @@ public final class ApnThrottleStatus implements Parcelable {
@Override
public String toString() {
- return "ApnThrottleStatus{"
+ return "ThrottleStatus{"
+ "mSlotIndex=" + mSlotIndex
+ ", mTransportType=" + mTransportType
+ ", mApnType=" + ApnSetting.getApnTypeString(mApnType)
@@ -239,18 +239,18 @@ public final class ApnThrottleStatus implements Parcelable {
}
/**
- * Provides a convenient way to set the fields of an {@link ApnThrottleStatus} when creating a
+ * Provides a convenient way to set the fields of an {@link ThrottleStatus} when creating a
* new instance.
*
- * <p>The example below shows how you might create a new {@code ApnThrottleStatus}:
+ * <p>The example below shows how you might create a new {@code ThrottleStatus}:
*
* <pre><code>
*
- * DataCallResponseApnThrottleStatus = new ApnThrottleStatus.Builder()
+ * ThrottleStatus = new ThrottleStatus.Builder()
* .setSlotIndex(1)
* .setApnType({@link ApnSetting#TYPE_EMERGENCY})
* .setNoThrottle()
- * .setRetryType({@link ApnThrottleStatus#RETRY_TYPE_NEW_CONNECTION})
+ * .setRetryType({@link ThrottleStatus#RETRY_TYPE_NEW_CONNECTION})
* .build();
* </code></pre>
*/
@@ -261,6 +261,10 @@ public final class ApnThrottleStatus implements Parcelable {
private long mThrottleExpiryTimeMillis;
private @RetryType int mRetryType;
private @ThrottleType int mThrottleType;
+
+ /**
+ * @hide
+ */
public static final long NO_THROTTLE_EXPIRY_TIME =
DataCallResponse.RETRY_DURATION_UNDEFINED;
@@ -312,7 +316,7 @@ public final class ApnThrottleStatus implements Parcelable {
* {@link SystemClock#elapsedRealtime}.
*
* When setting this value, the throttle type is set to
- * {@link ApnThrottleStatus#THROTTLE_TYPE_ELAPSED_TIME}.
+ * {@link ThrottleStatus#THROTTLE_TYPE_ELAPSED_TIME}.
*
* A value of {@link Long#MAX_VALUE} implies that the APN type is throttled indefinitely.
*
@@ -338,7 +342,7 @@ public final class ApnThrottleStatus implements Parcelable {
* Sets the status of the APN type as not being throttled.
*
* When setting this value, the throttle type is set to
- * {@link ApnThrottleStatus#THROTTLE_TYPE_NONE} and the expiry time is set to
+ * {@link ThrottleStatus#THROTTLE_TYPE_NONE} and the expiry time is set to
* {@link Builder#NO_THROTTLE_EXPIRY_TIME}.
*
* @return The same instance of the builder.
@@ -365,13 +369,13 @@ public final class ApnThrottleStatus implements Parcelable {
}
/**
- * Build the {@link ApnThrottleStatus}
+ * Build the {@link ThrottleStatus}
*
- * @return the {@link ApnThrottleStatus} object
+ * @return the {@link ThrottleStatus} object
*/
@NonNull
- public ApnThrottleStatus build() {
- return new ApnThrottleStatus(
+ public ThrottleStatus build() {
+ return new ThrottleStatus(
mSlotIndex,
mTransportType,
mApnType,
diff --git a/telephony/java/android/telephony/ims/ImsRcsManager.java b/telephony/java/android/telephony/ims/ImsRcsManager.java
index bd623e055743..5f4e1e6f3148 100644
--- a/telephony/java/android/telephony/ims/ImsRcsManager.java
+++ b/telephony/java/android/telephony/ims/ImsRcsManager.java
@@ -21,6 +21,7 @@ import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
+import android.annotation.SystemApi;
import android.content.Context;
import android.content.Intent;
import android.os.Binder;
@@ -39,6 +40,8 @@ import android.util.Log;
import com.android.internal.telephony.IIntegerConsumer;
+import java.util.HashMap;
+import java.util.Map;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
@@ -77,31 +80,49 @@ public class ImsRcsManager {
"android.telephony.ims.action.SHOW_CAPABILITY_DISCOVERY_OPT_IN";
/**
- * Receives RCS Feature availability status updates from the ImsService.
- *
- * @see #isAvailable(int)
- * @see #registerRcsAvailabilityCallback(Executor, AvailabilityCallback)
- * @see #unregisterRcsAvailabilityCallback(AvailabilityCallback)
+ * An application can use {@link #addOnAvailabilityChangedListener} to register a
+ * {@link OnAvailabilityChangedListener}, which will notify the user when the RCS feature
+ * availability status updates from the ImsService.
* @hide
*/
- public static class AvailabilityCallback {
+ @SystemApi
+ public interface OnAvailabilityChangedListener {
+ /**
+ * The availability of the feature's capabilities has changed to either available or
+ * unavailable.
+ * <p>
+ * If unavailable, the feature does not support the capability at the current time. This may
+ * be due to network or subscription provisioning changes, such as the IMS registration
+ * being lost, network type changing, or OMA-DM provisioning updates.
+ *
+ * @param capabilities The new availability of the capabilities.
+ */
+ void onAvailabilityChanged(@RcsUceAdapter.RcsImsCapabilityFlag int capabilities);
+ }
- private static class CapabilityBinder extends IImsCapabilityCallback.Stub {
+ /**
+ * Receive the availability status changed from the ImsService and pass the status change to
+ * the associated {@link OnAvailabilityChangedListener}
+ */
+ private static class AvailabilityCallbackAdapter {
- private final AvailabilityCallback mLocalCallback;
- private Executor mExecutor;
+ private static class CapabilityBinder extends IImsCapabilityCallback.Stub {
+ private final OnAvailabilityChangedListener mOnAvailabilityChangedListener;
+ private final Executor mExecutor;
- CapabilityBinder(AvailabilityCallback c) {
- mLocalCallback = c;
+ CapabilityBinder(OnAvailabilityChangedListener listener, Executor executor) {
+ mExecutor = executor;
+ mOnAvailabilityChangedListener = listener;
}
@Override
public void onCapabilitiesStatusChanged(int config) {
- if (mLocalCallback == null) return;
+ if (mOnAvailabilityChangedListener == null) return;
long callingIdentity = Binder.clearCallingIdentity();
try {
- mExecutor.execute(() -> mLocalCallback.onAvailabilityChanged(config));
+ mExecutor.execute(() ->
+ mOnAvailabilityChangedListener.onAvailabilityChanged(config));
} finally {
restoreCallingIdentity(callingIdentity);
}
@@ -110,48 +131,34 @@ public class ImsRcsManager {
@Override
public void onQueryCapabilityConfiguration(int capability, int radioTech,
boolean isEnabled) {
- // This is not used for public interfaces.
+ // This is not used.
}
@Override
public void onChangeCapabilityConfigurationError(int capability, int radioTech,
@ImsFeature.ImsCapabilityError int reason) {
- // This is not used for public interfaces
- }
-
- private void setExecutor(Executor executor) {
- mExecutor = executor;
+ // This is not used.
}
}
- private final CapabilityBinder mBinder = new CapabilityBinder(this);
+ private final CapabilityBinder mBinder;
- /**
- * The availability of the feature's capabilities has changed to either available or
- * unavailable.
- * <p>
- * If unavailable, the feature does not support the capability at the current time. This may
- * be due to network or subscription provisioning changes, such as the IMS registration
- * being lost, network type changing, or OMA-DM provisioning updates.
- *
- * @param capabilities The new availability of the capabilities.
- */
- public void onAvailabilityChanged(@RcsUceAdapter.RcsImsCapabilityFlag int capabilities) {
+ AvailabilityCallbackAdapter(@NonNull Executor executor,
+ @NonNull OnAvailabilityChangedListener listener) {
+ mBinder = new CapabilityBinder(listener, executor);
}
/**@hide*/
public final IImsCapabilityCallback getBinder() {
return mBinder;
}
-
- private void setExecutor(Executor executor) {
- mBinder.setExecutor(executor);
- }
}
private final int mSubId;
private final Context mContext;
private final BinderCacheManager<IImsRcsController> mBinderCache;
+ private final Map<OnAvailabilityChangedListener, AvailabilityCallbackAdapter>
+ mAvailabilityChangedCallbacks;
/**
* Use {@link ImsManager#getImsRcsManager(int)} to create an instance of this class.
@@ -162,6 +169,7 @@ public class ImsRcsManager {
mSubId = subId;
mContext = context;
mBinderCache = binderCache;
+ mAvailabilityChangedCallbacks = new HashMap<>();
}
/**
@@ -174,10 +182,23 @@ public class ImsRcsManager {
}
/**
- * @hide
+ * Registers a {@link RegistrationManager.RegistrationCallback} with the system. When the
+ * callback is registered, it will initiate the callback c to be called with the current
+ * registration state.
+ *
+ * Requires Permission: {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE
+ * READ_PRECISE_PHONE_STATE} or that the calling app has carrier privileges
+ * (see {@link android.telephony.TelephonyManager#hasCarrierPrivileges}).
+ *
+ * @param executor The executor the callback events should be run on.
+ * @param c The {@link RegistrationManager.RegistrationCallback} to be added.
+ * @see #unregisterImsRegistrationCallback(RegistrationManager.RegistrationCallback)
+ * @throws ImsException if the subscription associated with this callback is valid, but
+ * the {@link ImsService} associated with the subscription is not available. This can happen if
+ * the service crashed, for example. See {@link ImsException#getCode()} for a more detailed
+ * reason.
*/
- // @Override add back to RegistrationManager interface once public.
- @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ @RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE)
public void registerImsRegistrationCallback(
@NonNull @CallbackExecutor Executor executor,
@NonNull RegistrationManager.RegistrationCallback c)
@@ -191,7 +212,7 @@ public class ImsRcsManager {
IImsRcsController imsRcsController = getIImsRcsController();
if (imsRcsController == null) {
- Log.e(TAG, "Register registration callback: IImsRcsController is null");
+ Log.w(TAG, "Register registration callback: IImsRcsController is null");
throw new ImsException("Cannot find remote IMS service",
ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
}
@@ -207,10 +228,21 @@ public class ImsRcsManager {
}
/**
- * @hide
+ * Removes an existing {@link RegistrationManager.RegistrationCallback}.
+ *
+ * When the subscription associated with this callback is removed (SIM removed, ESIM swap,
+ * etc...), this callback will automatically be removed. If this method is called for an
+ * inactive subscription, it will result in a no-op.
+ *
+ * Requires Permission: {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE
+ * READ_PRECISE_PHONE_STATE} or that the calling app has carrier privileges
+ * (see {@link android.telephony.TelephonyManager#hasCarrierPrivileges}).
+ *
+ * @param c The {@link RegistrationManager.RegistrationCallback} to be removed.
+ * @see android.telephony.SubscriptionManager.OnSubscriptionsChangedListener
+ * @see #registerImsRegistrationCallback(Executor, RegistrationCallback)
*/
- // @Override add back to RegistrationManager interface once public.
- @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ @RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE)
public void unregisterImsRegistrationCallback(
@NonNull RegistrationManager.RegistrationCallback c) {
if (c == null) {
@@ -219,7 +251,7 @@ public class ImsRcsManager {
IImsRcsController imsRcsController = getIImsRcsController();
if (imsRcsController == null) {
- Log.e(TAG, "Unregister registration callback: IImsRcsController is null");
+ Log.w(TAG, "Unregister registration callback: IImsRcsController is null");
throw new IllegalStateException("Cannot find remote IMS service");
}
@@ -231,10 +263,21 @@ public class ImsRcsManager {
}
/**
- * @hide
+ * Gets the registration state of the IMS service.
+ *
+ * Requires Permission: {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE
+ * READ_PRECISE_PHONE_STATE} or that the calling app has carrier privileges
+ * (see {@link android.telephony.TelephonyManager#hasCarrierPrivileges}).
+ *
+ * @param executor The {@link Executor} that will be used to call the IMS registration state
+ * callback.
+ * @param stateCallback A callback called on the supplied {@link Executor} that will contain the
+ * registration state of the IMS service, which will be one of the
+ * following: {@link RegistrationManager#REGISTRATION_STATE_NOT_REGISTERED},
+ * {@link RegistrationManager#REGISTRATION_STATE_REGISTERING}, or
+ * {@link RegistrationManager#REGISTRATION_STATE_REGISTERED}.
*/
- // @Override add back to RegistrationManager interface once public.
- @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ @RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE)
public void getRegistrationState(@NonNull @CallbackExecutor Executor executor,
@NonNull @RegistrationManager.ImsRegistrationState Consumer<Integer> stateCallback) {
if (stateCallback == null) {
@@ -246,7 +289,7 @@ public class ImsRcsManager {
IImsRcsController imsRcsController = getIImsRcsController();
if (imsRcsController == null) {
- Log.e(TAG, "Get registration state error: IImsRcsController is null");
+ Log.w(TAG, "Get registration state error: IImsRcsController is null");
throw new IllegalStateException("Cannot find remote IMS service");
}
@@ -263,9 +306,20 @@ public class ImsRcsManager {
}
/**
- * @hide
+ * Gets the Transport Type associated with the current IMS registration.
+ *
+ * Requires Permission: {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE
+ * READ_PRECISE_PHONE_STATE} or that the calling app has carrier privileges
+ * (see {@link android.telephony.TelephonyManager#hasCarrierPrivileges}).
+ *
+ * @param executor The {@link Executor} that will be used to call the transportTypeCallback.
+ * @param transportTypeCallback The transport type associated with the current IMS registration,
+ * which will be one of following:
+ * {@see AccessNetworkConstants#TRANSPORT_TYPE_WWAN},
+ * {@see AccessNetworkConstants#TRANSPORT_TYPE_WLAN}, or
+ * {@see AccessNetworkConstants#TRANSPORT_TYPE_INVALID}.
*/
- @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ @RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE)
public void getRegistrationTransportType(@NonNull @CallbackExecutor Executor executor,
@NonNull @AccessNetworkConstants.TransportType
Consumer<Integer> transportTypeCallback) {
@@ -278,7 +332,7 @@ public class ImsRcsManager {
IImsRcsController imsRcsController = getIImsRcsController();
if (imsRcsController == null) {
- Log.e(TAG, "Get registration transport type error: IImsRcsController is null");
+ Log.w(TAG, "Get registration transport type error: IImsRcsController is null");
throw new IllegalStateException("Cannot find remote IMS service");
}
@@ -296,31 +350,33 @@ public class ImsRcsManager {
}
/**
- * Registers an {@link AvailabilityCallback} with the system, which will provide RCS
+ * Add an {@link OnAvailabilityChangedListener} with the system, which will provide RCS
* availability updates for the subscription specified.
*
* Use {@link SubscriptionManager.OnSubscriptionsChangedListener} to listen to
* subscription changed events and call
- * {@link #unregisterRcsAvailabilityCallback(AvailabilityCallback)} to clean up after a
- * subscription is removed.
+ * {@link #removeOnAvailabilityChangedListener(OnAvailabilityChangedListener)} to clean up
+ * after a subscription is removed.
* <p>
- * When the callback is registered, it will initiate the callback c to be called with the
- * current capabilities.
+ * When the listener is registered, it will initiate the callback listener to be called with
+ * the current capabilities.
*
* @param executor The executor the callback events should be run on.
- * @param c The RCS {@link AvailabilityCallback} to be registered.
- * @see #unregisterRcsAvailabilityCallback(AvailabilityCallback)
+ * @param listener The RCS {@link OnAvailabilityChangedListener} to be registered.
+ * @see #removeOnAvailabilityChangedListener(OnAvailabilityChangedListener)
* @throws ImsException if the subscription associated with this instance of
* {@link ImsRcsManager} is valid, but the ImsService associated with the subscription is not
* available. This can happen if the ImsService has crashed, for example, or if the subscription
* becomes inactive. See {@link ImsException#getCode()} for more information on the error codes.
* @hide
*/
+ @SystemApi
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
- public void registerRcsAvailabilityCallback(@NonNull @CallbackExecutor Executor executor,
- @NonNull AvailabilityCallback c) throws ImsException {
- if (c == null) {
- throw new IllegalArgumentException("Must include a non-null AvailabilityCallback.");
+ public void addOnAvailabilityChangedListener(@NonNull @CallbackExecutor Executor executor,
+ @NonNull OnAvailabilityChangedListener listener) throws ImsException {
+ if (listener == null) {
+ throw new IllegalArgumentException("Must include a non-null"
+ + "OnAvailabilityChangedListener.");
}
if (executor == null) {
throw new IllegalArgumentException("Must include a non-null Executor.");
@@ -328,56 +384,61 @@ public class ImsRcsManager {
IImsRcsController imsRcsController = getIImsRcsController();
if (imsRcsController == null) {
- Log.e(TAG, "Register availability callback: IImsRcsController is null");
+ Log.w(TAG, "Add availability changed listener: IImsRcsController is null");
throw new ImsException("Cannot find remote IMS service",
ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
}
- c.setExecutor(executor);
+ AvailabilityCallbackAdapter adapter =
+ addAvailabilityChangedListenerToCollection(executor, listener);
try {
- imsRcsController.registerRcsAvailabilityCallback(mSubId, c.getBinder());
-
+ imsRcsController.registerRcsAvailabilityCallback(mSubId, adapter.getBinder());
} catch (ServiceSpecificException e) {
throw new ImsException(e.toString(), e.errorCode);
} catch (RemoteException e) {
- Log.e(TAG, "Error calling IImsRcsController#registerRcsAvailabilityCallback", e);
+ Log.w(TAG, "Error calling IImsRcsController#registerRcsAvailabilityCallback", e);
throw new ImsException("Remote IMS Service is not available",
ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
}
}
- /**
- * Removes an existing RCS {@link AvailabilityCallback}.
+ /**
+ * Removes an existing RCS {@link OnAvailabilityChangedListener}.
* <p>
* When the subscription associated with this callback is removed (SIM removed, ESIM swap,
* etc...), this callback will automatically be unregistered. If this method is called for an
* inactive subscription, it will result in a no-op.
- * @param c The RCS {@link AvailabilityCallback} to be removed.
- * @see #registerRcsAvailabilityCallback(Executor, AvailabilityCallback)
+ * @param listener The RCS {@link OnAvailabilityChangedListener} to be removed.
+ * @see #addOnAvailabilityChangedListener(Executor, OnAvailabilityChangedListener)
* @throws ImsException if the IMS service is not available when calling this method.
* See {@link ImsException#getCode()} for more information on the error codes.
* @hide
*/
+ @SystemApi
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
- public void unregisterRcsAvailabilityCallback(@NonNull AvailabilityCallback c)
- throws ImsException {
- if (c == null) {
- throw new IllegalArgumentException("Must include a non-null AvailabilityCallback.");
+ public void removeOnAvailabilityChangedListener(
+ @NonNull OnAvailabilityChangedListener listener) {
+ if (listener == null) {
+ throw new IllegalArgumentException("Must include a non-null"
+ + "OnAvailabilityChangedListener.");
}
IImsRcsController imsRcsController = getIImsRcsController();
if (imsRcsController == null) {
- Log.e(TAG, "Unregister availability callback: IImsRcsController is null");
- throw new ImsException("Cannot find remote IMS service",
- ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+ Log.w(TAG, "Remove availability changed listener: IImsRcsController is null");
+ return;
+ }
+
+ AvailabilityCallbackAdapter callback =
+ removeAvailabilityChangedListenerFromCollection(listener);
+ if (callback == null) {
+ return;
}
try {
- imsRcsController.unregisterRcsAvailabilityCallback(mSubId, c.getBinder());
+ imsRcsController.unregisterRcsAvailabilityCallback(mSubId, callback.getBinder());
} catch (RemoteException e) {
- Log.e(TAG, "Error calling IImsRcsController#unregisterRcsAvailabilityCallback", e);
- throw new ImsException("Remote IMS Service is not available",
- ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+ Log.w(TAG, "Error calling IImsRcsController#unregisterRcsAvailabilityCallback", e);
}
}
@@ -388,25 +449,24 @@ public class ImsRcsManager {
* RCS capabilities provided over-the-top by applications.
*
* @param capability The RCS capability to query.
- * @param radioTech The radio tech that this capability failed for, defined as
- * {@link ImsRegistrationImplBase#REGISTRATION_TECH_LTE} or
- * {@link ImsRegistrationImplBase#REGISTRATION_TECH_IWLAN}.
+ * @param radioTech The radio technology type that we are querying.
* @return true if the RCS capability is capable for this subscription, false otherwise. This
* does not necessarily mean that we are registered for IMS and the capability is available, but
* rather the subscription is capable of this service over IMS.
- * @see #isAvailable(int)
+ * @see #isAvailable(int, int)
* @see android.telephony.CarrierConfigManager#KEY_USE_RCS_PRESENCE_BOOL
* @see android.telephony.CarrierConfigManager.Ims#KEY_ENABLE_PRESENCE_CAPABILITY_EXCHANGE_BOOL
* @throws ImsException if the IMS service is not available when calling this method.
* See {@link ImsException#getCode()} for more information on the error codes.
* @hide
*/
+ @SystemApi
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public boolean isCapable(@RcsUceAdapter.RcsImsCapabilityFlag int capability,
@ImsRegistrationImplBase.ImsRegistrationTech int radioTech) throws ImsException {
IImsRcsController imsRcsController = getIImsRcsController();
if (imsRcsController == null) {
- Log.e(TAG, "isCapable: IImsRcsController is null");
+ Log.w(TAG, "isCapable: IImsRcsController is null");
throw new ImsException("Cannot find remote IMS service",
ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
}
@@ -414,7 +474,7 @@ public class ImsRcsManager {
try {
return imsRcsController.isCapable(mSubId, capability, radioTech);
} catch (RemoteException e) {
- Log.e(TAG, "Error calling IImsRcsController#isCapable", e);
+ Log.w(TAG, "Error calling IImsRcsController#isCapable", e);
throw new ImsException("Remote IMS Service is not available",
ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
}
@@ -427,6 +487,7 @@ public class ImsRcsManager {
* RCS capabilities provided by over-the-top by applications.
*
* @param capability the RCS capability to query.
+ * @param radioTech The radio technology type that we are querying.
* @return true if the RCS capability is currently available for the associated subscription,
* false otherwise. If the capability is available, IMS is registered and the service is
* currently available over IMS.
@@ -435,25 +496,57 @@ public class ImsRcsManager {
* See {@link ImsException#getCode()} for more information on the error codes.
* @hide
*/
+ @SystemApi
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
- public boolean isAvailable(@RcsUceAdapter.RcsImsCapabilityFlag int capability)
+ public boolean isAvailable(@RcsUceAdapter.RcsImsCapabilityFlag int capability,
+ @ImsRegistrationImplBase.ImsRegistrationTech int radioTech)
throws ImsException {
IImsRcsController imsRcsController = getIImsRcsController();
if (imsRcsController == null) {
- Log.e(TAG, "isAvailable: IImsRcsController is null");
+ Log.w(TAG, "isAvailable: IImsRcsController is null");
throw new ImsException("Cannot find remote IMS service",
ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
}
try {
- return imsRcsController.isAvailable(mSubId, capability);
+ return imsRcsController.isAvailable(mSubId, capability, radioTech);
} catch (RemoteException e) {
- Log.e(TAG, "Error calling IImsRcsController#isAvailable", e);
+ Log.w(TAG, "Error calling IImsRcsController#isAvailable", e);
throw new ImsException("Remote IMS Service is not available",
ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
}
}
+ /**
+ * Add the {@link OnAvailabilityChangedListener} to collection for tracking.
+ * @param executor The executor that will be used when the publish state is changed and the
+ * {@link OnAvailabilityChangedListener} is called.
+ * @param listener The {@link OnAvailabilityChangedListener} to call the publish state changed.
+ * @return The {@link AvailabilityCallbackAdapter} to wrapper the
+ * {@link OnAvailabilityChangedListener}
+ */
+ private AvailabilityCallbackAdapter addAvailabilityChangedListenerToCollection(
+ @NonNull Executor executor, @NonNull OnAvailabilityChangedListener listener) {
+ AvailabilityCallbackAdapter adapter = new AvailabilityCallbackAdapter(executor, listener);
+ synchronized (mAvailabilityChangedCallbacks) {
+ mAvailabilityChangedCallbacks.put(listener, adapter);
+ }
+ return adapter;
+ }
+
+ /**
+ * Remove the existing {@link OnAvailabilityChangedListener} from the collection.
+ * @param listener The {@link OnAvailabilityChangedListener} to remove from the collection.
+ * @return The wrapper class {@link AvailabilityCallbackAdapter} associated with the
+ * {@link OnAvailabilityChangedListener}.
+ */
+ private AvailabilityCallbackAdapter removeAvailabilityChangedListenerFromCollection(
+ @NonNull OnAvailabilityChangedListener listener) {
+ synchronized (mAvailabilityChangedCallbacks) {
+ return mAvailabilityChangedCallbacks.remove(listener);
+ }
+ }
+
private IImsRcsController getIImsRcsController() {
IBinder binder = TelephonyFrameworkInitializer
.getTelephonyServiceManager()
diff --git a/telephony/java/android/telephony/ims/ImsRegistrationAttributes.aidl b/telephony/java/android/telephony/ims/ImsRegistrationAttributes.aidl
new file mode 100644
index 000000000000..0830ff2ff050
--- /dev/null
+++ b/telephony/java/android/telephony/ims/ImsRegistrationAttributes.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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.telephony.ims;
+
+parcelable ImsRegistrationAttributes;
diff --git a/telephony/java/android/telephony/ims/ImsRegistrationAttributes.java b/telephony/java/android/telephony/ims/ImsRegistrationAttributes.java
new file mode 100644
index 000000000000..a36f54953e63
--- /dev/null
+++ b/telephony/java/android/telephony/ims/ImsRegistrationAttributes.java
@@ -0,0 +1,219 @@
+/*
+ * 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.telephony.ims;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.telephony.AccessNetworkConstants;
+import android.telephony.ims.stub.ImsRegistrationImplBase;
+import android.util.ArraySet;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * Contains the attributes associated with the current IMS registration.
+ */
+public final class ImsRegistrationAttributes implements Parcelable {
+
+ /**
+ * Builder for creating {@link ImsRegistrationAttributes} instances.
+ * @hide
+ */
+ @SystemApi
+ public static final class Builder {
+ private final int mRegistrationTech;
+ private Set<String> mFeatureTags = Collections.emptySet();
+
+ /**
+ * Build a new instance of {@link ImsRegistrationAttributes}.
+ *
+ * @param registrationTech The Radio Access Technology that IMS is registered on.
+ */
+ public Builder(@ImsRegistrationImplBase.ImsRegistrationTech int registrationTech) {
+ mRegistrationTech = registrationTech;
+ }
+
+ /**
+ * Optional IMS feature tags included in this IMS registration.
+ * @param tags A set of Strings containing the MMTEL and RCS feature tags associated with
+ * the IMS registration. This information is used for services such as the UCE
+ * service to ascertain the complete IMS registration state to ensure the SIP
+ * PUBLISH is accurate. The format of the set of feature tags must be one feature
+ * tag key and value per entry. Each feature tag will contain the feature tag name
+ * and string value (if applicable), even if they have the same feature tag name.
+ * For example,
+ * {@code +g.3gpp.icsi-ref="urn%3Aurn-7%3A3gpp-service.ims.icsi.oma.cpm.msg,
+ * urn%3Aurn-7%3A3gpp-service.ims.icsi.oma.cpm.session", +g.gsma.callcomposer} must
+ * be split into three feature tag entries:
+ * {@code {+g.3gpp.icsi-ref="urn%3Aurn-7%3A3gpp-service.ims.icsi.oma.cpm.msg",
+ * +g.3gpp.icsi-ref="urn%3Aurn-7%3A3gpp-service.ims.icsi.oma.cpm.session",
+ * +g.gsma.callcomposer}}.
+ */
+ public @NonNull Builder setFeatureTags(@NonNull Set<String> tags) {
+ if (tags == null) {
+ throw new IllegalArgumentException("feature tag set must not be null");
+ }
+ mFeatureTags = new ArraySet<>(tags);
+ return this;
+ }
+
+ /**
+ * @return A new instance created from this builder.
+ */
+ public @NonNull ImsRegistrationAttributes build() {
+ return new ImsRegistrationAttributes(mRegistrationTech,
+ RegistrationManager.getAccessType(mRegistrationTech),
+ 0 /* No attributes in AOSP */, mFeatureTags);
+ }
+
+ }
+
+ private final int mRegistrationTech;
+ private final int mTransportType;
+ private final int mImsAttributeFlags;
+ private final ArrayList<String> mFeatureTags;
+
+ /**
+ * Create a new {@link ImsRegistrationAttributes} instance.
+ *
+ * @param registrationTech The technology that IMS has been registered on.
+ * @param transportType The transport type that IMS has been registered on.
+ * @param imsAttributeFlags The attributes associated with the IMS registration.
+ * @param featureTags The feature tags included in the IMS registration.
+ * @see Builder
+ * @hide
+ */
+ public ImsRegistrationAttributes(
+ @ImsRegistrationImplBase.ImsRegistrationTech int registrationTech,
+ @AccessNetworkConstants.TransportType int transportType,
+ int imsAttributeFlags,
+ @Nullable Set<String> featureTags) {
+ mRegistrationTech = registrationTech;
+ mTransportType = transportType;
+ mImsAttributeFlags = imsAttributeFlags;
+ mFeatureTags = new ArrayList<>(featureTags);
+ }
+
+ /**@hide*/
+ public ImsRegistrationAttributes(Parcel source) {
+ mRegistrationTech = source.readInt();
+ mTransportType = source.readInt();
+ mImsAttributeFlags = source.readInt();
+ mFeatureTags = new ArrayList<>();
+ source.readList(mFeatureTags, null /*classloader*/);
+ }
+
+ /**
+ * @return The Radio Access Technology that the IMS registration has been registered over.
+ * @hide
+ */
+ @SystemApi
+ public @ImsRegistrationImplBase.ImsRegistrationTech int getRegistrationTechnology() {
+ return mRegistrationTech;
+ }
+
+ /**
+ * @return The access network transport type that IMS has been registered over.
+ */
+ public @AccessNetworkConstants.TransportType int getTransportType() {
+ return mTransportType;
+ }
+
+ /**
+ * @return A bit-mask containing attributes associated with the IMS registration.
+ */
+ public int getAttributeFlags() {
+ return mImsAttributeFlags;
+ }
+
+ /**
+ * Gets the Set of feature tags associated with the current IMS registration, if the IMS
+ * service supports supplying this information.
+ * <p>
+ * The format of the set of feature tags will be one feature tag key and value per entry and
+ * will potentially contain MMTEL and RCS feature tags, depending the configuration of the IMS
+ * service associated with the registration indications. Each feature tag will contain the
+ * feature tag name and string value (if applicable), even if they have the same feature tag
+ * name. For example, {@code +g.3gpp.icsi-ref="urn%3Aurn-7%3A3gpp-service.ims.icsi.oma.cpm.msg,
+ * urn%3Aurn-7%3A3gpp-service.ims.icsi.oma.cpm.session", +g.gsma.callcomposer} will be split
+ * into three feature tag entries:
+ * {@code {+g.3gpp.icsi-ref="urn%3Aurn-7%3A3gpp-service.ims.icsi.oma.cpm.msg",
+ * +g.3gpp.icsi-ref="urn%3Aurn-7%3A3gpp-service.ims.icsi.oma.cpm.session",
+ * +g.gsma.callcomposer}}.
+ * @return The Set of feature tags associated with the current IMS registration.
+ */
+ public @NonNull Set<String> getFeatureTags() {
+ if (mFeatureTags == null) {
+ return Collections.emptySet();
+ }
+ return new ArraySet<>(mFeatureTags);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeInt(mRegistrationTech);
+ dest.writeInt(mTransportType);
+ dest.writeInt(mImsAttributeFlags);
+ dest.writeList(mFeatureTags);
+ }
+
+ public static final @NonNull Creator<ImsRegistrationAttributes> CREATOR =
+ new Creator<ImsRegistrationAttributes>() {
+ @Override
+ public ImsRegistrationAttributes createFromParcel(Parcel source) {
+ return new ImsRegistrationAttributes(source);
+ }
+
+ @Override
+ public ImsRegistrationAttributes[] newArray(int size) {
+ return new ImsRegistrationAttributes[size];
+ }
+ };
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ ImsRegistrationAttributes that = (ImsRegistrationAttributes) o;
+ return mRegistrationTech == that.mRegistrationTech
+ && mTransportType == that.mTransportType
+ && mImsAttributeFlags == that.mImsAttributeFlags
+ && Objects.equals(mFeatureTags, that.mFeatureTags);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mRegistrationTech, mTransportType, mImsAttributeFlags, mFeatureTags);
+ }
+
+ @Override
+ public String toString() {
+ return "ImsRegistrationAttributes { transportType= " + mTransportType + ", attributeFlags="
+ + mImsAttributeFlags + ", featureTags=[" + mFeatureTags + "]}";
+ }
+}
diff --git a/telephony/java/android/telephony/ims/RegistrationManager.java b/telephony/java/android/telephony/ims/RegistrationManager.java
index 2c75368b86bf..c49121f4dc5d 100644
--- a/telephony/java/android/telephony/ims/RegistrationManager.java
+++ b/telephony/java/android/telephony/ims/RegistrationManager.java
@@ -71,7 +71,6 @@ public interface RegistrationManager {
*/
int REGISTRATION_STATE_REGISTERED = 2;
-
/**@hide*/
// Translate ImsRegistrationImplBase API to new AccessNetworkConstant because WLAN
// and WWAN are more accurate constants.
@@ -79,7 +78,8 @@ public interface RegistrationManager {
new HashMap<Integer, Integer>() {{
// Map NONE to -1 to make sure that we handle the REGISTRATION_TECH_NONE
// case, since it is defined.
- put(ImsRegistrationImplBase.REGISTRATION_TECH_NONE, -1);
+ put(ImsRegistrationImplBase.REGISTRATION_TECH_NONE,
+ AccessNetworkConstants.TRANSPORT_TYPE_INVALID);
put(ImsRegistrationImplBase.REGISTRATION_TECH_LTE,
AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
put(ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN,
@@ -103,6 +103,20 @@ public interface RegistrationManager {
}
/**
+ * @param regtech The registration technology.
+ * @return The Access Network type from registration technology.
+ * @hide
+ */
+ static int getAccessType(int regtech) {
+ if (!RegistrationManager.IMS_REG_TO_ACCESS_TYPE_MAP.containsKey(regtech)) {
+ Log.w("RegistrationManager", "getAccessType - invalid regType returned: "
+ + regtech);
+ return AccessNetworkConstants.TRANSPORT_TYPE_INVALID;
+ }
+ return RegistrationManager.IMS_REG_TO_ACCESS_TYPE_MAP.get(regtech);
+ }
+
+ /**
* Callback class for receiving IMS network Registration callback events.
* @see #registerImsRegistrationCallback(Executor, RegistrationCallback)
* @see #unregisterImsRegistrationCallback(RegistrationCallback)
@@ -119,26 +133,24 @@ public interface RegistrationManager {
}
@Override
- public void onRegistered(int imsRadioTech) {
+ public void onRegistered(ImsRegistrationAttributes attr) {
if (mLocalCallback == null) return;
long callingIdentity = Binder.clearCallingIdentity();
try {
- mExecutor.execute(() ->
- mLocalCallback.onRegistered(getAccessType(imsRadioTech)));
+ mExecutor.execute(() -> mLocalCallback.onRegistered(attr));
} finally {
restoreCallingIdentity(callingIdentity);
}
}
@Override
- public void onRegistering(int imsRadioTech) {
+ public void onRegistering(ImsRegistrationAttributes attr) {
if (mLocalCallback == null) return;
long callingIdentity = Binder.clearCallingIdentity();
try {
- mExecutor.execute(() ->
- mLocalCallback.onRegistering(getAccessType(imsRadioTech)));
+ mExecutor.execute(() -> mLocalCallback.onRegistering(attr));
} finally {
restoreCallingIdentity(callingIdentity);
}
@@ -183,15 +195,6 @@ public interface RegistrationManager {
private void setExecutor(Executor executor) {
mExecutor = executor;
}
-
- private static int getAccessType(int regType) {
- if (!RegistrationManager.IMS_REG_TO_ACCESS_TYPE_MAP.containsKey(regType)) {
- Log.w("RegistrationManager", "RegistrationBinder - invalid regType returned: "
- + regType);
- return -1;
- }
- return RegistrationManager.IMS_REG_TO_ACCESS_TYPE_MAP.get(regType);
- }
}
private final RegistrationBinder mBinder = new RegistrationBinder(this);
@@ -200,19 +203,42 @@ public interface RegistrationManager {
* Notifies the framework when the IMS Provider is registered to the IMS network.
*
* @param imsTransportType the radio access technology.
+ * @deprecated Use {@link #onRegistered(ImsRegistrationAttributes)} instead.
*/
public void onRegistered(@AccessNetworkConstants.TransportType int imsTransportType) {
}
/**
+ * Notifies the framework when the IMS Provider is registered to the IMS network
+ * with corresponding attributes.
+ *
+ * @param attributes The attributes associated with this IMS registration.
+ */
+ public void onRegistered(@NonNull ImsRegistrationAttributes attributes) {
+ // Default impl to keep backwards compatibility with old implementations
+ onRegistered(attributes.getTransportType());
+ }
+
+ /**
* Notifies the framework when the IMS Provider is trying to register the IMS network.
*
* @param imsTransportType the radio access technology.
+ * @deprecated Use {@link #onRegistering(ImsRegistrationAttributes)} instead.
*/
public void onRegistering(@AccessNetworkConstants.TransportType int imsTransportType) {
}
/**
+ * Notifies the framework when the IMS Provider is trying to register the IMS network.
+ *
+ * @param attributes The attributes associated with this IMS registration.
+ */
+ public void onRegistering(@NonNull ImsRegistrationAttributes attributes) {
+ // Default impl to keep backwards compatibility with old implementations
+ onRegistering(attributes.getTransportType());
+ }
+
+ /**
* Notifies the framework when the IMS Provider is unregistered from the IMS network.
*
* @param info the {@link ImsReasonInfo} associated with why registration was disconnected.
@@ -298,10 +324,10 @@ public interface RegistrationManager {
* @param executor The {@link Executor} that will be used to call the IMS registration state
* callback.
* @param stateCallback A callback called on the supplied {@link Executor} that will contain the
- * registration state of the IMS service, which will be one of the
- * following: {@link #REGISTRATION_STATE_NOT_REGISTERED},
- * {@link #REGISTRATION_STATE_REGISTERING}, or
- * {@link #REGISTRATION_STATE_REGISTERED}.
+ * registration state of the IMS service, which will be one of the
+ * following: {@link #REGISTRATION_STATE_NOT_REGISTERED},
+ * {@link #REGISTRATION_STATE_REGISTERING}, or
+ * {@link #REGISTRATION_STATE_REGISTERED}.
*/
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
void getRegistrationState(@NonNull @CallbackExecutor Executor executor,
diff --git a/telephony/java/android/telephony/ims/aidl/IImsRcsController.aidl b/telephony/java/android/telephony/ims/aidl/IImsRcsController.aidl
index 7a6c28bddd09..8931a78709ed 100644
--- a/telephony/java/android/telephony/ims/aidl/IImsRcsController.aidl
+++ b/telephony/java/android/telephony/ims/aidl/IImsRcsController.aidl
@@ -47,7 +47,7 @@ interface IImsRcsController {
void registerRcsAvailabilityCallback(int subId, IImsCapabilityCallback c);
void unregisterRcsAvailabilityCallback(int subId, IImsCapabilityCallback c);
boolean isCapable(int subId, int capability, int radioTech);
- boolean isAvailable(int subId, int capability);
+ boolean isAvailable(int subId, int capability, int radioTech);
// ImsUceAdapter specific
void requestCapabilities(int subId, String callingPackage, String callingFeatureId,
diff --git a/telephony/java/android/telephony/ims/aidl/IImsRegistrationCallback.aidl b/telephony/java/android/telephony/ims/aidl/IImsRegistrationCallback.aidl
index 749b1916962e..179407c983e5 100644
--- a/telephony/java/android/telephony/ims/aidl/IImsRegistrationCallback.aidl
+++ b/telephony/java/android/telephony/ims/aidl/IImsRegistrationCallback.aidl
@@ -21,6 +21,7 @@ import android.net.Uri;
import android.telephony.ims.stub.ImsFeatureConfiguration;
import android.telephony.ims.ImsReasonInfo;
+import android.telephony.ims.ImsRegistrationAttributes;
/**
* See {@link ImsManager#RegistrationCallback} for more information.
@@ -28,8 +29,8 @@ import android.telephony.ims.ImsReasonInfo;
* {@hide}
*/
oneway interface IImsRegistrationCallback {
- void onRegistered(int imsRadioTech);
- void onRegistering(int imsRadioTech);
+ void onRegistered(in ImsRegistrationAttributes attr);
+ void onRegistering(in ImsRegistrationAttributes attr);
void onDeregistered(in ImsReasonInfo info);
void onTechnologyChangeFailed(int imsRadioTech, in ImsReasonInfo info);
void onSubscriberAssociatedUriChanged(in Uri[] uris);
diff --git a/telephony/java/android/telephony/ims/feature/CapabilityChangeRequest.java b/telephony/java/android/telephony/ims/feature/CapabilityChangeRequest.java
index 87a6873d00b2..47c56e13f829 100644
--- a/telephony/java/android/telephony/ims/feature/CapabilityChangeRequest.java
+++ b/telephony/java/android/telephony/ims/feature/CapabilityChangeRequest.java
@@ -36,12 +36,9 @@ import java.util.Set;
public final class CapabilityChangeRequest implements Parcelable {
/**
- * Contains a feature capability, defined as
- * {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VOICE},
- * {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VIDEO},
- * {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_UT}, or
- * {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_SMS},
- * along with an associated technology, defined as
+ * Contains a MMTEL feature capability {@link MmTelFeature.MmTelCapabilities} and RCS feature
+ * capability {@link RcsFeature.RcsImsCapabilities}, along with an associated technology,
+ * defined as
* {@link ImsRegistrationImplBase#REGISTRATION_TECH_LTE} or
* {@link ImsRegistrationImplBase#REGISTRATION_TECH_IWLAN}
*/
@@ -49,7 +46,7 @@ public final class CapabilityChangeRequest implements Parcelable {
private final int mCapability;
private final int radioTech;
- public CapabilityPair(@MmTelFeature.MmTelCapabilities.MmTelCapability int capability,
+ public CapabilityPair(int capability,
@ImsRegistrationImplBase.ImsRegistrationTech int radioTech) {
this.mCapability = capability;
this.radioTech = radioTech;
@@ -80,13 +77,10 @@ public final class CapabilityChangeRequest implements Parcelable {
}
/**
- * @return The stored capability, defined as
- * {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VOICE},
- * {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VIDEO},
- * {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_UT}, or
- * {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_SMS}
+ * @return The stored capability, defined as {@link MmTelFeature.MmTelCapabilities} and
+ * {@link RcsFeature.RcsImsCapabilities}
*/
- public @MmTelFeature.MmTelCapabilities.MmTelCapability int getCapability() {
+ public int getCapability() {
return mCapability;
}
@@ -123,12 +117,11 @@ public final class CapabilityChangeRequest implements Parcelable {
* Add one or many capabilities to the request to be enabled.
*
* @param capabilities A bitfield of capabilities to enable, valid values are defined in
- * {@link MmTelFeature.MmTelCapabilities.MmTelCapability}.
+ * {@link MmTelFeature.MmTelCapabilities} and {@link RcsFeature.RcsImsCapabilities}.
* @param radioTech the radio tech that these capabilities should be enabled for, valid
* values are in {@link ImsRegistrationImplBase.ImsRegistrationTech}.
*/
- public void addCapabilitiesToEnableForTech(
- @MmTelFeature.MmTelCapabilities.MmTelCapability int capabilities,
+ public void addCapabilitiesToEnableForTech(int capabilities,
@ImsRegistrationImplBase.ImsRegistrationTech int radioTech) {
addAllCapabilities(mCapabilitiesToEnable, capabilities, radioTech);
}
@@ -136,12 +129,11 @@ public final class CapabilityChangeRequest implements Parcelable {
/**
* Add one or many capabilities to the request to be disabled.
* @param capabilities A bitfield of capabilities to diable, valid values are defined in
- * {@link MmTelFeature.MmTelCapabilities.MmTelCapability}.
+ * {@link MmTelFeature.MmTelCapabilities} and {@link RcsFeature.RcsImsCapabilities}.
* @param radioTech the radio tech that these capabilities should be disabled for, valid
* values are in {@link ImsRegistrationImplBase.ImsRegistrationTech}.
*/
- public void addCapabilitiesToDisableForTech(
- @MmTelFeature.MmTelCapabilities.MmTelCapability int capabilities,
+ public void addCapabilitiesToDisableForTech(int capabilities,
@ImsRegistrationImplBase.ImsRegistrationTech int radioTech) {
addAllCapabilities(mCapabilitiesToDisable, capabilities, radioTech);
}
diff --git a/telephony/java/android/telephony/ims/feature/RcsFeature.java b/telephony/java/android/telephony/ims/feature/RcsFeature.java
index 22df921c4214..85703f8de5e5 100644
--- a/telephony/java/android/telephony/ims/feature/RcsFeature.java
+++ b/telephony/java/android/telephony/ims/feature/RcsFeature.java
@@ -194,7 +194,6 @@ public class RcsFeature extends ImsFeature {
* of the capability and notify the capability status as true using
* {@link #notifyCapabilitiesStatusChanged(RcsImsCapabilities)}. This will signal to the
* framework that the capability is available for usage.
- * @hide
*/
public static class RcsImsCapabilities extends Capabilities {
/** @hide*/
@@ -226,12 +225,21 @@ public class RcsFeature extends ImsFeature {
*/
public static final int CAPABILITY_TYPE_PRESENCE_UCE = 1 << 1;
+ /**
+ * Create a new {@link RcsImsCapabilities} instance with the provided capabilities.
+ * @param capabilities The capabilities that are supported for RCS in the form of a
+ * bitfield.
+ */
public RcsImsCapabilities(@RcsUceAdapter.RcsImsCapabilityFlag int capabilities) {
super(capabilities);
}
- private RcsImsCapabilities(Capabilities c) {
- super(c.getMask());
+ /**
+ * Create a new {@link RcsImsCapabilities} instance with the provided capabilities.
+ * @param capabilities The capabilities instance that are supported for RCS
+ */
+ private RcsImsCapabilities(Capabilities capabilities) {
+ super(capabilities.getMask());
}
@Override
@@ -307,7 +315,7 @@ public class RcsFeature extends ImsFeature {
* set, the {@link RcsFeature} has brought up the capability and is ready for framework
* requests. To change the status of the capabilities
* {@link #notifyCapabilitiesStatusChanged(RcsImsCapabilities)} should be called.
- * @hide
+ * @return A copy of the current RcsFeature capability status.
*/
@Override
public @NonNull final RcsImsCapabilities queryCapabilityStatus() {
@@ -318,13 +326,13 @@ public class RcsFeature extends ImsFeature {
* Notify the framework that the capabilities status has changed. If a capability is enabled,
* this signals to the framework that the capability has been initialized and is ready.
* Call {@link #queryCapabilityStatus()} to return the current capability status.
- * @hide
+ * @param capabilities The current capability status of the RcsFeature.
*/
- public final void notifyCapabilitiesStatusChanged(@NonNull RcsImsCapabilities c) {
- if (c == null) {
+ public final void notifyCapabilitiesStatusChanged(@NonNull RcsImsCapabilities capabilities) {
+ if (capabilities == null) {
throw new IllegalArgumentException("RcsImsCapabilities must be non-null!");
}
- super.notifyCapabilitiesStatusChanged(c);
+ super.notifyCapabilitiesStatusChanged(capabilities);
}
/**
@@ -333,7 +341,9 @@ public class RcsFeature extends ImsFeature {
* {@link #changeEnabledCapabilities(CapabilityChangeRequest, CapabilityCallbackProxy)} to
* enable or disable capability A, this method should return the correct configuration for
* capability A afterwards (until it has changed).
- * @hide
+ * @param capability The capability that we are querying the configuration for.
+ * @param radioTech The radio technology type that we are querying.
+ * @return true if the capability is enabled, false otherwise.
*/
public boolean queryCapabilityConfiguration(
@RcsUceAdapter.RcsImsCapabilityFlag int capability,
@@ -355,11 +365,12 @@ public class RcsFeature extends ImsFeature {
* If for some reason one or more of these capabilities can not be enabled/disabled,
* {@link CapabilityCallbackProxy#onChangeCapabilityConfigurationError(int, int, int)} should
* be called for each capability change that resulted in an error.
- * @hide
+ * @param request The request to change the capability.
+ * @param callback To notify the framework that the result of the capability changes.
*/
@Override
public void changeEnabledCapabilities(@NonNull CapabilityChangeRequest request,
- @NonNull CapabilityCallbackProxy c) {
+ @NonNull CapabilityCallbackProxy callback) {
// Base Implementation - Override to provide functionality
}
diff --git a/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java b/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java
index 088a7e26a9d0..23032f0c4d38 100644
--- a/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java
@@ -18,17 +18,18 @@ package android.telephony.ims.stub;
import android.annotation.IntDef;
import android.annotation.IntRange;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.net.Uri;
import android.os.RemoteException;
import android.telephony.ims.ImsReasonInfo;
+import android.telephony.ims.ImsRegistrationAttributes;
import android.telephony.ims.RegistrationManager;
import android.telephony.ims.aidl.IImsRegistration;
import android.telephony.ims.aidl.IImsRegistrationCallback;
import android.util.Log;
-import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.util.RemoteCallbackListExt;
import com.android.internal.util.ArrayUtils;
@@ -83,7 +84,10 @@ public class ImsRegistrationImplBase {
@Override
public @ImsRegistrationTech int getRegistrationTechnology() throws RemoteException {
- return getConnectionType();
+ synchronized (mLock) {
+ return (mRegistrationAttributes == null) ? REGISTRATION_TECH_NONE
+ : mRegistrationAttributes.getRegistrationTechnology();
+ }
}
@Override
@@ -116,8 +120,7 @@ public class ImsRegistrationImplBase {
new RemoteCallbackListExt<>();
private final Object mLock = new Object();
// Locked on mLock
- private @ImsRegistrationTech
- int mConnectionType = REGISTRATION_TECH_NONE;
+ private ImsRegistrationAttributes mRegistrationAttributes;
// Locked on mLock
private int mRegistrationState = REGISTRATION_STATE_UNKNOWN;
// Locked on mLock, create unspecified disconnect cause.
@@ -195,17 +198,24 @@ public class ImsRegistrationImplBase {
/**
* Notify the framework that the device is connected to the IMS network.
*
- * @param imsRadioTech the radio access technology. Valid values are defined as
- * {@link #REGISTRATION_TECH_LTE} and {@link #REGISTRATION_TECH_IWLAN}.
+ * @param imsRadioTech the radio access technology.
*/
public final void onRegistered(@ImsRegistrationTech int imsRadioTech) {
- updateToState(imsRadioTech, RegistrationManager.REGISTRATION_STATE_REGISTERED);
+ onRegistered(new ImsRegistrationAttributes.Builder(imsRadioTech).build());
+ }
+
+ /**
+ * Notify the framework that the device is connected to the IMS network.
+ *
+ * @param attributes The attributes associated with the IMS registration.
+ */
+ public final void onRegistered(@NonNull ImsRegistrationAttributes attributes) {
+ updateToState(attributes, RegistrationManager.REGISTRATION_STATE_REGISTERED);
mCallbacks.broadcastAction((c) -> {
try {
- c.onRegistered(imsRadioTech);
+ c.onRegistered(attributes);
} catch (RemoteException e) {
- Log.w(LOG_TAG, e + " " + "onRegistrationConnected() - Skipping " +
- "callback.");
+ Log.w(LOG_TAG, e + "onRegistered(int, Set) - Skipping callback.");
}
});
}
@@ -213,17 +223,24 @@ public class ImsRegistrationImplBase {
/**
* Notify the framework that the device is trying to connect the IMS network.
*
- * @param imsRadioTech the radio access technology. Valid values are defined as
- * {@link #REGISTRATION_TECH_LTE} and {@link #REGISTRATION_TECH_IWLAN}.
+ * @param imsRadioTech the radio access technology.
*/
public final void onRegistering(@ImsRegistrationTech int imsRadioTech) {
- updateToState(imsRadioTech, RegistrationManager.REGISTRATION_STATE_REGISTERING);
+ onRegistering(new ImsRegistrationAttributes.Builder(imsRadioTech).build());
+ }
+
+ /**
+ * Notify the framework that the device is trying to connect the IMS network.
+ *
+ * @param attributes The attributes associated with the IMS registration.
+ */
+ public final void onRegistering(@NonNull ImsRegistrationAttributes attributes) {
+ updateToState(attributes, RegistrationManager.REGISTRATION_STATE_REGISTERING);
mCallbacks.broadcastAction((c) -> {
try {
- c.onRegistering(imsRadioTech);
+ c.onRegistering(attributes);
} catch (RemoteException e) {
- Log.w(LOG_TAG, e + " " + "onRegistrationProcessing() - Skipping " +
- "callback.");
+ Log.w(LOG_TAG, e + "onRegistering(int, Set) - Skipping callback.");
}
});
}
@@ -252,8 +269,7 @@ public class ImsRegistrationImplBase {
try {
c.onDeregistered(reasonInfo);
} catch (RemoteException e) {
- Log.w(LOG_TAG, e + " " + "onRegistrationDisconnected() - Skipping " +
- "callback.");
+ Log.w(LOG_TAG, e + "onDeregistered() - Skipping callback.");
}
});
}
@@ -272,8 +288,7 @@ public class ImsRegistrationImplBase {
try {
c.onTechnologyChangeFailed(imsRadioTech, reasonInfo);
} catch (RemoteException e) {
- Log.w(LOG_TAG, e + " " + "onRegistrationChangeFailed() - Skipping " +
- "callback.");
+ Log.w(LOG_TAG, e + "onTechnologyChangeFailed() - Skipping callback.");
}
});
}
@@ -297,14 +312,13 @@ public class ImsRegistrationImplBase {
try {
callback.onSubscriberAssociatedUriChanged(uris);
} catch (RemoteException e) {
- Log.w(LOG_TAG, e + " " + "onSubscriberAssociatedUriChanged() - Skipping "
- + "callback.");
+ Log.w(LOG_TAG, e + "onSubscriberAssociatedUriChanged() - Skipping callback.");
}
}
- private void updateToState(@ImsRegistrationTech int connType, int newState) {
+ private void updateToState(ImsRegistrationAttributes attributes, int newState) {
synchronized (mLock) {
- mConnectionType = connType;
+ mRegistrationAttributes = attributes;
mRegistrationState = newState;
mLastDisconnectCause = null;
}
@@ -316,7 +330,7 @@ public class ImsRegistrationImplBase {
mUrisSet = false;
mUris = null;
- updateToState(REGISTRATION_TECH_NONE,
+ updateToState(new ImsRegistrationAttributes.Builder(REGISTRATION_TECH_NONE).build(),
RegistrationManager.REGISTRATION_STATE_NOT_REGISTERED);
if (info != null) {
mLastDisconnectCause = info;
@@ -328,29 +342,19 @@ public class ImsRegistrationImplBase {
}
/**
- * @return the current registration connection type. Valid values are
- * {@link #REGISTRATION_TECH_LTE} and {@link #REGISTRATION_TECH_IWLAN}
- * @hide
- */
- @VisibleForTesting
- public final @ImsRegistrationTech int getConnectionType() {
- synchronized (mLock) {
- return mConnectionType;
- }
- }
-
- /**
* @param c the newly registered callback that will be updated with the current registration
* state.
*/
private void updateNewCallbackWithState(IImsRegistrationCallback c)
throws RemoteException {
int state;
+ ImsRegistrationAttributes attributes;
ImsReasonInfo disconnectInfo;
boolean urisSet;
Uri[] uris;
synchronized (mLock) {
state = mRegistrationState;
+ attributes = mRegistrationAttributes;
disconnectInfo = mLastDisconnectCause;
urisSet = mUrisSet;
uris = mUris;
@@ -361,11 +365,11 @@ public class ImsRegistrationImplBase {
break;
}
case RegistrationManager.REGISTRATION_STATE_REGISTERING: {
- c.onRegistering(getConnectionType());
+ c.onRegistering(attributes);
break;
}
case RegistrationManager.REGISTRATION_STATE_REGISTERED: {
- c.onRegistered(getConnectionType());
+ c.onRegistered(attributes);
break;
}
case REGISTRATION_STATE_UNKNOWN: {
diff --git a/tests/ApkVerityTest/OWNERS b/tests/ApkVerityTest/OWNERS
new file mode 100644
index 000000000000..d67285ede44a
--- /dev/null
+++ b/tests/ApkVerityTest/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 36824
+
+victorhsieh@google.com
diff --git a/tests/PlatformCompatGating/src/com/android/tests/gating/PlatformCompatCommandNotInstalledTest.kt b/tests/PlatformCompatGating/src/com/android/tests/gating/PlatformCompatCommandNotInstalledTest.kt
index eb04f6907748..ac9e6817a230 100644
--- a/tests/PlatformCompatGating/src/com/android/tests/gating/PlatformCompatCommandNotInstalledTest.kt
+++ b/tests/PlatformCompatGating/src/com/android/tests/gating/PlatformCompatCommandNotInstalledTest.kt
@@ -76,11 +76,11 @@ class PlatformCompatCommandNotInstalledTest {
Params(enableDisable = null, targetSdk = 29, result = false),
Params(enableDisable = null, targetSdk = 30, result = true),
- Params(enableDisable = true, targetSdk = 29, result = true),
+ Params(enableDisable = true, targetSdk = 29, result = false),
Params(enableDisable = true, targetSdk = 30, result = true),
Params(enableDisable = false, targetSdk = 29, result = false),
- Params(enableDisable = false, targetSdk = 30, result = false)
+ Params(enableDisable = false, targetSdk = 30, result = true)
)
}
diff --git a/tests/net/AndroidManifest.xml b/tests/net/AndroidManifest.xml
index 009f817af407..d08b2f8d40dd 100644
--- a/tests/net/AndroidManifest.xml
+++ b/tests/net/AndroidManifest.xml
@@ -48,6 +48,7 @@
<uses-permission android:name="android.permission.OBSERVE_NETWORK_POLICY" />
<uses-permission android:name="android.permission.NETWORK_FACTORY" />
<uses-permission android:name="android.permission.NETWORK_STATS_PROVIDER" />
+ <uses-permission android:name="android.permission.CONTROL_OEM_PAID_NETWORK_PREFERENCE" />
<application>
<uses-library android:name="android.test.runner" />
diff --git a/tests/net/common/java/android/net/CaptivePortalDataTest.kt b/tests/net/common/java/android/net/CaptivePortalDataTest.kt
index b2bcfeb9019d..ad5bbf220d57 100644
--- a/tests/net/common/java/android/net/CaptivePortalDataTest.kt
+++ b/tests/net/common/java/android/net/CaptivePortalDataTest.kt
@@ -54,12 +54,26 @@ class CaptivePortalDataTest {
}
.build()
+ private val dataFromPasspoint = CaptivePortalData.Builder()
+ .setUserPortalUrl(Uri.parse("https://tc.example.com/passpoint"),
+ CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT)
+ .setVenueInfoUrl(Uri.parse("https://venue.example.com/passpoint"),
+ CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT)
+ .setCaptive(true)
+ .apply {
+ if (SdkLevel.isAtLeastS()) {
+ setVenueFriendlyName("venue friendly name")
+ }
+ }
+ .build()
+
private fun makeBuilder() = CaptivePortalData.Builder(data)
@Test
fun testParcelUnparcel() {
- val fieldCount = if (SdkLevel.isAtLeastS()) 8 else 7
+ val fieldCount = if (SdkLevel.isAtLeastS()) 10 else 7
assertParcelSane(data, fieldCount)
+ assertParcelSane(dataFromPasspoint, fieldCount)
assertParcelingIsLossless(makeBuilder().setUserPortalUrl(null).build())
assertParcelingIsLossless(makeBuilder().setVenueInfoUrl(null).build())
@@ -83,6 +97,27 @@ class CaptivePortalDataTest {
assertNotEqualsAfterChange { it.setVenueFriendlyName("another friendly name") }
assertNotEqualsAfterChange { it.setVenueFriendlyName(null) }
}
+
+ assertEquals(dataFromPasspoint, CaptivePortalData.Builder(dataFromPasspoint).build())
+ assertNotEqualsAfterChange { it.setUserPortalUrl(
+ Uri.parse("https://tc.example.com/passpoint")) }
+ assertNotEqualsAfterChange { it.setUserPortalUrl(
+ Uri.parse("https://tc.example.com/passpoint"),
+ CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_OTHER) }
+ assertNotEqualsAfterChange { it.setUserPortalUrl(
+ Uri.parse("https://tc.example.com/other"),
+ CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT) }
+ assertNotEqualsAfterChange { it.setUserPortalUrl(
+ Uri.parse("https://tc.example.com/passpoint"),
+ CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_OTHER) }
+ assertNotEqualsAfterChange { it.setVenueInfoUrl(
+ Uri.parse("https://venue.example.com/passpoint")) }
+ assertNotEqualsAfterChange { it.setVenueInfoUrl(
+ Uri.parse("https://venue.example.com/other"),
+ CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT) }
+ assertNotEqualsAfterChange { it.setVenueInfoUrl(
+ Uri.parse("https://venue.example.com/passpoint"),
+ CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_OTHER) }
}
@Test
@@ -130,6 +165,22 @@ class CaptivePortalDataTest {
assertEquals("venue friendly name", data.venueFriendlyName)
}
+ @Test @IgnoreUpTo(Build.VERSION_CODES.R)
+ fun testGetVenueInfoUrlSource() {
+ assertEquals(CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_OTHER,
+ data.venueInfoUrlSource)
+ assertEquals(CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT,
+ dataFromPasspoint.venueInfoUrlSource)
+ }
+
+ @Test @IgnoreUpTo(Build.VERSION_CODES.R)
+ fun testGetUserPortalUrlSource() {
+ assertEquals(CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_OTHER,
+ data.userPortalUrlSource)
+ assertEquals(CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT,
+ dataFromPasspoint.userPortalUrlSource)
+ }
+
private fun CaptivePortalData.mutate(mutator: (CaptivePortalData.Builder) -> Unit) =
CaptivePortalData.Builder(this).apply { mutator(this) }.build()
diff --git a/tests/net/common/java/android/net/OemNetworkPreferencesTest.java b/tests/net/common/java/android/net/OemNetworkPreferencesTest.java
index d232a507454d..fd29a9539de8 100644
--- a/tests/net/common/java/android/net/OemNetworkPreferencesTest.java
+++ b/tests/net/common/java/android/net/OemNetworkPreferencesTest.java
@@ -40,7 +40,7 @@ import java.util.Map;
@SmallTest
public class OemNetworkPreferencesTest {
- private static final int TEST_PREF = OemNetworkPreferences.OEM_NETWORK_PREFERENCE_DEFAULT;
+ private static final int TEST_PREF = OemNetworkPreferences.OEM_NETWORK_PREFERENCE_UNINITIALIZED;
private static final String TEST_PACKAGE = "com.google.apps.contacts";
private final OemNetworkPreferences.Builder mBuilder = new OemNetworkPreferences.Builder();
@@ -54,7 +54,7 @@ public class OemNetworkPreferencesTest {
@Test
public void testBuilderRemoveNetworkPreferenceRequiresNonNullPackageName() {
assertThrows(NullPointerException.class,
- () -> mBuilder.removeNetworkPreference(null));
+ () -> mBuilder.clearNetworkPreference(null));
}
@Test
@@ -129,7 +129,7 @@ public class OemNetworkPreferencesTest {
assertTrue(networkPreferences.containsKey(TEST_PACKAGE));
- mBuilder.removeNetworkPreference(TEST_PACKAGE);
+ mBuilder.clearNetworkPreference(TEST_PACKAGE);
networkPreferences = mBuilder.build().getNetworkPreferences();
assertFalse(networkPreferences.containsKey(TEST_PACKAGE));
diff --git a/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java b/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java
index e1da3d0ae2b3..dc9e587332cb 100644
--- a/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java
+++ b/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java
@@ -17,7 +17,6 @@
package com.android.server;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET;
@@ -85,7 +84,6 @@ public class NetworkAgentWrapper implements TestableNetworkCallback.HasNetwork {
final String typeName = ConnectivityManager.getNetworkTypeName(type);
mNetworkCapabilities = (ncTemplate != null) ? ncTemplate : new NetworkCapabilities();
mNetworkCapabilities.addCapability(NET_CAPABILITY_NOT_SUSPENDED);
- mNetworkCapabilities.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
mNetworkCapabilities.addTransportType(transport);
switch (transport) {
case TRANSPORT_ETHERNET:
diff --git a/tests/net/java/android/net/ConnectivityManagerTest.java b/tests/net/java/android/net/ConnectivityManagerTest.java
index fcfb4aa9b864..6a09b0237a38 100644
--- a/tests/net/java/android/net/ConnectivityManagerTest.java
+++ b/tests/net/java/android/net/ConnectivityManagerTest.java
@@ -35,6 +35,7 @@ import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
import static android.net.NetworkRequest.Type.BACKGROUND_REQUEST;
import static android.net.NetworkRequest.Type.REQUEST;
import static android.net.NetworkRequest.Type.TRACK_DEFAULT;
+import static android.net.NetworkRequest.Type.TRACK_SYSTEM_DEFAULT;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
@@ -329,6 +330,9 @@ public class ConnectivityManagerTest {
mustFail(() -> { manager.registerDefaultNetworkCallback(null, handler); });
mustFail(() -> { manager.registerDefaultNetworkCallback(callback, null); });
+ mustFail(() -> { manager.registerSystemDefaultNetworkCallback(null, handler); });
+ mustFail(() -> { manager.registerSystemDefaultNetworkCallback(callback, null); });
+
mustFail(() -> { manager.unregisterNetworkCallback(nullCallback); });
mustFail(() -> { manager.unregisterNetworkCallback(nullIntent); });
mustFail(() -> { manager.releaseNetworkRequest(nullIntent); });
@@ -377,6 +381,13 @@ public class ConnectivityManagerTest {
eq(BACKGROUND_REQUEST.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE),
eq(testPkgName), eq(testAttributionTag));
reset(mService);
+
+ Handler handler = new Handler(ConnectivityThread.getInstanceLooper());
+ manager.registerSystemDefaultNetworkCallback(callback, handler);
+ verify(mService).requestNetwork(eq(null),
+ eq(TRACK_SYSTEM_DEFAULT.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE),
+ eq(testPkgName), eq(testAttributionTag));
+ reset(mService);
}
static Message makeMessage(NetworkRequest req, int messageType) {
diff --git a/tests/net/java/android/net/VpnManagerTest.java b/tests/net/java/android/net/VpnManagerTest.java
index 95a794235a2e..c548e30761c9 100644
--- a/tests/net/java/android/net/VpnManagerTest.java
+++ b/tests/net/java/android/net/VpnManagerTest.java
@@ -49,7 +49,7 @@ public class VpnManagerTest {
private static final String IDENTITY_STRING = "Identity";
private static final byte[] PSK_BYTES = "preSharedKey".getBytes();
- private IConnectivityManager mMockCs;
+ private IVpnManager mMockService;
private VpnManager mVpnManager;
private final MockContext mMockContext =
new MockContext() {
@@ -61,24 +61,26 @@ public class VpnManagerTest {
@Before
public void setUp() throws Exception {
- mMockCs = mock(IConnectivityManager.class);
- mVpnManager = new VpnManager(mMockContext, mMockCs);
+ mMockService = mock(IVpnManager.class);
+ mVpnManager = new VpnManager(mMockContext, mMockService);
}
@Test
public void testProvisionVpnProfilePreconsented() throws Exception {
final PlatformVpnProfile profile = getPlatformVpnProfile();
- when(mMockCs.provisionVpnProfile(any(VpnProfile.class), eq(PKG_NAME))).thenReturn(true);
+ when(mMockService.provisionVpnProfile(any(VpnProfile.class), eq(PKG_NAME)))
+ .thenReturn(true);
// Expect there to be no intent returned, as consent has already been granted.
assertNull(mVpnManager.provisionVpnProfile(profile));
- verify(mMockCs).provisionVpnProfile(eq(profile.toVpnProfile()), eq(PKG_NAME));
+ verify(mMockService).provisionVpnProfile(eq(profile.toVpnProfile()), eq(PKG_NAME));
}
@Test
public void testProvisionVpnProfileNeedsConsent() throws Exception {
final PlatformVpnProfile profile = getPlatformVpnProfile();
- when(mMockCs.provisionVpnProfile(any(VpnProfile.class), eq(PKG_NAME))).thenReturn(false);
+ when(mMockService.provisionVpnProfile(any(VpnProfile.class), eq(PKG_NAME)))
+ .thenReturn(false);
// Expect intent to be returned, as consent has not already been granted.
final Intent intent = mVpnManager.provisionVpnProfile(profile);
@@ -88,25 +90,25 @@ public class VpnManagerTest {
ComponentName.unflattenFromString(
"com.android.vpndialogs/com.android.vpndialogs.PlatformVpnConfirmDialog");
assertEquals(expectedComponentName, intent.getComponent());
- verify(mMockCs).provisionVpnProfile(eq(profile.toVpnProfile()), eq(PKG_NAME));
+ verify(mMockService).provisionVpnProfile(eq(profile.toVpnProfile()), eq(PKG_NAME));
}
@Test
public void testDeleteProvisionedVpnProfile() throws Exception {
mVpnManager.deleteProvisionedVpnProfile();
- verify(mMockCs).deleteVpnProfile(eq(PKG_NAME));
+ verify(mMockService).deleteVpnProfile(eq(PKG_NAME));
}
@Test
public void testStartProvisionedVpnProfile() throws Exception {
mVpnManager.startProvisionedVpnProfile();
- verify(mMockCs).startVpnProfile(eq(PKG_NAME));
+ verify(mMockService).startVpnProfile(eq(PKG_NAME));
}
@Test
public void testStopProvisionedVpnProfile() throws Exception {
mVpnManager.stopProvisionedVpnProfile();
- verify(mMockCs).stopVpnProfile(eq(PKG_NAME));
+ verify(mMockService).stopVpnProfile(eq(PKG_NAME));
}
private Ikev2VpnProfile getPlatformVpnProfile() throws Exception {
diff --git a/tests/net/java/android/net/VpnTransportInfoTest.java b/tests/net/java/android/net/VpnTransportInfoTest.java
new file mode 100644
index 000000000000..866f38c84333
--- /dev/null
+++ b/tests/net/java/android/net/VpnTransportInfoTest.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2010 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 com.android.testutils.ParcelUtils.assertParcelSane;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class VpnTransportInfoTest {
+
+ @Test
+ public void testParceling() {
+ VpnTransportInfo v = new VpnTransportInfo(VpnManager.TYPE_VPN_PLATFORM);
+ assertParcelSane(v, 1 /* fieldCount */);
+ }
+
+ @Test
+ public void testEqualsAndHashCode() {
+ VpnTransportInfo v1 = new VpnTransportInfo(VpnManager.TYPE_VPN_PLATFORM);
+ VpnTransportInfo v2 = new VpnTransportInfo(VpnManager.TYPE_VPN_SERVICE);
+ VpnTransportInfo v3 = new VpnTransportInfo(VpnManager.TYPE_VPN_PLATFORM);
+ assertNotEquals(v1, v2);
+ assertEquals(v1, v3);
+ assertEquals(v1.hashCode(), v3.hashCode());
+ }
+} \ No newline at end of file
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index edc2c636e0ee..a84e2f15657c 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -200,11 +200,13 @@ import android.net.ResolverParamsParcel;
import android.net.RouteInfo;
import android.net.RouteInfoParcel;
import android.net.SocketKeepalive;
+import android.net.TransportInfo;
import android.net.UidRange;
import android.net.UidRangeParcel;
import android.net.UnderlyingNetworkInfo;
import android.net.Uri;
import android.net.VpnManager;
+import android.net.VpnTransportInfo;
import android.net.metrics.IpConnectivityLog;
import android.net.shared.NetworkMonitorUtils;
import android.net.shared.PrivateDnsConfig;
@@ -361,13 +363,21 @@ public class ConnectivityServiceTest {
private static final String INTERFACE_NAME = "interface";
- private static final String TEST_VENUE_URL_NA = "https://android.com/";
+ private static final String TEST_VENUE_URL_NA_PASSPOINT = "https://android.com/";
+ private static final String TEST_VENUE_URL_NA_OTHER = "https://example.com/";
+ private static final String TEST_TERMS_AND_CONDITIONS_URL_NA_PASSPOINT =
+ "https://android.com/terms/";
+ private static final String TEST_TERMS_AND_CONDITIONS_URL_NA_OTHER =
+ "https://example.com/terms/";
private static final String TEST_VENUE_URL_CAPPORT = "https://android.com/capport/";
+ private static final String TEST_USER_PORTAL_API_URL_CAPPORT =
+ "https://android.com/user/api/capport/";
private static final String TEST_FRIENDLY_NAME = "Network friendly name";
private static final String TEST_REDIRECT_URL = "http://example.com/firstPath";
private MockContext mServiceContext;
private HandlerThread mCsHandlerThread;
+ private HandlerThread mVMSHandlerThread;
private ConnectivityService.Dependencies mDeps;
private ConnectivityService mService;
private WrappedConnectivityManager mCm;
@@ -382,6 +392,7 @@ public class ConnectivityServiceTest {
private TestNetIdManager mNetIdManager;
private QosCallbackMockHelper mQosCallbackMockHelper;
private QosCallbackTracker mQosCallbackTracker;
+ private VpnManagerService mVpnManagerService;
// State variables required to emulate NetworkPolicyManagerService behaviour.
private int mUidRules = RULE_NONE;
@@ -1110,7 +1121,7 @@ public class ConnectivityServiceTest {
}
@Override
- public int getActiveAppVpnType() {
+ public int getActiveVpnType() {
return mVpnType;
}
@@ -1123,10 +1134,12 @@ public class ConnectivityServiceTest {
private void registerAgent(boolean isAlwaysMetered, Set<UidRange> uids, LinkProperties lp)
throws Exception {
if (mAgentRegistered) throw new IllegalStateException("already registered");
+ updateState(NetworkInfo.DetailedState.CONNECTING, "registerAgent");
mConfig = new VpnConfig();
setUids(uids);
if (!isAlwaysMetered) mNetworkCapabilities.addCapability(NET_CAPABILITY_NOT_METERED);
mInterface = VPN_IFNAME;
+ mNetworkCapabilities.setTransportInfo(new VpnTransportInfo(getActiveVpnType()));
mMockNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN, lp,
mNetworkCapabilities);
mMockNetworkAgent.waitForIdle(TIMEOUT_MS);
@@ -1252,24 +1265,55 @@ public class ConnectivityServiceTest {
r -> new UidRangeParcel(r.start, r.stop)).toArray(UidRangeParcel[]::new);
}
- private void mockVpn(int uid) {
- synchronized (mService.mVpns) {
- int userId = UserHandle.getUserId(uid);
- mMockVpn = new MockVpn(userId);
- // This has no effect unless the VPN is actually connected, because things like
- // getActiveNetworkForUidInternal call getNetworkAgentInfoForNetId on the VPN
- // netId, and check if that network is actually connected.
- mService.mVpns.put(userId, mMockVpn);
- }
+ private VpnManagerService makeVpnManagerService() {
+ final VpnManagerService.Dependencies deps = new VpnManagerService.Dependencies() {
+ public int getCallingUid() {
+ return mDeps.getCallingUid();
+ }
+
+ public HandlerThread makeHandlerThread() {
+ return mVMSHandlerThread;
+ }
+
+ public KeyStore getKeyStore() {
+ return mKeyStore;
+ }
+
+ public INetd getNetd() {
+ return mMockNetd;
+ }
+
+ public INetworkManagementService getINetworkManagementService() {
+ return mNetworkManagementService;
+ }
+ };
+ return new VpnManagerService(mServiceContext, deps);
+ }
+
+ private void assertVpnTransportInfo(NetworkCapabilities nc, int type) {
+ assertNotNull(nc);
+ final TransportInfo ti = nc.getTransportInfo();
+ assertTrue("VPN TransportInfo is not a VpnTransportInfo: " + ti,
+ ti instanceof VpnTransportInfo);
+ assertEquals(type, ((VpnTransportInfo) ti).type);
+
}
private void processBroadcastForVpn(Intent intent) {
- // The BroadcastReceiver for this broadcast checks it is being run on the handler thread.
- final Handler handler = new Handler(mCsHandlerThread.getLooper());
- handler.post(() -> mServiceContext.sendBroadcast(intent));
+ mServiceContext.sendBroadcast(intent);
+ HandlerUtils.waitForIdle(mVMSHandlerThread, TIMEOUT_MS);
waitForIdle();
}
+ private void mockVpn(int uid) {
+ synchronized (mVpnManagerService.mVpns) {
+ int userId = UserHandle.getUserId(uid);
+ mMockVpn = new MockVpn(userId);
+ // Every running user always has a Vpn in the mVpns array, even if no VPN is running.
+ mVpnManagerService.mVpns.put(userId, mMockVpn);
+ }
+ }
+
private void mockUidNetworkingBlocked() {
doAnswer(i -> mContext.getSystemService(NetworkPolicyManager.class)
.checkUidNetworkingBlocked(i.getArgument(0) /* uid */, mUidRules,
@@ -1384,6 +1428,7 @@ public class ConnectivityServiceTest {
FakeSettingsProvider.clearSettingsProvider();
mServiceContext = new MockContext(InstrumentationRegistry.getContext(),
new FakeSettingsProvider());
+ mServiceContext.setUseRegisteredHandlers(true);
LocalServices.removeServiceForTest(NetworkPolicyManagerInternal.class);
LocalServices.addService(
NetworkPolicyManagerInternal.class, mock(NetworkPolicyManagerInternal.class));
@@ -1393,6 +1438,7 @@ public class ConnectivityServiceTest {
initAlarmManager(mAlarmManager, mAlarmManagerThread.getThreadHandler());
mCsHandlerThread = new HandlerThread("TestConnectivityService");
+ mVMSHandlerThread = new HandlerThread("TestVpnManagerService");
mDeps = makeDependencies();
returnRealCallingUid();
mService = new ConnectivityService(mServiceContext,
@@ -1415,6 +1461,8 @@ public class ConnectivityServiceTest {
// getSystemService() correctly.
mCm = new WrappedConnectivityManager(InstrumentationRegistry.getContext(), mService);
mService.systemReadyInternal();
+ mVpnManagerService = makeVpnManagerService();
+ mVpnManagerService.systemReady();
mockVpn(Process.myUid());
mCm.bindProcessToNetwork(null);
mQosCallbackTracker = mock(QosCallbackTracker.class);
@@ -1442,7 +1490,6 @@ public class ConnectivityServiceTest {
doReturn(mock(ProxyTracker.class)).when(deps).makeProxyTracker(any(), any());
doReturn(true).when(deps).queryUserAccess(anyInt(), anyInt());
doReturn(mBatteryStatsService).when(deps).getBatteryStatsService();
- doReturn(mKeyStore).when(deps).getKeyStore();
doAnswer(inv -> {
mPolicyTracker = new WrappedMultinetworkPolicyTracker(
inv.getArgument(0), inv.getArgument(1), inv.getArgument(2));
@@ -2707,10 +2754,6 @@ public class ConnectivityServiceTest {
NetworkCapabilities filter = new NetworkCapabilities();
filter.addCapability(capability);
- // Add NOT_VCN_MANAGED capability into filter unconditionally since some request will add
- // NOT_VCN_MANAGED automatically but not for NetworkCapabilities,
- // see {@code NetworkCapabilities#deduceNotVcnManagedCapability} for more details.
- filter.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
final HandlerThread handlerThread = new HandlerThread("testNetworkFactoryRequests");
handlerThread.start();
final MockNetworkFactory testFactory = new MockNetworkFactory(handlerThread.getLooper(),
@@ -3286,39 +3329,68 @@ public class ConnectivityServiceTest {
}
private class CaptivePortalTestData {
- CaptivePortalTestData(CaptivePortalData naData, CaptivePortalData capportData,
- CaptivePortalData expectedMergedData) {
- mNaData = naData;
+ CaptivePortalTestData(CaptivePortalData naPasspointData, CaptivePortalData capportData,
+ CaptivePortalData naOtherData, CaptivePortalData expectedMergedPasspointData,
+ CaptivePortalData expectedMergedOtherData) {
+ mNaPasspointData = naPasspointData;
mCapportData = capportData;
- mExpectedMergedData = expectedMergedData;
+ mNaOtherData = naOtherData;
+ mExpectedMergedPasspointData = expectedMergedPasspointData;
+ mExpectedMergedOtherData = expectedMergedOtherData;
}
- public final CaptivePortalData mNaData;
+ public final CaptivePortalData mNaPasspointData;
public final CaptivePortalData mCapportData;
- public final CaptivePortalData mExpectedMergedData;
+ public final CaptivePortalData mNaOtherData;
+ public final CaptivePortalData mExpectedMergedPasspointData;
+ public final CaptivePortalData mExpectedMergedOtherData;
+
}
private CaptivePortalTestData setupCaptivePortalData() {
final CaptivePortalData capportData = new CaptivePortalData.Builder()
.setUserPortalUrl(Uri.parse(TEST_REDIRECT_URL))
.setVenueInfoUrl(Uri.parse(TEST_VENUE_URL_CAPPORT))
+ .setUserPortalUrl(Uri.parse(TEST_USER_PORTAL_API_URL_CAPPORT))
.setExpiryTime(1000000L)
.setBytesRemaining(12345L)
.build();
- final CaptivePortalData naData = new CaptivePortalData.Builder()
+ final CaptivePortalData naPasspointData = new CaptivePortalData.Builder()
+ .setBytesRemaining(80802L)
+ .setVenueInfoUrl(Uri.parse(TEST_VENUE_URL_NA_PASSPOINT),
+ CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT)
+ .setUserPortalUrl(Uri.parse(TEST_TERMS_AND_CONDITIONS_URL_NA_PASSPOINT),
+ CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT)
+ .setVenueFriendlyName(TEST_FRIENDLY_NAME).build();
+
+ final CaptivePortalData naOtherData = new CaptivePortalData.Builder()
.setBytesRemaining(80802L)
- .setVenueInfoUrl(Uri.parse(TEST_VENUE_URL_NA))
+ .setVenueInfoUrl(Uri.parse(TEST_VENUE_URL_NA_OTHER),
+ CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_OTHER)
+ .setUserPortalUrl(Uri.parse(TEST_TERMS_AND_CONDITIONS_URL_NA_OTHER),
+ CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_OTHER)
.setVenueFriendlyName(TEST_FRIENDLY_NAME).build();
- final CaptivePortalData expectedMergedData = new CaptivePortalData.Builder()
+ final CaptivePortalData expectedMergedPasspointData = new CaptivePortalData.Builder()
.setUserPortalUrl(Uri.parse(TEST_REDIRECT_URL))
.setBytesRemaining(12345L)
.setExpiryTime(1000000L)
- .setVenueInfoUrl(Uri.parse(TEST_VENUE_URL_NA))
+ .setVenueInfoUrl(Uri.parse(TEST_VENUE_URL_NA_PASSPOINT),
+ CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT)
+ .setUserPortalUrl(Uri.parse(TEST_TERMS_AND_CONDITIONS_URL_NA_PASSPOINT),
+ CaptivePortalData.CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT)
.setVenueFriendlyName(TEST_FRIENDLY_NAME).build();
- return new CaptivePortalTestData(naData, capportData, expectedMergedData);
+ final CaptivePortalData expectedMergedOtherData = new CaptivePortalData.Builder()
+ .setUserPortalUrl(Uri.parse(TEST_REDIRECT_URL))
+ .setBytesRemaining(12345L)
+ .setExpiryTime(1000000L)
+ .setVenueInfoUrl(Uri.parse(TEST_VENUE_URL_CAPPORT))
+ .setUserPortalUrl(Uri.parse(TEST_USER_PORTAL_API_URL_CAPPORT))
+ .setVenueFriendlyName(TEST_FRIENDLY_NAME).build();
+ return new CaptivePortalTestData(naPasspointData, capportData, naOtherData,
+ expectedMergedPasspointData, expectedMergedOtherData);
}
@Test
@@ -3332,15 +3404,26 @@ public class ConnectivityServiceTest {
captivePortalCallback.expectLinkPropertiesThat(mWiFiNetworkAgent,
lp -> captivePortalTestData.mCapportData.equals(lp.getCaptivePortalData()));
- // Venue URL and friendly name from Network agent, confirm that API data gets precedence
- // on the bytes remaining.
+ // Venue URL, T&C URL and friendly name from Network agent with Passpoint source, confirm
+ // that API data gets precedence on the bytes remaining.
final LinkProperties linkProperties = new LinkProperties();
- linkProperties.setCaptivePortalData(captivePortalTestData.mNaData);
+ linkProperties.setCaptivePortalData(captivePortalTestData.mNaPasspointData);
+ mWiFiNetworkAgent.sendLinkProperties(linkProperties);
+
+ // Make sure that the capport data is merged
+ captivePortalCallback.expectLinkPropertiesThat(mWiFiNetworkAgent,
+ lp -> captivePortalTestData.mExpectedMergedPasspointData
+ .equals(lp.getCaptivePortalData()));
+
+ // Now send this information from non-Passpoint source, confirm that Capport data takes
+ // precedence
+ linkProperties.setCaptivePortalData(captivePortalTestData.mNaOtherData);
mWiFiNetworkAgent.sendLinkProperties(linkProperties);
// Make sure that the capport data is merged
captivePortalCallback.expectLinkPropertiesThat(mWiFiNetworkAgent,
- lp -> captivePortalTestData.mExpectedMergedData.equals(lp.getCaptivePortalData()));
+ lp -> captivePortalTestData.mExpectedMergedOtherData
+ .equals(lp.getCaptivePortalData()));
// Create a new LP with no Network agent capport data
final LinkProperties newLps = new LinkProperties();
@@ -3357,12 +3440,12 @@ public class ConnectivityServiceTest {
captivePortalCallback.expectLinkPropertiesThat(mWiFiNetworkAgent,
lp -> lp.getCaptivePortalData() == null);
- newLps.setCaptivePortalData(captivePortalTestData.mNaData);
+ newLps.setCaptivePortalData(captivePortalTestData.mNaPasspointData);
mWiFiNetworkAgent.sendLinkProperties(newLps);
// Make sure that only the network agent capport data is available
captivePortalCallback.expectLinkPropertiesThat(mWiFiNetworkAgent,
- lp -> captivePortalTestData.mNaData.equals(lp.getCaptivePortalData()));
+ lp -> captivePortalTestData.mNaPasspointData.equals(lp.getCaptivePortalData()));
}
@Test
@@ -3373,12 +3456,12 @@ public class ConnectivityServiceTest {
// Venue URL and friendly name from Network agent, confirm that API data gets precedence
// on the bytes remaining.
final LinkProperties linkProperties = new LinkProperties();
- linkProperties.setCaptivePortalData(captivePortalTestData.mNaData);
+ linkProperties.setCaptivePortalData(captivePortalTestData.mNaPasspointData);
mWiFiNetworkAgent.sendLinkProperties(linkProperties);
// Make sure that the data is saved correctly
captivePortalCallback.expectLinkPropertiesThat(mWiFiNetworkAgent,
- lp -> captivePortalTestData.mNaData.equals(lp.getCaptivePortalData()));
+ lp -> captivePortalTestData.mNaPasspointData.equals(lp.getCaptivePortalData()));
// Expected merged data: Network agent data is preferred, and values that are not used by
// it are merged from capport data
@@ -3386,7 +3469,8 @@ public class ConnectivityServiceTest {
// Make sure that the Capport data is merged correctly
captivePortalCallback.expectLinkPropertiesThat(mWiFiNetworkAgent,
- lp -> captivePortalTestData.mExpectedMergedData.equals(lp.getCaptivePortalData()));
+ lp -> captivePortalTestData.mExpectedMergedPasspointData.equals(
+ lp.getCaptivePortalData()));
// Now set the naData to null
linkProperties.setCaptivePortalData(null);
@@ -3397,6 +3481,32 @@ public class ConnectivityServiceTest {
lp -> captivePortalTestData.mCapportData.equals(lp.getCaptivePortalData()));
}
+ @Test
+ public void testMergeCaptivePortalDataFromNetworkAgentOtherSourceFirstThenCapport()
+ throws Exception {
+ final TestNetworkCallback captivePortalCallback = setupNetworkCallbackAndConnectToWifi();
+ final CaptivePortalTestData captivePortalTestData = setupCaptivePortalData();
+
+ // Venue URL and friendly name from Network agent, confirm that API data gets precedence
+ // on the bytes remaining.
+ final LinkProperties linkProperties = new LinkProperties();
+ linkProperties.setCaptivePortalData(captivePortalTestData.mNaOtherData);
+ mWiFiNetworkAgent.sendLinkProperties(linkProperties);
+
+ // Make sure that the data is saved correctly
+ captivePortalCallback.expectLinkPropertiesThat(mWiFiNetworkAgent,
+ lp -> captivePortalTestData.mNaOtherData.equals(lp.getCaptivePortalData()));
+
+ // Expected merged data: Network agent data is preferred, and values that are not used by
+ // it are merged from capport data
+ mWiFiNetworkAgent.notifyCapportApiDataChanged(captivePortalTestData.mCapportData);
+
+ // Make sure that the Capport data is merged correctly
+ captivePortalCallback.expectLinkPropertiesThat(mWiFiNetworkAgent,
+ lp -> captivePortalTestData.mExpectedMergedOtherData.equals(
+ lp.getCaptivePortalData()));
+ }
+
private NetworkRequest.Builder newWifiRequestBuilder() {
return new NetworkRequest.Builder().addTransportType(TRANSPORT_WIFI);
}
@@ -3649,10 +3759,19 @@ public class ConnectivityServiceTest {
@Test
public void testRegisterDefaultNetworkCallback() throws Exception {
+ // NETWORK_SETTINGS is necessary to call registerSystemDefaultNetworkCallback.
+ mServiceContext.setPermission(Manifest.permission.NETWORK_SETTINGS,
+ PERMISSION_GRANTED);
+
final TestNetworkCallback defaultNetworkCallback = new TestNetworkCallback();
mCm.registerDefaultNetworkCallback(defaultNetworkCallback);
defaultNetworkCallback.assertNoCallback();
+ final Handler handler = new Handler(ConnectivityThread.getInstanceLooper());
+ final TestNetworkCallback systemDefaultCallback = new TestNetworkCallback();
+ mCm.registerSystemDefaultNetworkCallback(systemDefaultCallback, handler);
+ systemDefaultCallback.assertNoCallback();
+
// Create a TRANSPORT_CELLULAR request to keep the mobile interface up
// whenever Wi-Fi is up. Without this, the mobile network agent is
// reaped before any other activity can take place.
@@ -3667,27 +3786,35 @@ public class ConnectivityServiceTest {
mCellNetworkAgent.connect(true);
cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
defaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+ systemDefaultCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
assertEquals(defaultNetworkCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
+ assertEquals(systemDefaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
// Bring up wifi and expect CALLBACK_AVAILABLE.
mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(true);
cellNetworkCallback.assertNoCallback();
defaultNetworkCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
+ systemDefaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
assertEquals(defaultNetworkCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
+ assertEquals(systemDefaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
// Bring down cell. Expect no default network callback, since it wasn't the default.
mCellNetworkAgent.disconnect();
cellNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
defaultNetworkCallback.assertNoCallback();
+ systemDefaultCallback.assertNoCallback();
assertEquals(defaultNetworkCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
+ assertEquals(systemDefaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
// Bring up cell. Expect no default network callback, since it won't be the default.
mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
mCellNetworkAgent.connect(true);
cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
defaultNetworkCallback.assertNoCallback();
+ systemDefaultCallback.assertNoCallback();
assertEquals(defaultNetworkCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
+ assertEquals(systemDefaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
// Bring down wifi. Expect the default network callback to notified of LOST wifi
// followed by AVAILABLE cell.
@@ -3695,19 +3822,25 @@ public class ConnectivityServiceTest {
cellNetworkCallback.assertNoCallback();
defaultNetworkCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
defaultNetworkCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
+ systemDefaultCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
+ systemDefaultCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
mCellNetworkAgent.disconnect();
cellNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
defaultNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
+ systemDefaultCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
waitForIdle();
assertEquals(null, mCm.getActiveNetwork());
mMockVpn.establishForMyUid();
assertUidRangesUpdatedForMyUid(true);
defaultNetworkCallback.expectAvailableThenValidatedCallbacks(mMockVpn);
+ systemDefaultCallback.assertNoCallback();
assertEquals(defaultNetworkCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
+ assertEquals(null, systemDefaultCallback.getLastAvailableNetwork());
mMockVpn.disconnect();
defaultNetworkCallback.expectCallback(CallbackEntry.LOST, mMockVpn);
+ systemDefaultCallback.assertNoCallback();
waitForIdle();
assertEquals(null, mCm.getActiveNetwork());
}
@@ -3773,6 +3906,24 @@ public class ConnectivityServiceTest {
mCm.unregisterNetworkCallback(cellNetworkCallback);
}
+ @Test
+ public void testRegisterSystemDefaultCallbackRequiresNetworkSettings() throws Exception {
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
+ mCellNetworkAgent.connect(false /* validated */);
+
+ final Handler handler = new Handler(ConnectivityThread.getInstanceLooper());
+ final TestNetworkCallback callback = new TestNetworkCallback();
+ assertThrows(SecurityException.class,
+ () -> mCm.registerSystemDefaultNetworkCallback(callback, handler));
+ callback.assertNoCallback();
+
+ mServiceContext.setPermission(Manifest.permission.NETWORK_SETTINGS,
+ PERMISSION_GRANTED);
+ mCm.registerSystemDefaultNetworkCallback(callback, handler);
+ callback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
+ mCm.unregisterNetworkCallback(callback);
+ }
+
private void setCaptivePortalMode(int mode) {
ContentResolver cr = mServiceContext.getContentResolver();
Settings.Global.putInt(cr, Settings.Global.CAPTIVE_PORTAL_MODE, mode);
@@ -3962,7 +4113,6 @@ public class ConnectivityServiceTest {
handlerThread.start();
NetworkCapabilities filter = new NetworkCapabilities()
.addTransportType(TRANSPORT_CELLULAR)
- .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
.addCapability(NET_CAPABILITY_INTERNET);
final MockNetworkFactory testFactory = new MockNetworkFactory(handlerThread.getLooper(),
mServiceContext, "testFactory", filter);
@@ -5866,7 +6016,6 @@ public class ConnectivityServiceTest {
.addTransportType(TRANSPORT_CELLULAR)
.addCapability(NET_CAPABILITY_INTERNET)
.addCapability(NET_CAPABILITY_NOT_CONGESTED)
- .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
.setLinkDownstreamBandwidthKbps(10);
final NetworkCapabilities wifiNc = new NetworkCapabilities()
.addTransportType(TRANSPORT_WIFI)
@@ -5875,7 +6024,6 @@ public class ConnectivityServiceTest {
.addCapability(NET_CAPABILITY_NOT_ROAMING)
.addCapability(NET_CAPABILITY_NOT_CONGESTED)
.addCapability(NET_CAPABILITY_NOT_SUSPENDED)
- .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
.setLinkUpstreamBandwidthKbps(20);
mCellNetworkAgent.setNetworkCapabilities(cellNc, true /* sendToConnectivityService */);
mWiFiNetworkAgent.setNetworkCapabilities(wifiNc, true /* sendToConnectivityService */);
@@ -6134,6 +6282,10 @@ public class ConnectivityServiceTest {
@Test
public void testVpnNetworkActive() throws Exception {
+ // NETWORK_SETTINGS is necessary to call registerSystemDefaultNetworkCallback.
+ mServiceContext.setPermission(Manifest.permission.NETWORK_SETTINGS,
+ PERMISSION_GRANTED);
+
final int uid = Process.myUid();
final TestNetworkCallback genericNetworkCallback = new TestNetworkCallback();
@@ -6141,6 +6293,7 @@ public class ConnectivityServiceTest {
final TestNetworkCallback wifiNetworkCallback = new TestNetworkCallback();
final TestNetworkCallback vpnNetworkCallback = new TestNetworkCallback();
final TestNetworkCallback defaultCallback = new TestNetworkCallback();
+ final TestNetworkCallback systemDefaultCallback = new TestNetworkCallback();
final NetworkRequest genericNotVpnRequest = new NetworkRequest.Builder().build();
final NetworkRequest genericRequest = new NetworkRequest.Builder()
.removeCapability(NET_CAPABILITY_NOT_VPN).build();
@@ -6154,6 +6307,8 @@ public class ConnectivityServiceTest {
mCm.registerNetworkCallback(wifiRequest, wifiNetworkCallback);
mCm.registerNetworkCallback(vpnNetworkRequest, vpnNetworkCallback);
mCm.registerDefaultNetworkCallback(defaultCallback);
+ mCm.registerSystemDefaultNetworkCallback(systemDefaultCallback,
+ new Handler(ConnectivityThread.getInstanceLooper()));
defaultCallback.assertNoCallback();
mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
@@ -6163,6 +6318,7 @@ public class ConnectivityServiceTest {
genericNotVpnNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
wifiNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
+ systemDefaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
vpnNetworkCallback.assertNoCallback();
assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
@@ -6183,7 +6339,10 @@ public class ConnectivityServiceTest {
wifiNetworkCallback.assertNoCallback();
vpnNetworkCallback.expectAvailableThenValidatedCallbacks(mMockVpn);
defaultCallback.expectAvailableThenValidatedCallbacks(mMockVpn);
+ systemDefaultCallback.assertNoCallback();
assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
+ assertEquals(mWiFiNetworkAgent.getNetwork(),
+ systemDefaultCallback.getLastAvailableNetwork());
ranges.clear();
mMockVpn.setUids(ranges);
@@ -6200,6 +6359,7 @@ public class ConnectivityServiceTest {
// much, but that is the reason the test here has to check for an update to the
// capabilities instead of the expected LOST then AVAILABLE.
defaultCallback.expectCallback(CallbackEntry.NETWORK_CAPS_UPDATED, mMockVpn);
+ systemDefaultCallback.assertNoCallback();
ranges.add(new UidRange(uid, uid));
mMockVpn.setUids(ranges);
@@ -6211,6 +6371,7 @@ public class ConnectivityServiceTest {
// TODO : Here like above, AVAILABLE would be correct, but because this can't actually
// happen outside of the test, ConnectivityService does not rematch callbacks.
defaultCallback.expectCallback(CallbackEntry.NETWORK_CAPS_UPDATED, mMockVpn);
+ systemDefaultCallback.assertNoCallback();
mWiFiNetworkAgent.disconnect();
@@ -6219,6 +6380,7 @@ public class ConnectivityServiceTest {
wifiNetworkCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
vpnNetworkCallback.assertNoCallback();
defaultCallback.assertNoCallback();
+ systemDefaultCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
mMockVpn.disconnect();
@@ -6227,12 +6389,14 @@ public class ConnectivityServiceTest {
wifiNetworkCallback.assertNoCallback();
vpnNetworkCallback.expectCallback(CallbackEntry.LOST, mMockVpn);
defaultCallback.expectCallback(CallbackEntry.LOST, mMockVpn);
+ systemDefaultCallback.assertNoCallback();
assertEquals(null, mCm.getActiveNetwork());
mCm.unregisterNetworkCallback(genericNetworkCallback);
mCm.unregisterNetworkCallback(wifiNetworkCallback);
mCm.unregisterNetworkCallback(vpnNetworkCallback);
mCm.unregisterNetworkCallback(defaultCallback);
+ mCm.unregisterNetworkCallback(systemDefaultCallback);
}
@Test
@@ -6368,6 +6532,8 @@ public class ConnectivityServiceTest {
assertTrue(nc.hasCapability(NET_CAPABILITY_VALIDATED));
assertFalse(nc.hasCapability(NET_CAPABILITY_NOT_METERED));
assertTrue(nc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
+
+ assertVpnTransportInfo(nc, VpnManager.TYPE_VPN_SERVICE);
}
private void assertDefaultNetworkCapabilities(int userId, NetworkAgentWrapper... networks) {
@@ -6407,6 +6573,7 @@ public class ConnectivityServiceTest {
assertFalse(nc.hasCapability(NET_CAPABILITY_NOT_METERED));
// A VPN without underlying networks is not suspended.
assertTrue(nc.hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
+ assertVpnTransportInfo(nc, VpnManager.TYPE_VPN_SERVICE);
final int userId = UserHandle.getUserId(Process.myUid());
assertDefaultNetworkCapabilities(userId /* no networks */);
@@ -6570,6 +6737,7 @@ public class ConnectivityServiceTest {
// By default, VPN is set to track default network (i.e. its underlying networks is null).
// In case of no default network, VPN is considered metered.
assertFalse(nc.hasCapability(NET_CAPABILITY_NOT_METERED));
+ assertVpnTransportInfo(nc, VpnManager.TYPE_VPN_SERVICE);
// Connect to Cell; Cell is the default network.
mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
@@ -6627,6 +6795,7 @@ public class ConnectivityServiceTest {
NetworkCapabilities nc = mCm.getNetworkCapabilities(mMockVpn.getNetwork());
assertNotNull("nc=" + nc, nc.getUids());
assertEquals(nc.getUids(), uidRangesForUid(uid));
+ assertVpnTransportInfo(nc, VpnManager.TYPE_VPN_SERVICE);
// Set an underlying network and expect to see the VPN transports change.
mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
@@ -6709,8 +6878,8 @@ public class ConnectivityServiceTest {
// Enable always-on VPN lockdown. The main user loses network access because no VPN is up.
final ArrayList<String> allowList = new ArrayList<>();
- mService.setAlwaysOnVpnPackage(PRIMARY_USER, ALWAYS_ON_PACKAGE, true /* lockdown */,
- allowList);
+ mVpnManagerService.setAlwaysOnVpnPackage(PRIMARY_USER, ALWAYS_ON_PACKAGE,
+ true /* lockdown */, allowList);
waitForIdle();
assertNull(mCm.getActiveNetworkForUid(uid));
// This is arguably overspecified: a UID that is not running doesn't have an active network.
@@ -6740,7 +6909,8 @@ public class ConnectivityServiceTest {
assertNull(mCm.getActiveNetworkForUid(uid));
assertNotNull(mCm.getActiveNetworkForUid(restrictedUid));
- mService.setAlwaysOnVpnPackage(PRIMARY_USER, null, false /* lockdown */, allowList);
+ mVpnManagerService.setAlwaysOnVpnPackage(PRIMARY_USER, null, false /* lockdown */,
+ allowList);
waitForIdle();
}
@@ -7116,7 +7286,8 @@ public class ConnectivityServiceTest {
final int uid = Process.myUid();
final int userId = UserHandle.getUserId(uid);
final ArrayList<String> allowList = new ArrayList<>();
- mService.setAlwaysOnVpnPackage(userId, ALWAYS_ON_PACKAGE, true /* lockdown */, allowList);
+ mVpnManagerService.setAlwaysOnVpnPackage(userId, ALWAYS_ON_PACKAGE, true /* lockdown */,
+ allowList);
waitForIdle();
UidRangeParcel firstHalf = new UidRangeParcel(1, VPN_UID - 1);
@@ -7138,7 +7309,7 @@ public class ConnectivityServiceTest {
assertNetworkInfo(TYPE_WIFI, DetailedState.BLOCKED);
// Disable lockdown, expect to see the network unblocked.
- mService.setAlwaysOnVpnPackage(userId, null, false /* lockdown */, allowList);
+ mVpnManagerService.setAlwaysOnVpnPackage(userId, null, false /* lockdown */, allowList);
callback.expectBlockedStatusCallback(false, mWiFiNetworkAgent);
defaultCallback.expectBlockedStatusCallback(false, mWiFiNetworkAgent);
vpnUidCallback.assertNoCallback();
@@ -7151,7 +7322,8 @@ public class ConnectivityServiceTest {
// Add our UID to the allowlist and re-enable lockdown, expect network is not blocked.
allowList.add(TEST_PACKAGE_NAME);
- mService.setAlwaysOnVpnPackage(userId, ALWAYS_ON_PACKAGE, true /* lockdown */, allowList);
+ mVpnManagerService.setAlwaysOnVpnPackage(userId, ALWAYS_ON_PACKAGE, true /* lockdown */,
+ allowList);
callback.assertNoCallback();
defaultCallback.assertNoCallback();
vpnUidCallback.assertNoCallback();
@@ -7184,11 +7356,12 @@ public class ConnectivityServiceTest {
// Disable lockdown, remove our UID from the allowlist, and re-enable lockdown.
// Everything should now be blocked.
- mService.setAlwaysOnVpnPackage(userId, null, false /* lockdown */, allowList);
+ mVpnManagerService.setAlwaysOnVpnPackage(userId, null, false /* lockdown */, allowList);
waitForIdle();
expectNetworkRejectNonSecureVpn(inOrder, false, piece1, piece2, piece3);
allowList.clear();
- mService.setAlwaysOnVpnPackage(userId, ALWAYS_ON_PACKAGE, true /* lockdown */, allowList);
+ mVpnManagerService.setAlwaysOnVpnPackage(userId, ALWAYS_ON_PACKAGE, true /* lockdown */,
+ allowList);
waitForIdle();
expectNetworkRejectNonSecureVpn(inOrder, true, firstHalf, secondHalf);
defaultCallback.expectBlockedStatusCallback(true, mWiFiNetworkAgent);
@@ -7201,7 +7374,7 @@ public class ConnectivityServiceTest {
assertNetworkInfo(TYPE_WIFI, DetailedState.BLOCKED);
// Disable lockdown. Everything is unblocked.
- mService.setAlwaysOnVpnPackage(userId, null, false /* lockdown */, allowList);
+ mVpnManagerService.setAlwaysOnVpnPackage(userId, null, false /* lockdown */, allowList);
defaultCallback.expectBlockedStatusCallback(false, mWiFiNetworkAgent);
assertBlockedCallbackInAnyOrder(callback, false, mWiFiNetworkAgent, mCellNetworkAgent);
vpnUidCallback.assertNoCallback();
@@ -7213,7 +7386,8 @@ public class ConnectivityServiceTest {
// Enable and disable an always-on VPN package without lockdown. Expect no changes.
reset(mMockNetd);
- mService.setAlwaysOnVpnPackage(userId, ALWAYS_ON_PACKAGE, false /* lockdown */, allowList);
+ mVpnManagerService.setAlwaysOnVpnPackage(userId, ALWAYS_ON_PACKAGE, false /* lockdown */,
+ allowList);
inOrder.verify(mMockNetd, never()).networkRejectNonSecureVpn(anyBoolean(), any());
callback.assertNoCallback();
defaultCallback.assertNoCallback();
@@ -7224,7 +7398,7 @@ public class ConnectivityServiceTest {
assertNetworkInfo(TYPE_MOBILE, DetailedState.DISCONNECTED);
assertNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
- mService.setAlwaysOnVpnPackage(userId, null, false /* lockdown */, allowList);
+ mVpnManagerService.setAlwaysOnVpnPackage(userId, null, false /* lockdown */, allowList);
inOrder.verify(mMockNetd, never()).networkRejectNonSecureVpn(anyBoolean(), any());
callback.assertNoCallback();
defaultCallback.assertNoCallback();
@@ -7236,7 +7410,8 @@ public class ConnectivityServiceTest {
assertNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
// Enable lockdown and connect a VPN. The VPN is not blocked.
- mService.setAlwaysOnVpnPackage(userId, ALWAYS_ON_PACKAGE, true /* lockdown */, allowList);
+ mVpnManagerService.setAlwaysOnVpnPackage(userId, ALWAYS_ON_PACKAGE, true /* lockdown */,
+ allowList);
defaultCallback.expectBlockedStatusCallback(true, mWiFiNetworkAgent);
assertBlockedCallbackInAnyOrder(callback, true, mWiFiNetworkAgent, mCellNetworkAgent);
vpnUidCallback.assertNoCallback();
@@ -7282,10 +7457,14 @@ public class ConnectivityServiceTest {
when(mKeyStore.get(Credentials.VPN + profileName)).thenReturn(encodedProfile);
}
- private void establishLegacyLockdownVpn() throws Exception {
+ private void establishLegacyLockdownVpn(Network underlying) throws Exception {
+ // The legacy lockdown VPN only supports userId 0, and must have an underlying network.
+ assertNotNull(underlying);
+ mMockVpn.setVpnType(VpnManager.TYPE_VPN_LEGACY);
// The legacy lockdown VPN only supports userId 0.
final Set<UidRange> ranges = Collections.singleton(UidRange.createForUser(PRIMARY_USER));
mMockVpn.registerAgent(ranges);
+ mMockVpn.setUnderlyingNetworks(new Network[]{underlying});
mMockVpn.connect(true);
}
@@ -7293,6 +7472,9 @@ public class ConnectivityServiceTest {
public void testLegacyLockdownVpn() throws Exception {
mServiceContext.setPermission(
Manifest.permission.CONTROL_VPN, PERMISSION_GRANTED);
+ // For LockdownVpnTracker to call registerSystemDefaultNetworkCallback.
+ mServiceContext.setPermission(
+ Manifest.permission.NETWORK_SETTINGS, PERMISSION_GRANTED);
final NetworkRequest request = new NetworkRequest.Builder().clearCapabilities().build();
final TestNetworkCallback callback = new TestNetworkCallback();
@@ -7301,6 +7483,10 @@ public class ConnectivityServiceTest {
final TestNetworkCallback defaultCallback = new TestNetworkCallback();
mCm.registerDefaultNetworkCallback(defaultCallback);
+ final TestNetworkCallback systemDefaultCallback = new TestNetworkCallback();
+ mCm.registerSystemDefaultNetworkCallback(systemDefaultCallback,
+ new Handler(ConnectivityThread.getInstanceLooper()));
+
// Pretend lockdown VPN was configured.
setupLegacyLockdownVpn();
@@ -7330,6 +7516,7 @@ public class ConnectivityServiceTest {
mCellNetworkAgent.connect(false /* validated */);
callback.expectAvailableCallbacksUnvalidatedAndBlocked(mCellNetworkAgent);
defaultCallback.expectAvailableCallbacksUnvalidatedAndBlocked(mCellNetworkAgent);
+ systemDefaultCallback.expectAvailableCallbacksUnvalidatedAndBlocked(mCellNetworkAgent);
waitForIdle();
assertNull(mMockVpn.getAgent());
@@ -7341,6 +7528,8 @@ public class ConnectivityServiceTest {
mCellNetworkAgent.sendLinkProperties(cellLp);
callback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
defaultCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
+ systemDefaultCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED,
+ mCellNetworkAgent);
waitForIdle();
assertNull(mMockVpn.getAgent());
@@ -7350,6 +7539,7 @@ public class ConnectivityServiceTest {
mCellNetworkAgent.disconnect();
callback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
defaultCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
+ systemDefaultCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
b1.expectBroadcast();
// When lockdown VPN is active, the NetworkInfo state in CONNECTIVITY_ACTION is overwritten
@@ -7359,6 +7549,7 @@ public class ConnectivityServiceTest {
mCellNetworkAgent.connect(false /* validated */);
callback.expectAvailableCallbacksUnvalidatedAndBlocked(mCellNetworkAgent);
defaultCallback.expectAvailableCallbacksUnvalidatedAndBlocked(mCellNetworkAgent);
+ systemDefaultCallback.expectAvailableCallbacksUnvalidatedAndBlocked(mCellNetworkAgent);
b1.expectBroadcast();
assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
@@ -7381,9 +7572,10 @@ public class ConnectivityServiceTest {
mMockVpn.expectStartLegacyVpnRunner();
b1 = expectConnectivityAction(TYPE_VPN, DetailedState.CONNECTED);
ExpectedBroadcast b2 = expectConnectivityAction(TYPE_MOBILE, DetailedState.CONNECTED);
- establishLegacyLockdownVpn();
+ establishLegacyLockdownVpn(mCellNetworkAgent.getNetwork());
callback.expectAvailableThenValidatedCallbacks(mMockVpn);
defaultCallback.expectAvailableThenValidatedCallbacks(mMockVpn);
+ systemDefaultCallback.assertNoCallback();
NetworkCapabilities vpnNc = mCm.getNetworkCapabilities(mMockVpn.getNetwork());
b1.expectBroadcast();
b2.expectBroadcast();
@@ -7395,6 +7587,7 @@ public class ConnectivityServiceTest {
assertTrue(vpnNc.hasTransport(TRANSPORT_CELLULAR));
assertFalse(vpnNc.hasTransport(TRANSPORT_WIFI));
assertFalse(vpnNc.hasCapability(NET_CAPABILITY_NOT_METERED));
+ assertVpnTransportInfo(vpnNc, VpnManager.TYPE_VPN_LEGACY);
// Switch default network from cell to wifi. Expect VPN to disconnect and reconnect.
final LinkProperties wifiLp = new LinkProperties();
@@ -7422,11 +7615,10 @@ public class ConnectivityServiceTest {
// fact that a VPN is connected should only result in the VPN itself being unblocked, not
// any other network. Bug in isUidBlockedByVpn?
callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
- callback.expectCapabilitiesThat(mMockVpn, nc -> nc.hasTransport(TRANSPORT_WIFI));
callback.expectCallback(CallbackEntry.LOST, mMockVpn);
- defaultCallback.expectCapabilitiesThat(mMockVpn, nc -> nc.hasTransport(TRANSPORT_WIFI));
defaultCallback.expectCallback(CallbackEntry.LOST, mMockVpn);
defaultCallback.expectAvailableCallbacksUnvalidatedAndBlocked(mWiFiNetworkAgent);
+ systemDefaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
// While the VPN is reconnecting on the new network, everything is blocked.
assertActiveNetworkInfo(TYPE_WIFI, DetailedState.BLOCKED);
@@ -7437,9 +7629,10 @@ public class ConnectivityServiceTest {
// The VPN comes up again on wifi.
b1 = expectConnectivityAction(TYPE_VPN, DetailedState.CONNECTED);
b2 = expectConnectivityAction(TYPE_WIFI, DetailedState.CONNECTED);
- establishLegacyLockdownVpn();
+ establishLegacyLockdownVpn(mWiFiNetworkAgent.getNetwork());
callback.expectAvailableThenValidatedCallbacks(mMockVpn);
defaultCallback.expectAvailableThenValidatedCallbacks(mMockVpn);
+ systemDefaultCallback.assertNoCallback();
b1.expectBroadcast();
b2.expectBroadcast();
assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
@@ -7453,14 +7646,10 @@ public class ConnectivityServiceTest {
assertTrue(vpnNc.hasCapability(NET_CAPABILITY_NOT_METERED));
// Disconnect cell. Nothing much happens since it's not the default network.
- // Whenever LockdownVpnTracker is connected, it will send a connected broadcast any time any
- // NetworkInfo is updated. This is probably a bug.
- // TODO: consider fixing this.
- b1 = expectConnectivityAction(TYPE_WIFI, DetailedState.CONNECTED);
mCellNetworkAgent.disconnect();
- b1.expectBroadcast();
callback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
defaultCallback.assertNoCallback();
+ systemDefaultCallback.assertNoCallback();
assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
assertNetworkInfo(TYPE_MOBILE, DetailedState.DISCONNECTED);
@@ -7470,6 +7659,7 @@ public class ConnectivityServiceTest {
b1 = expectConnectivityAction(TYPE_WIFI, DetailedState.DISCONNECTED);
mWiFiNetworkAgent.disconnect();
callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
+ systemDefaultCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
b1.expectBroadcast();
callback.expectCapabilitiesThat(mMockVpn, nc -> !nc.hasTransport(TRANSPORT_WIFI));
b2 = expectConnectivityAction(TYPE_VPN, DetailedState.DISCONNECTED);
@@ -7521,13 +7711,19 @@ public class ConnectivityServiceTest {
mWiFiNetworkAgent.removeCapability(testCap);
callbackWithCap.expectAvailableCallbacksValidated(mCellNetworkAgent);
callbackWithoutCap.expectCapabilitiesWithout(testCap, mWiFiNetworkAgent);
- verify(mMockNetd).networkSetDefault(eq(mCellNetworkAgent.getNetwork().netId));
- reset(mMockNetd);
+ // TODO: Test default network changes for NOT_VCN_MANAGED once the default request has
+ // it.
+ if (testCap == NET_CAPABILITY_TRUSTED) {
+ verify(mMockNetd).networkSetDefault(eq(mCellNetworkAgent.getNetwork().netId));
+ reset(mMockNetd);
+ }
mCellNetworkAgent.removeCapability(testCap);
callbackWithCap.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
callbackWithoutCap.assertNoCallback();
- verify(mMockNetd).networkClearDefault();
+ if (testCap == NET_CAPABILITY_TRUSTED) {
+ verify(mMockNetd).networkClearDefault();
+ }
mCm.unregisterNetworkCallback(callbackWithCap);
mCm.unregisterNetworkCallback(callbackWithoutCap);
@@ -8521,11 +8717,7 @@ public class ConnectivityServiceTest {
final int myUid = Process.myUid();
setupConnectionOwnerUidAsVpnApp(myUid, VpnManager.TYPE_VPN_PLATFORM);
- try {
- mService.getConnectionOwnerUid(getTestConnectionInfo());
- fail("Expected SecurityException for non-VpnService app");
- } catch (SecurityException expected) {
- }
+ assertEquals(INVALID_UID, mService.getConnectionOwnerUid(getTestConnectionInfo()));
}
@Test
@@ -8533,11 +8725,7 @@ public class ConnectivityServiceTest {
final int myUid = Process.myUid();
setupConnectionOwnerUidAsVpnApp(myUid + 1, VpnManager.TYPE_VPN_SERVICE);
- try {
- mService.getConnectionOwnerUid(getTestConnectionInfo());
- fail("Expected SecurityException for non-VpnService app");
- } catch (SecurityException expected) {
- }
+ assertEquals(INVALID_UID, mService.getConnectionOwnerUid(getTestConnectionInfo()));
}
@Test
diff --git a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
index 799bcc82d2a9..c86224a71978 100644
--- a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
+++ b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
@@ -33,6 +33,7 @@ import static org.mockito.Mockito.when;
import android.app.AppOpsManager;
import android.content.Context;
import android.content.pm.PackageManager;
+import android.net.ConnectivityManager;
import android.net.INetd;
import android.net.InetAddresses;
import android.net.IpSecAlgorithm;
@@ -44,6 +45,7 @@ import android.net.IpSecTransformResponse;
import android.net.IpSecTunnelInterfaceResponse;
import android.net.IpSecUdpEncapResponse;
import android.net.LinkAddress;
+import android.net.LinkProperties;
import android.net.Network;
import android.os.Binder;
import android.os.INetworkManagementService;
@@ -53,6 +55,8 @@ import android.test.mock.MockContext;
import androidx.test.filters.SmallTest;
+import com.android.server.IpSecService.TunnelInterfaceRecord;
+
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
@@ -109,6 +113,7 @@ public class IpSecServiceParameterizedTest {
};
AppOpsManager mMockAppOps = mock(AppOpsManager.class);
+ ConnectivityManager mMockConnectivityMgr = mock(ConnectivityManager.class);
MockContext mMockContext = new MockContext() {
@Override
@@ -116,12 +121,22 @@ public class IpSecServiceParameterizedTest {
switch(name) {
case Context.APP_OPS_SERVICE:
return mMockAppOps;
+ case Context.CONNECTIVITY_SERVICE:
+ return mMockConnectivityMgr;
default:
return null;
}
}
@Override
+ public String getSystemServiceName(Class<?> serviceClass) {
+ if (ConnectivityManager.class == serviceClass) {
+ return Context.CONNECTIVITY_SERVICE;
+ }
+ return null;
+ }
+
+ @Override
public PackageManager getPackageManager() {
return mMockPkgMgr;
}
@@ -151,6 +166,10 @@ public class IpSecServiceParameterizedTest {
new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 128);
private static final int REMOTE_ENCAP_PORT = 4500;
+ private static final String BLESSED_PACKAGE = "blessedPackage";
+ private static final String SYSTEM_PACKAGE = "systemPackage";
+ private static final String BAD_PACKAGE = "badPackage";
+
public IpSecServiceParameterizedTest(
String sourceAddr, String destAddr, String localInnerAddr, int family) {
mSourceAddr = sourceAddr;
@@ -174,15 +193,15 @@ public class IpSecServiceParameterizedTest {
when(mMockPkgMgr.hasSystemFeature(anyString())).thenReturn(true);
// A package granted the AppOp for MANAGE_IPSEC_TUNNELS will be MODE_ALLOWED.
- when(mMockAppOps.noteOp(anyInt(), anyInt(), eq("blessedPackage")))
- .thenReturn(AppOpsManager.MODE_ALLOWED);
+ when(mMockAppOps.noteOp(anyInt(), anyInt(), eq(BLESSED_PACKAGE)))
+ .thenReturn(AppOpsManager.MODE_ALLOWED);
// A system package will not be granted the app op, so this should fall back to
// a permissions check, which should pass.
- when(mMockAppOps.noteOp(anyInt(), anyInt(), eq("systemPackage")))
- .thenReturn(AppOpsManager.MODE_DEFAULT);
+ when(mMockAppOps.noteOp(anyInt(), anyInt(), eq(SYSTEM_PACKAGE)))
+ .thenReturn(AppOpsManager.MODE_DEFAULT);
// A mismatch between the package name and the UID will return MODE_IGNORED.
- when(mMockAppOps.noteOp(anyInt(), anyInt(), eq("badPackage")))
- .thenReturn(AppOpsManager.MODE_IGNORED);
+ when(mMockAppOps.noteOp(anyInt(), anyInt(), eq(BAD_PACKAGE)))
+ .thenReturn(AppOpsManager.MODE_IGNORED);
}
//TODO: Add a test to verify SPI.
@@ -338,7 +357,7 @@ public class IpSecServiceParameterizedTest {
addAuthAndCryptToIpSecConfig(ipSecConfig);
IpSecTransformResponse createTransformResp =
- mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
+ mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
assertEquals(IpSecManager.Status.OK, createTransformResp.status);
verifyTransformNetdCalledForCreatingSA(ipSecConfig, createTransformResp);
@@ -352,7 +371,7 @@ public class IpSecServiceParameterizedTest {
ipSecConfig.setAuthenticatedEncryption(AEAD_ALGO);
IpSecTransformResponse createTransformResp =
- mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
+ mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
assertEquals(IpSecManager.Status.OK, createTransformResp.status);
verifyTransformNetdCalledForCreatingSA(ipSecConfig, createTransformResp);
@@ -370,14 +389,14 @@ public class IpSecServiceParameterizedTest {
if (mFamily == AF_INET) {
IpSecTransformResponse createTransformResp =
- mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
+ mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
assertEquals(IpSecManager.Status.OK, createTransformResp.status);
verifyTransformNetdCalledForCreatingSA(ipSecConfig, createTransformResp, udpSock.port);
} else {
try {
IpSecTransformResponse createTransformResp =
- mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
+ mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
fail("Expected IllegalArgumentException on attempt to use UDP Encap in IPv6");
} catch (IllegalArgumentException expected) {
}
@@ -396,14 +415,14 @@ public class IpSecServiceParameterizedTest {
if (mFamily == AF_INET) {
IpSecTransformResponse createTransformResp =
- mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
+ mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
assertEquals(IpSecManager.Status.OK, createTransformResp.status);
verifyTransformNetdCalledForCreatingSA(ipSecConfig, createTransformResp, udpSock.port);
} else {
try {
IpSecTransformResponse createTransformResp =
- mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
+ mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
fail("Expected IllegalArgumentException on attempt to use UDP Encap in IPv6");
} catch (IllegalArgumentException expected) {
}
@@ -417,12 +436,12 @@ public class IpSecServiceParameterizedTest {
addAuthAndCryptToIpSecConfig(ipSecConfig);
IpSecTransformResponse createTransformResp =
- mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
+ mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
assertEquals(IpSecManager.Status.OK, createTransformResp.status);
// Attempting to create transform a second time with the same SPIs should throw an error...
try {
- mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
+ mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
fail("IpSecService should have thrown an error for reuse of SPI");
} catch (IllegalStateException expected) {
}
@@ -430,7 +449,7 @@ public class IpSecServiceParameterizedTest {
// ... even if the transform is deleted
mIpSecService.deleteTransform(createTransformResp.resourceId);
try {
- mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
+ mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
fail("IpSecService should have thrown an error for reuse of SPI");
} catch (IllegalStateException expected) {
}
@@ -443,7 +462,7 @@ public class IpSecServiceParameterizedTest {
addAuthAndCryptToIpSecConfig(ipSecConfig);
IpSecTransformResponse createTransformResp =
- mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
+ mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(mUid);
assertEquals(1, userRecord.mSpiQuotaTracker.mCurrent);
mIpSecService.releaseSecurityParameterIndex(ipSecConfig.getSpiResourceId());
@@ -467,7 +486,7 @@ public class IpSecServiceParameterizedTest {
addAuthAndCryptToIpSecConfig(ipSecConfig);
IpSecTransformResponse createTransformResp =
- mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
+ mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
mIpSecService.deleteTransform(createTransformResp.resourceId);
verify(mMockNetd, times(1))
@@ -515,7 +534,7 @@ public class IpSecServiceParameterizedTest {
addAuthAndCryptToIpSecConfig(ipSecConfig);
IpSecTransformResponse createTransformResp =
- mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
+ mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(mUid);
IpSecService.RefcountedResource refcountedRecord =
@@ -562,7 +581,7 @@ public class IpSecServiceParameterizedTest {
addAuthAndCryptToIpSecConfig(ipSecConfig);
IpSecTransformResponse createTransformResp =
- mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
+ mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
if (closeSpiBeforeApply) {
mIpSecService.releaseSecurityParameterIndex(ipSecConfig.getSpiResourceId());
@@ -592,7 +611,7 @@ public class IpSecServiceParameterizedTest {
addAuthAndCryptToIpSecConfig(ipSecConfig);
IpSecTransformResponse createTransformResp =
- mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
+ mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
// Close SPI record
mIpSecService.releaseSecurityParameterIndex(ipSecConfig.getSpiResourceId());
@@ -638,7 +657,7 @@ public class IpSecServiceParameterizedTest {
@Test
public void testCreateTunnelInterface() throws Exception {
IpSecTunnelInterfaceResponse createTunnelResp =
- createAndValidateTunnel(mSourceAddr, mDestinationAddr, "blessedPackage");
+ createAndValidateTunnel(mSourceAddr, mDestinationAddr, BLESSED_PACKAGE);
// Check that we have stored the tracking object, and retrieve it
IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(mUid);
@@ -661,11 +680,11 @@ public class IpSecServiceParameterizedTest {
@Test
public void testDeleteTunnelInterface() throws Exception {
IpSecTunnelInterfaceResponse createTunnelResp =
- createAndValidateTunnel(mSourceAddr, mDestinationAddr, "blessedPackage");
+ createAndValidateTunnel(mSourceAddr, mDestinationAddr, BLESSED_PACKAGE);
IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(mUid);
- mIpSecService.deleteTunnelInterface(createTunnelResp.resourceId, "blessedPackage");
+ mIpSecService.deleteTunnelInterface(createTunnelResp.resourceId, BLESSED_PACKAGE);
// Verify quota and RefcountedResource objects cleaned up
assertEquals(0, userRecord.mTunnelQuotaTracker.mCurrent);
@@ -678,10 +697,73 @@ public class IpSecServiceParameterizedTest {
}
}
+ private Network createFakeUnderlyingNetwork(String interfaceName) {
+ final Network fakeNetwork = new Network(1000);
+ final LinkProperties fakeLp = new LinkProperties();
+ fakeLp.setInterfaceName(interfaceName);
+ when(mMockConnectivityMgr.getLinkProperties(eq(fakeNetwork))).thenReturn(fakeLp);
+ return fakeNetwork;
+ }
+
+ @Test
+ public void testSetNetworkForTunnelInterface() throws Exception {
+ final IpSecTunnelInterfaceResponse createTunnelResp =
+ createAndValidateTunnel(mSourceAddr, mDestinationAddr, BLESSED_PACKAGE);
+ final Network newFakeNetwork = createFakeUnderlyingNetwork("newFakeNetworkInterface");
+ final int tunnelIfaceResourceId = createTunnelResp.resourceId;
+ mIpSecService.setNetworkForTunnelInterface(
+ tunnelIfaceResourceId, newFakeNetwork, BLESSED_PACKAGE);
+
+ final IpSecService.UserRecord userRecord =
+ mIpSecService.mUserResourceTracker.getUserRecord(mUid);
+ assertEquals(1, userRecord.mTunnelQuotaTracker.mCurrent);
+
+ final TunnelInterfaceRecord tunnelInterfaceInfo =
+ userRecord.mTunnelInterfaceRecords.getResourceOrThrow(tunnelIfaceResourceId);
+ assertEquals(newFakeNetwork, tunnelInterfaceInfo.getUnderlyingNetwork());
+ }
+
+ @Test
+ public void testSetNetworkForTunnelInterfaceFailsForInvalidResourceId() throws Exception {
+ final IpSecTunnelInterfaceResponse createTunnelResp =
+ createAndValidateTunnel(mSourceAddr, mDestinationAddr, BLESSED_PACKAGE);
+ final Network newFakeNetwork = new Network(1000);
+
+ try {
+ mIpSecService.setNetworkForTunnelInterface(
+ IpSecManager.INVALID_RESOURCE_ID, newFakeNetwork, BLESSED_PACKAGE);
+ fail("Expected an IllegalArgumentException for invalid resource ID.");
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
+ @Test
+ public void testSetNetworkForTunnelInterfaceFailsWhenSettingTunnelNetwork() throws Exception {
+ final IpSecTunnelInterfaceResponse createTunnelResp =
+ createAndValidateTunnel(mSourceAddr, mDestinationAddr, BLESSED_PACKAGE);
+ final int tunnelIfaceResourceId = createTunnelResp.resourceId;
+ final IpSecService.UserRecord userRecord =
+ mIpSecService.mUserResourceTracker.getUserRecord(mUid);
+ final TunnelInterfaceRecord tunnelInterfaceInfo =
+ userRecord.mTunnelInterfaceRecords.getResourceOrThrow(tunnelIfaceResourceId);
+
+ final Network newFakeNetwork =
+ createFakeUnderlyingNetwork(tunnelInterfaceInfo.getInterfaceName());
+
+ try {
+ mIpSecService.setNetworkForTunnelInterface(
+ tunnelIfaceResourceId, newFakeNetwork, BLESSED_PACKAGE);
+ fail(
+ "Expected an IllegalArgumentException because the underlying network is the"
+ + " network being exposed by this tunnel.");
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
@Test
public void testTunnelInterfaceBinderDeath() throws Exception {
IpSecTunnelInterfaceResponse createTunnelResp =
- createAndValidateTunnel(mSourceAddr, mDestinationAddr, "blessedPackage");
+ createAndValidateTunnel(mSourceAddr, mDestinationAddr, BLESSED_PACKAGE);
IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(mUid);
IpSecService.RefcountedResource refcountedRecord =
@@ -718,9 +800,9 @@ public class IpSecServiceParameterizedTest {
addAuthAndCryptToIpSecConfig(ipSecConfig);
IpSecTransformResponse createTransformResp =
- mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
+ mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
IpSecTunnelInterfaceResponse createTunnelResp =
- createAndValidateTunnel(mSourceAddr, mDestinationAddr, "blessedPackage");
+ createAndValidateTunnel(mSourceAddr, mDestinationAddr, BLESSED_PACKAGE);
if (closeSpiBeforeApply) {
mIpSecService.releaseSecurityParameterIndex(ipSecConfig.getSpiResourceId());
@@ -728,8 +810,8 @@ public class IpSecServiceParameterizedTest {
int transformResourceId = createTransformResp.resourceId;
int tunnelResourceId = createTunnelResp.resourceId;
- mIpSecService.applyTunnelModeTransform(tunnelResourceId, IpSecManager.DIRECTION_OUT,
- transformResourceId, "blessedPackage");
+ mIpSecService.applyTunnelModeTransform(
+ tunnelResourceId, IpSecManager.DIRECTION_OUT, transformResourceId, BLESSED_PACKAGE);
for (int selAddrFamily : ADDRESS_FAMILIES) {
verify(mMockNetd)
@@ -758,17 +840,17 @@ public class IpSecServiceParameterizedTest {
addAuthAndCryptToIpSecConfig(ipSecConfig);
IpSecTransformResponse createTransformResp =
- mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
+ mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
IpSecTunnelInterfaceResponse createTunnelResp =
- createAndValidateTunnel(mSourceAddr, mDestinationAddr, "blessedPackage");
+ createAndValidateTunnel(mSourceAddr, mDestinationAddr, BLESSED_PACKAGE);
// Close SPI record
mIpSecService.releaseSecurityParameterIndex(ipSecConfig.getSpiResourceId());
int transformResourceId = createTransformResp.resourceId;
int tunnelResourceId = createTunnelResp.resourceId;
- mIpSecService.applyTunnelModeTransform(tunnelResourceId, IpSecManager.DIRECTION_OUT,
- transformResourceId, "blessedPackage");
+ mIpSecService.applyTunnelModeTransform(
+ tunnelResourceId, IpSecManager.DIRECTION_OUT, transformResourceId, BLESSED_PACKAGE);
for (int selAddrFamily : ADDRESS_FAMILIES) {
verify(mMockNetd)
@@ -790,7 +872,7 @@ public class IpSecServiceParameterizedTest {
@Test
public void testAddRemoveAddressFromTunnelInterface() throws Exception {
- for (String pkgName : new String[]{"blessedPackage", "systemPackage"}) {
+ for (String pkgName : new String[] {BLESSED_PACKAGE, SYSTEM_PACKAGE}) {
IpSecTunnelInterfaceResponse createTunnelResp =
createAndValidateTunnel(mSourceAddr, mDestinationAddr, pkgName);
mIpSecService.addAddressToTunnelInterface(
@@ -816,7 +898,7 @@ public class IpSecServiceParameterizedTest {
public void testAddTunnelFailsForBadPackageName() throws Exception {
try {
IpSecTunnelInterfaceResponse createTunnelResp =
- createAndValidateTunnel(mSourceAddr, mDestinationAddr, "badPackage");
+ createAndValidateTunnel(mSourceAddr, mDestinationAddr, BAD_PACKAGE);
fail("Expected a SecurityException for badPackage.");
} catch (SecurityException expected) {
}
@@ -830,7 +912,7 @@ public class IpSecServiceParameterizedTest {
try {
String addr = Inet4Address.getLoopbackAddress().getHostAddress();
mIpSecService.createTunnelInterface(
- addr, addr, new Network(0), new Binder(), "blessedPackage");
+ addr, addr, new Network(0), new Binder(), BLESSED_PACKAGE);
fail("Expected UnsupportedOperationException for disabled feature");
} catch (UnsupportedOperationException expected) {
}
diff --git a/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java b/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java
index b47be97ed002..7e85acb05dee 100644
--- a/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java
+++ b/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java
@@ -63,6 +63,8 @@ import java.util.List;
@SmallTest
public class NetworkNotificationManagerTest {
+ private static final String TEST_SSID = "Test SSID";
+ private static final String TEST_EXTRA_INFO = "extra";
static final NetworkCapabilities CELL_CAPABILITIES = new NetworkCapabilities();
static final NetworkCapabilities WIFI_CAPABILITIES = new NetworkCapabilities();
static final NetworkCapabilities VPN_CAPABILITIES = new NetworkCapabilities();
@@ -72,6 +74,7 @@ public class NetworkNotificationManagerTest {
WIFI_CAPABILITIES.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
WIFI_CAPABILITIES.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
+ WIFI_CAPABILITIES.setSSID(TEST_SSID);
// Set the underyling network to wifi.
VPN_CAPABILITIES.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
@@ -112,7 +115,7 @@ public class NetworkNotificationManagerTest {
when(mCtx.createContextAsUser(eq(UserHandle.ALL), anyInt())).thenReturn(asUserCtx);
when(mCtx.getSystemService(eq(Context.NOTIFICATION_SERVICE)))
.thenReturn(mNotificationManager);
- when(mNetworkInfo.getExtraInfo()).thenReturn("extra");
+ when(mNetworkInfo.getExtraInfo()).thenReturn(TEST_EXTRA_INFO);
when(mResources.getColor(anyInt(), any())).thenReturn(0xFF607D8B);
mManager = new NetworkNotificationManager(mCtx, mTelephonyManager);
@@ -125,11 +128,11 @@ public class NetworkNotificationManagerTest {
.notify(eq(tag), eq(PRIVATE_DNS_BROKEN.eventId), any());
final int transportType = NetworkNotificationManager.approximateTransportType(nai);
if (transportType == NetworkCapabilities.TRANSPORT_WIFI) {
- verify(mResources, times(1)).getString(title, eq(any()));
+ verify(mResources, times(1)).getString(eq(title), eq(TEST_EXTRA_INFO));
} else {
verify(mResources, times(1)).getString(title);
}
- verify(mResources, times(1)).getString(R.string.private_dns_broken_detailed);
+ verify(mResources, times(1)).getString(eq(R.string.private_dns_broken_detailed));
}
@Test
diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java
index 73cc9f129e79..cffd2d1d428f 100644
--- a/tests/net/java/com/android/server/connectivity/VpnTest.java
+++ b/tests/net/java/com/android/server/connectivity/VpnTest.java
@@ -25,6 +25,7 @@ import static android.net.ConnectivityManager.NetworkCallback;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
@@ -74,6 +75,7 @@ import android.net.UidRange;
import android.net.UidRangeParcel;
import android.net.VpnManager;
import android.net.VpnService;
+import android.net.VpnTransportInfo;
import android.net.ipsec.ike.IkeSessionCallback;
import android.net.ipsec.ike.exceptions.IkeProtocolException;
import android.os.Build.VERSION_CODES;
@@ -984,6 +986,13 @@ public class VpnTest {
startRacoon("hostname", "5.6.7.8"); // address returned by deps.resolve
}
+ private void assertTransportInfoMatches(NetworkCapabilities nc, int type) {
+ assertNotNull(nc);
+ VpnTransportInfo ti = (VpnTransportInfo) nc.getTransportInfo();
+ assertNotNull(ti);
+ assertEquals(type, ti.type);
+ }
+
public void startRacoon(final String serverAddr, final String expectedAddr)
throws Exception {
final ConditionVariable legacyRunnerReady = new ConditionVariable();
@@ -1020,8 +1029,10 @@ public class VpnTest {
// Now wait for the runner to be ready before testing for the route.
ArgumentCaptor<LinkProperties> lpCaptor = ArgumentCaptor.forClass(LinkProperties.class);
+ ArgumentCaptor<NetworkCapabilities> ncCaptor =
+ ArgumentCaptor.forClass(NetworkCapabilities.class);
verify(mConnectivityManager, timeout(10_000)).registerNetworkAgent(any(), any(),
- lpCaptor.capture(), any(), anyInt(), any(), anyInt());
+ lpCaptor.capture(), ncCaptor.capture(), anyInt(), any(), anyInt());
// In this test the expected address is always v4 so /32.
// Note that the interface needs to be specified because RouteInfo objects stored in
@@ -1031,6 +1042,8 @@ public class VpnTest {
final List<RouteInfo> actualRoutes = lpCaptor.getValue().getRoutes();
assertTrue("Expected throw route (" + expectedRoute + ") not found in " + actualRoutes,
actualRoutes.contains(expectedRoute));
+
+ assertTransportInfoMatches(ncCaptor.getValue(), VpnManager.TYPE_VPN_LEGACY);
} finally {
// Now interrupt the thread, unblock the runner and clean up.
vpn.mVpnRunner.exitVpnRunner();
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 1102624da031..4a1f96d145bd 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
@@ -42,6 +42,8 @@ public class BroadcastInterceptingContext extends ContextWrapper {
private final List<BroadcastInterceptor> mInterceptors = new ArrayList<>();
+ private boolean mUseRegisteredHandlers;
+
public abstract class FutureIntent extends FutureTask<Intent> {
public FutureIntent() {
super(
@@ -61,17 +63,24 @@ public class BroadcastInterceptingContext extends ContextWrapper {
public class BroadcastInterceptor extends FutureIntent {
private final BroadcastReceiver mReceiver;
private final IntentFilter mFilter;
+ private final Handler mHandler;
- public BroadcastInterceptor(BroadcastReceiver receiver, IntentFilter filter) {
+ public BroadcastInterceptor(BroadcastReceiver receiver, IntentFilter filter,
+ Handler handler) {
mReceiver = receiver;
mFilter = filter;
+ mHandler = mUseRegisteredHandlers ? handler : null;
}
public boolean dispatchBroadcast(Intent intent) {
if (mFilter.match(getContentResolver(), intent, false, TAG) > 0) {
if (mReceiver != null) {
final Context context = BroadcastInterceptingContext.this;
- mReceiver.onReceive(context, intent);
+ if (mHandler == null) {
+ mReceiver.onReceive(context, intent);
+ } else {
+ mHandler.post(() -> mReceiver.onReceive(context, intent));
+ }
return false;
} else {
set(intent);
@@ -116,25 +125,38 @@ public class BroadcastInterceptingContext extends ContextWrapper {
}
public FutureIntent nextBroadcastIntent(IntentFilter filter) {
- final BroadcastInterceptor interceptor = new BroadcastInterceptor(null, filter);
+ final BroadcastInterceptor interceptor = new BroadcastInterceptor(null, filter, null);
synchronized (mInterceptors) {
mInterceptors.add(interceptor);
}
return interceptor;
}
- @Override
- public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
+ /**
+ * Whether to send broadcasts to registered handlers. By default, receivers are called
+ * synchronously by sendBroadcast. If this method is called with {@code true}, the receiver is
+ * instead called by a runnable posted to the Handler specified when the receiver was
+ * registered. This method applies only to future registrations, already-registered receivers
+ * are unaffected.
+ */
+ public void setUseRegisteredHandlers(boolean use) {
synchronized (mInterceptors) {
- mInterceptors.add(new BroadcastInterceptor(receiver, filter));
+ mUseRegisteredHandlers = use;
}
- return null;
+ }
+
+ @Override
+ public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
+ return registerReceiver(receiver, filter, null, null);
}
@Override
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
String broadcastPermission, Handler scheduler) {
- return registerReceiver(receiver, filter);
+ synchronized (mInterceptors) {
+ mInterceptors.add(new BroadcastInterceptor(receiver, filter, scheduler));
+ }
+ return null;
}
@Override
diff --git a/tests/vcn/java/android/net/vcn/VcnManagerTest.java b/tests/vcn/java/android/net/vcn/VcnManagerTest.java
index f9db408462b7..7dada9d1b6d4 100644
--- a/tests/vcn/java/android/net/vcn/VcnManagerTest.java
+++ b/tests/vcn/java/android/net/vcn/VcnManagerTest.java
@@ -65,7 +65,7 @@ public class VcnManagerTest {
ArgumentCaptor.forClass(IVcnUnderlyingNetworkPolicyListener.class);
verify(mMockVcnManagementService).addVcnUnderlyingNetworkPolicyListener(captor.capture());
- assertTrue(VcnManager.REGISTERED_POLICY_LISTENERS.containsKey(mMockPolicyListener));
+ assertTrue(VcnManager.getAllPolicyListeners().containsKey(mMockPolicyListener));
IVcnUnderlyingNetworkPolicyListener listenerWrapper = captor.getValue();
listenerWrapper.onPolicyChanged();
@@ -78,7 +78,7 @@ public class VcnManagerTest {
mVcnManager.removeVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
- assertFalse(VcnManager.REGISTERED_POLICY_LISTENERS.containsKey(mMockPolicyListener));
+ assertFalse(VcnManager.getAllPolicyListeners().containsKey(mMockPolicyListener));
verify(mMockVcnManagementService)
.addVcnUnderlyingNetworkPolicyListener(
any(IVcnUnderlyingNetworkPolicyListener.class));
@@ -88,7 +88,7 @@ public class VcnManagerTest {
public void testRemoveVcnUnderlyingNetworkPolicyListenerUnknownListener() throws Exception {
mVcnManager.removeVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
- assertFalse(VcnManager.REGISTERED_POLICY_LISTENERS.containsKey(mMockPolicyListener));
+ assertFalse(VcnManager.getAllPolicyListeners().containsKey(mMockPolicyListener));
verify(mMockVcnManagementService, never())
.addVcnUnderlyingNetworkPolicyListener(
any(IVcnUnderlyingNetworkPolicyListener.class));
diff --git a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
index 485964487fda..c290bff188c1 100644
--- a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
+++ b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
@@ -16,6 +16,10 @@
package com.android.server;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED;
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+
import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionTrackerCallback;
import static com.android.server.vcn.VcnTestUtils.setupSystemService;
@@ -106,6 +110,7 @@ public class VcnManagementServiceTest {
Collections.unmodifiableMap(Collections.singletonMap(TEST_UUID_1, TEST_VCN_CONFIG));
private static final int TEST_SUBSCRIPTION_ID = 1;
+ private static final int TEST_SUBSCRIPTION_ID_2 = 2;
private static final SubscriptionInfo TEST_SUBSCRIPTION_INFO =
new SubscriptionInfo(
TEST_SUBSCRIPTION_ID /* id */,
@@ -537,59 +542,121 @@ public class VcnManagementServiceTest {
Collections.singleton(subGroup), Collections.singletonMap(subId, subGroup));
}
- private void verifyMergedNetworkCapabilitiesIsVcnManaged(
- NetworkCapabilities mergedCapabilities, @Transport int transportType) {
+ private void verifyMergedNetworkCapabilities(
+ NetworkCapabilities mergedCapabilities,
+ @Transport int transportType,
+ boolean isVcnManaged,
+ boolean isRestricted) {
assertTrue(mergedCapabilities.hasTransport(transportType));
- assertFalse(
+ assertEquals(
+ !isVcnManaged,
mergedCapabilities.hasCapability(
NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED));
+ assertEquals(
+ !isRestricted,
+ mergedCapabilities.hasCapability(
+ NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED));
+ }
+
+ private void setupSubscriptionAndStartVcn(int subId, ParcelUuid subGrp, boolean isVcnActive) {
+ setUpVcnSubscription(subId, subGrp);
+ final Vcn vcn = startAndGetVcnInstance(subGrp);
+ doReturn(isVcnActive).when(vcn).isActive();
+ }
+
+ private VcnUnderlyingNetworkPolicy startVcnAndGetPolicyForTransport(
+ int subId, ParcelUuid subGrp, boolean isVcnActive, int transport) {
+ setupSubscriptionAndStartVcn(subId, subGrp, isVcnActive);
+
+ final NetworkCapabilities.Builder ncBuilder = new NetworkCapabilities.Builder();
+ ncBuilder.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
+ if (transport == TRANSPORT_CELLULAR) {
+ ncBuilder
+ .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
+ .setNetworkSpecifier(new TelephonyNetworkSpecifier(TEST_SUBSCRIPTION_ID));
+ } else if (transport == TRANSPORT_WIFI) {
+ WifiInfo wifiInfo = mock(WifiInfo.class);
+ when(wifiInfo.makeCopy(anyBoolean())).thenReturn(wifiInfo);
+ when(mMockDeps.getSubIdForWifiInfo(eq(wifiInfo))).thenReturn(TEST_SUBSCRIPTION_ID);
+
+ ncBuilder
+ .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
+ .setTransportInfo(wifiInfo);
+ } else {
+ throw new IllegalArgumentException("Unknown transport");
+ }
+
+ return mVcnMgmtSvc.getUnderlyingNetworkPolicy(ncBuilder.build(), new LinkProperties());
}
@Test
public void testGetUnderlyingNetworkPolicyCellular() throws Exception {
- setUpVcnSubscription(TEST_SUBSCRIPTION_ID, TEST_UUID_2);
+ final VcnUnderlyingNetworkPolicy policy =
+ startVcnAndGetPolicyForTransport(
+ TEST_SUBSCRIPTION_ID, TEST_UUID_2, true /* isActive */, TRANSPORT_CELLULAR);
- NetworkCapabilities nc =
- new NetworkCapabilities.Builder()
- .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
- .setNetworkSpecifier(new TelephonyNetworkSpecifier(TEST_SUBSCRIPTION_ID))
- .build();
+ assertFalse(policy.isTeardownRequested());
+ verifyMergedNetworkCapabilities(
+ policy.getMergedNetworkCapabilities(),
+ TRANSPORT_CELLULAR,
+ true /* isVcnManaged */,
+ false /* isRestricted */);
+ }
- VcnUnderlyingNetworkPolicy policy =
- mVcnMgmtSvc.getUnderlyingNetworkPolicy(nc, new LinkProperties());
+ @Test
+ public void testGetUnderlyingNetworkPolicyCellular_safeMode() throws Exception {
+ final VcnUnderlyingNetworkPolicy policy =
+ startVcnAndGetPolicyForTransport(
+ TEST_SUBSCRIPTION_ID,
+ TEST_UUID_2,
+ false /* isActive */,
+ TRANSPORT_CELLULAR);
assertFalse(policy.isTeardownRequested());
- verifyMergedNetworkCapabilitiesIsVcnManaged(
- policy.getMergedNetworkCapabilities(), NetworkCapabilities.TRANSPORT_CELLULAR);
+ verifyMergedNetworkCapabilities(
+ policy.getMergedNetworkCapabilities(),
+ NetworkCapabilities.TRANSPORT_CELLULAR,
+ false /* isVcnManaged */,
+ false /* isRestricted */);
}
@Test
public void testGetUnderlyingNetworkPolicyWifi() throws Exception {
- setUpVcnSubscription(TEST_SUBSCRIPTION_ID, TEST_UUID_2);
+ final VcnUnderlyingNetworkPolicy policy =
+ startVcnAndGetPolicyForTransport(
+ TEST_SUBSCRIPTION_ID, TEST_UUID_2, true /* isActive */, TRANSPORT_WIFI);
- WifiInfo wifiInfo = mock(WifiInfo.class);
- when(wifiInfo.makeCopy(anyBoolean())).thenReturn(wifiInfo);
- when(mMockDeps.getSubIdForWifiInfo(eq(wifiInfo))).thenReturn(TEST_SUBSCRIPTION_ID);
- NetworkCapabilities nc =
- new NetworkCapabilities.Builder()
- .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
- .setTransportInfo(wifiInfo)
- .build();
+ assertFalse(policy.isTeardownRequested());
+ verifyMergedNetworkCapabilities(
+ policy.getMergedNetworkCapabilities(),
+ NetworkCapabilities.TRANSPORT_WIFI,
+ true /* isVcnManaged */,
+ true /* isRestricted */);
+ }
- VcnUnderlyingNetworkPolicy policy =
- mVcnMgmtSvc.getUnderlyingNetworkPolicy(nc, new LinkProperties());
+ @Test
+ public void testGetUnderlyingNetworkPolicyVcnWifi_safeMode() throws Exception {
+ final VcnUnderlyingNetworkPolicy policy =
+ startVcnAndGetPolicyForTransport(
+ TEST_SUBSCRIPTION_ID, TEST_UUID_2, false /* isActive */, TRANSPORT_WIFI);
assertFalse(policy.isTeardownRequested());
- verifyMergedNetworkCapabilitiesIsVcnManaged(
- policy.getMergedNetworkCapabilities(), NetworkCapabilities.TRANSPORT_WIFI);
+ verifyMergedNetworkCapabilities(
+ policy.getMergedNetworkCapabilities(),
+ NetworkCapabilities.TRANSPORT_WIFI,
+ false /* isVcnManaged */,
+ true /* isRestricted */);
}
@Test
public void testGetUnderlyingNetworkPolicyNonVcnNetwork() throws Exception {
+ setupSubscriptionAndStartVcn(TEST_SUBSCRIPTION_ID, TEST_UUID_1, true /* isActive */);
+
NetworkCapabilities nc =
new NetworkCapabilities.Builder()
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
- .setNetworkSpecifier(new TelephonyNetworkSpecifier(TEST_SUBSCRIPTION_ID))
+ .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
+ .setNetworkSpecifier(new TelephonyNetworkSpecifier(TEST_SUBSCRIPTION_ID_2))
.build();
VcnUnderlyingNetworkPolicy policy =
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java
index 8643d8a2ea8a..16181b6f839a 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectedStateTest.java
@@ -16,12 +16,18 @@
package com.android.server.vcn;
+import static android.net.IpSecManager.IpSecTunnelInterface;
+
+import static com.android.server.vcn.VcnGatewayConnection.DUMMY_ADDR;
+
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 android.net.IpSecManager;
+
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -37,6 +43,11 @@ public class VcnGatewayConnectionDisconnectedStateTest extends VcnGatewayConnect
public void setUp() throws Exception {
super.setUp();
+ final IpSecTunnelInterface tunnelIface =
+ mContext.getSystemService(IpSecManager.class)
+ .createIpSecTunnelInterface(
+ DUMMY_ADDR, DUMMY_ADDR, TEST_UNDERLYING_NETWORK_RECORD_1.network);
+ mGatewayConnection.setTunnelInterface(tunnelIface);
mGatewayConnection.transitionTo(mGatewayConnection.mDisconnectedState);
mTestLooper.dispatchAll();
}
diff --git a/tools/hiddenapi/generate_hiddenapi_lists.py b/tools/hiddenapi/generate_hiddenapi_lists.py
deleted file mode 100755
index 28ff606d0381..000000000000
--- a/tools/hiddenapi/generate_hiddenapi_lists.py
+++ /dev/null
@@ -1,383 +0,0 @@
-#!/usr/bin/env python
-#
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-"""Generate API lists for non-SDK API enforcement."""
-import argparse
-from collections import defaultdict, namedtuple
-import functools
-import os
-import re
-import sys
-
-# Names of flags recognized by the `hiddenapi` tool.
-FLAG_SDK = 'sdk'
-FLAG_UNSUPPORTED = 'unsupported'
-FLAG_BLOCKED = 'blocked'
-FLAG_MAX_TARGET_O = 'max-target-o'
-FLAG_MAX_TARGET_P = 'max-target-p'
-FLAG_MAX_TARGET_Q = 'max-target-q'
-FLAG_MAX_TARGET_R = 'max-target-r'
-FLAG_CORE_PLATFORM_API = 'core-platform-api'
-FLAG_PUBLIC_API = 'public-api'
-FLAG_SYSTEM_API = 'system-api'
-FLAG_TEST_API = 'test-api'
-
-# List of all known flags.
-FLAGS_API_LIST = [
- FLAG_SDK,
- FLAG_UNSUPPORTED,
- FLAG_BLOCKED,
- FLAG_MAX_TARGET_O,
- FLAG_MAX_TARGET_P,
- FLAG_MAX_TARGET_Q,
- FLAG_MAX_TARGET_R,
-]
-ALL_FLAGS = FLAGS_API_LIST + [
- FLAG_CORE_PLATFORM_API,
- FLAG_PUBLIC_API,
- FLAG_SYSTEM_API,
- FLAG_TEST_API,
-]
-
-FLAGS_API_LIST_SET = set(FLAGS_API_LIST)
-ALL_FLAGS_SET = set(ALL_FLAGS)
-
-# Option specified after one of FLAGS_API_LIST to indicate that
-# only known and otherwise unassigned entries should be assign the
-# given flag.
-# For example, the max-target-P list is checked in as it was in P,
-# but signatures have changes since then. The flag instructs this
-# script to skip any entries which do not exist any more.
-FLAG_IGNORE_CONFLICTS = "ignore-conflicts"
-
-# Option specified after one of FLAGS_API_LIST to express that all
-# apis within a given set of packages should be assign the given flag.
-FLAG_PACKAGES = "packages"
-
-# Option specified after one of FLAGS_API_LIST to indicate an extra
-# tag that should be added to the matching APIs.
-FLAG_TAG = "tag"
-
-# Regex patterns of fields/methods used in serialization. These are
-# considered public API despite being hidden.
-SERIALIZATION_PATTERNS = [
- r'readObject\(Ljava/io/ObjectInputStream;\)V',
- r'readObjectNoData\(\)V',
- r'readResolve\(\)Ljava/lang/Object;',
- r'serialVersionUID:J',
- r'serialPersistentFields:\[Ljava/io/ObjectStreamField;',
- r'writeObject\(Ljava/io/ObjectOutputStream;\)V',
- r'writeReplace\(\)Ljava/lang/Object;',
-]
-
-# Single regex used to match serialization API. It combines all the
-# SERIALIZATION_PATTERNS into a single regular expression.
-SERIALIZATION_REGEX = re.compile(r'.*->(' + '|'.join(SERIALIZATION_PATTERNS) + r')$')
-
-# Predicates to be used with filter_apis.
-HAS_NO_API_LIST_ASSIGNED = lambda api, flags: not FLAGS_API_LIST_SET.intersection(flags)
-IS_SERIALIZATION = lambda api, flags: SERIALIZATION_REGEX.match(api)
-
-
-class StoreOrderedOptions(argparse.Action):
- """An argparse action that stores a number of option arguments in the order that
- they were specified.
- """
- def __call__(self, parser, args, values, option_string = None):
- items = getattr(args, self.dest, None)
- if items is None:
- items = []
- items.append([option_string.lstrip('-'), values])
- setattr(args, self.dest, items)
-
-def get_args():
- """Parses command line arguments.
-
- Returns:
- Namespace: dictionary of parsed arguments
- """
- parser = argparse.ArgumentParser()
- parser.add_argument('--output', required=True)
- parser.add_argument('--csv', nargs='*', default=[], metavar='CSV_FILE',
- help='CSV files to be merged into output')
-
- for flag in ALL_FLAGS:
- parser.add_argument('--' + flag, dest='ordered_flags', metavar='TXT_FILE',
- action=StoreOrderedOptions, help='lists of entries with flag "' + flag + '"')
- parser.add_argument('--' + FLAG_IGNORE_CONFLICTS, dest='ordered_flags', nargs=0,
- action=StoreOrderedOptions, help='Indicates that only known and otherwise unassigned '
- 'entries should be assign the given flag. Must follow a list of entries and applies '
- 'to the preceding such list.')
- parser.add_argument('--' + FLAG_PACKAGES, dest='ordered_flags', nargs=0,
- action=StoreOrderedOptions, help='Indicates that the previous list of entries '
- 'is a list of packages. All members in those packages will be given the flag. '
- 'Must follow a list of entries and applies to the preceding such list.')
- parser.add_argument('--' + FLAG_TAG, dest='ordered_flags', nargs=1,
- action=StoreOrderedOptions, help='Adds an extra tag to the previous list of entries. '
- 'Must follow a list of entries and applies to the preceding such list.')
-
- return parser.parse_args()
-
-
-def read_lines(filename):
- """Reads entire file and return it as a list of lines.
-
- Lines which begin with a hash are ignored.
-
- Args:
- filename (string): Path to the file to read from.
-
- Returns:
- Lines of the file as a list of string.
- """
- with open(filename, 'r') as f:
- lines = f.readlines();
- lines = filter(lambda line: not line.startswith('#'), lines)
- lines = map(lambda line: line.strip(), lines)
- return set(lines)
-
-
-def write_lines(filename, lines):
- """Writes list of lines into a file, overwriting the file if it exists.
-
- Args:
- filename (string): Path to the file to be writting into.
- lines (list): List of strings to write into the file.
- """
- lines = map(lambda line: line + '\n', lines)
- with open(filename, 'w') as f:
- f.writelines(lines)
-
-
-def extract_package(signature):
- """Extracts the package from a signature.
-
- Args:
- signature (string): JNI signature of a method or field.
-
- Returns:
- The package name of the class containing the field/method.
- """
- full_class_name = signature.split(";->")[0]
- # Example: Landroid/hardware/radio/V1_2/IRadio$Proxy
- if (full_class_name[0] != "L"):
- raise ValueError("Expected to start with 'L': %s" % full_class_name)
- full_class_name = full_class_name[1:]
- # If full_class_name doesn't contain '/', then package_name will be ''.
- package_name = full_class_name.rpartition("/")[0]
- return package_name.replace('/', '.')
-
-
-class FlagsDict:
- def __init__(self):
- self._dict_keyset = set()
- self._dict = defaultdict(set)
-
- def _check_entries_set(self, keys_subset, source):
- assert isinstance(keys_subset, set)
- assert keys_subset.issubset(self._dict_keyset), (
- "Error: {} specifies signatures not present in code:\n"
- "{}"
- "Please visit go/hiddenapi for more information.").format(
- source, "".join(map(lambda x: " " + str(x) + "\n", keys_subset - self._dict_keyset)))
-
- def _check_flags_set(self, flags_subset, source):
- assert isinstance(flags_subset, set)
- assert flags_subset.issubset(ALL_FLAGS_SET), (
- "Error processing: {}\n"
- "The following flags were not recognized: \n"
- "{}\n"
- "Please visit go/hiddenapi for more information.").format(
- source, "\n".join(flags_subset - ALL_FLAGS_SET))
-
- def filter_apis(self, filter_fn):
- """Returns APIs which match a given predicate.
-
- This is a helper function which allows to filter on both signatures (keys) and
- flags (values). The built-in filter() invokes the lambda only with dict's keys.
-
- Args:
- filter_fn : Function which takes two arguments (signature/flags) and returns a boolean.
-
- Returns:
- A set of APIs which match the predicate.
- """
- return set(filter(lambda x: filter_fn(x, self._dict[x]), self._dict_keyset))
-
- def get_valid_subset_of_unassigned_apis(self, api_subset):
- """Sanitizes a key set input to only include keys which exist in the dictionary
- and have not been assigned any API list flags.
-
- Args:
- entries_subset (set/list): Key set to be sanitized.
-
- Returns:
- Sanitized key set.
- """
- assert isinstance(api_subset, set)
- return api_subset.intersection(self.filter_apis(HAS_NO_API_LIST_ASSIGNED))
-
- def generate_csv(self):
- """Constructs CSV entries from a dictionary.
-
- Old versions of flags are used to generate the file.
-
- Returns:
- List of lines comprising a CSV file. See "parse_and_merge_csv" for format description.
- """
- lines = []
- for api in self._dict:
- flags = sorted(self._dict[api])
- lines.append(",".join([api] + flags))
- return sorted(lines)
-
- def parse_and_merge_csv(self, csv_lines, source = "<unknown>"):
- """Parses CSV entries and merges them into a given dictionary.
-
- The expected CSV format is:
- <api signature>,<flag1>,<flag2>,...,<flagN>
-
- Args:
- csv_lines (list of strings): Lines read from a CSV file.
- source (string): Origin of `csv_lines`. Will be printed in error messages.
-
- Throws:
- AssertionError if parsed flags are invalid.
- """
- # Split CSV lines into arrays of values.
- csv_values = [ line.split(',') for line in csv_lines ]
-
- # Update the full set of API signatures.
- self._dict_keyset.update([ csv[0] for csv in csv_values ])
-
- # Check that all flags are known.
- csv_flags = set()
- for csv in csv_values:
- csv_flags.update(csv[1:])
- self._check_flags_set(csv_flags, source)
-
- # Iterate over all CSV lines, find entry in dict and append flags to it.
- for csv in csv_values:
- flags = csv[1:]
- if (FLAG_PUBLIC_API in flags) or (FLAG_SYSTEM_API in flags):
- flags.append(FLAG_SDK)
- self._dict[csv[0]].update(flags)
-
- def assign_flag(self, flag, apis, source="<unknown>", tag = None):
- """Assigns a flag to given subset of entries.
-
- Args:
- flag (string): One of ALL_FLAGS.
- apis (set): Subset of APIs to receive the flag.
- source (string): Origin of `entries_subset`. Will be printed in error messages.
-
- Throws:
- AssertionError if parsed API signatures of flags are invalid.
- """
- # Check that all APIs exist in the dict.
- self._check_entries_set(apis, source)
-
- # Check that the flag is known.
- self._check_flags_set(set([ flag ]), source)
-
- # Iterate over the API subset, find each entry in dict and assign the flag to it.
- for api in apis:
- self._dict[api].add(flag)
- if tag:
- self._dict[api].add(tag)
-
-
-FlagFile = namedtuple('FlagFile', ('flag', 'file', 'ignore_conflicts', 'packages', 'tag'))
-
-def parse_ordered_flags(ordered_flags):
- r = []
- currentflag, file, ignore_conflicts, packages, tag = None, None, False, False, None
- for flag_value in ordered_flags:
- flag, value = flag_value[0], flag_value[1]
- if flag in ALL_FLAGS_SET:
- if currentflag:
- r.append(FlagFile(currentflag, file, ignore_conflicts, packages, tag))
- ignore_conflicts, packages, tag = False, False, None
- currentflag = flag
- file = value
- else:
- if currentflag is None:
- raise argparse.ArgumentError('--%s is only allowed after one of %s' % (
- flag, ' '.join(['--%s' % f for f in ALL_FLAGS_SET])))
- if flag == FLAG_IGNORE_CONFLICTS:
- ignore_conflicts = True
- elif flag == FLAG_PACKAGES:
- packages = True
- elif flag == FLAG_TAG:
- tag = value[0]
-
-
- if currentflag:
- r.append(FlagFile(currentflag, file, ignore_conflicts, packages, tag))
- return r
-
-
-def main(argv):
- # Parse arguments.
- args = vars(get_args())
- flagfiles = parse_ordered_flags(args['ordered_flags'])
-
- # Initialize API->flags dictionary.
- flags = FlagsDict()
-
- # Merge input CSV files into the dictionary.
- # Do this first because CSV files produced by parsing API stubs will
- # contain the full set of APIs. Subsequent additions from text files
- # will be able to detect invalid entries, and/or filter all as-yet
- # unassigned entries.
- for filename in args["csv"]:
- flags.parse_and_merge_csv(read_lines(filename), filename)
-
- # Combine inputs which do not require any particular order.
- # (1) Assign serialization API to SDK.
- flags.assign_flag(FLAG_SDK, flags.filter_apis(IS_SERIALIZATION))
-
- # (2) Merge text files with a known flag into the dictionary.
- for info in flagfiles:
- if (not info.ignore_conflicts) and (not info.packages):
- flags.assign_flag(info.flag, read_lines(info.file), info.file, info.tag)
-
- # Merge text files where conflicts should be ignored.
- # This will only assign the given flag if:
- # (a) the entry exists, and
- # (b) it has not been assigned any other flag.
- # Because of (b), this must run after all strict assignments have been performed.
- for info in flagfiles:
- if info.ignore_conflicts:
- valid_entries = flags.get_valid_subset_of_unassigned_apis(read_lines(info.file))
- flags.assign_flag(info.flag, valid_entries, filename, info.tag)
-
- # All members in the specified packages will be assigned the appropriate flag.
- for info in flagfiles:
- if info.packages:
- packages_needing_list = set(read_lines(info.file))
- should_add_signature_to_list = lambda sig,lists: extract_package(
- sig) in packages_needing_list and not lists
- valid_entries = flags.filter_apis(should_add_signature_to_list)
- flags.assign_flag(info.flag, valid_entries, info.file, info.tag)
-
- # Mark all remaining entries as blocked.
- flags.assign_flag(FLAG_BLOCKED, flags.filter_apis(HAS_NO_API_LIST_ASSIGNED))
-
- # Write output.
- write_lines(args["output"], flags.generate_csv())
-
-if __name__ == "__main__":
- main(sys.argv)
diff --git a/tools/hiddenapi/generate_hiddenapi_lists_test.py b/tools/hiddenapi/generate_hiddenapi_lists_test.py
deleted file mode 100755
index 82d117fbbbab..000000000000
--- a/tools/hiddenapi/generate_hiddenapi_lists_test.py
+++ /dev/null
@@ -1,104 +0,0 @@
-#!/usr/bin/env python
-#
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the 'License');
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an 'AS IS' BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-"""Unit tests for Hidden API list generation."""
-import unittest
-from generate_hiddenapi_lists import *
-
-class TestHiddenapiListGeneration(unittest.TestCase):
-
- def test_filter_apis(self):
- # Initialize flags so that A and B are put on the whitelist and
- # C, D, E are left unassigned. Try filtering for the unassigned ones.
- flags = FlagsDict()
- flags.parse_and_merge_csv(['A,' + FLAG_SDK, 'B,' + FLAG_SDK,
- 'C', 'D', 'E'])
- filter_set = flags.filter_apis(lambda api, flags: not flags)
- self.assertTrue(isinstance(filter_set, set))
- self.assertEqual(filter_set, set([ 'C', 'D', 'E' ]))
-
- def test_get_valid_subset_of_unassigned_keys(self):
- # Create flags where only A is unassigned.
- flags = FlagsDict()
- flags.parse_and_merge_csv(['A,' + FLAG_SDK, 'B', 'C'])
- flags.assign_flag(FLAG_UNSUPPORTED, set(['C']))
- self.assertEqual(flags.generate_csv(),
- [ 'A,' + FLAG_SDK, 'B', 'C,' + FLAG_UNSUPPORTED ])
-
- # Check three things:
- # (1) B is selected as valid unassigned
- # (2) A is not selected because it is assigned 'whitelist'
- # (3) D is not selected because it is not a valid key
- self.assertEqual(
- flags.get_valid_subset_of_unassigned_apis(set(['A', 'B', 'D'])), set([ 'B' ]))
-
- def test_parse_and_merge_csv(self):
- flags = FlagsDict()
-
- # Test empty CSV entry.
- self.assertEqual(flags.generate_csv(), [])
-
- # Test new additions.
- flags.parse_and_merge_csv([
- 'A,' + FLAG_UNSUPPORTED,
- 'B,' + FLAG_BLOCKED + ',' + FLAG_MAX_TARGET_O,
- 'C,' + FLAG_SDK + ',' + FLAG_SYSTEM_API,
- 'D,' + FLAG_UNSUPPORTED + ',' + FLAG_TEST_API,
- 'E,' + FLAG_BLOCKED + ',' + FLAG_TEST_API,
- ])
- self.assertEqual(flags.generate_csv(), [
- 'A,' + FLAG_UNSUPPORTED,
- 'B,' + FLAG_BLOCKED + "," + FLAG_MAX_TARGET_O,
- 'C,' + FLAG_SYSTEM_API + ',' + FLAG_SDK,
- 'D,' + FLAG_UNSUPPORTED + ',' + FLAG_TEST_API,
- 'E,' + FLAG_BLOCKED + ',' + FLAG_TEST_API,
- ])
-
- # Test unknown flag.
- with self.assertRaises(AssertionError):
- flags.parse_and_merge_csv([ 'Z,foo' ])
-
- def test_assign_flag(self):
- flags = FlagsDict()
- flags.parse_and_merge_csv(['A,' + FLAG_SDK, 'B'])
-
- # Test new additions.
- flags.assign_flag(FLAG_UNSUPPORTED, set([ 'A', 'B' ]))
- self.assertEqual(flags.generate_csv(),
- [ 'A,' + FLAG_UNSUPPORTED + "," + FLAG_SDK, 'B,' + FLAG_UNSUPPORTED ])
-
- # Test invalid API signature.
- with self.assertRaises(AssertionError):
- flags.assign_flag(FLAG_SDK, set([ 'C' ]))
-
- # Test invalid flag.
- with self.assertRaises(AssertionError):
- flags.assign_flag('foo', set([ 'A' ]))
-
- def test_extract_package(self):
- signature = 'Lcom/foo/bar/Baz;->method1()Lcom/bar/Baz;'
- expected_package = 'com.foo.bar'
- self.assertEqual(extract_package(signature), expected_package)
-
- signature = 'Lcom/foo1/bar/MyClass;->method2()V'
- expected_package = 'com.foo1.bar'
- self.assertEqual(extract_package(signature), expected_package)
-
- signature = 'Lcom/foo_bar/baz/MyClass;->method3()V'
- expected_package = 'com.foo_bar.baz'
- self.assertEqual(extract_package(signature), expected_package)
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/tools/hiddenapi/merge_csv.py b/tools/hiddenapi/merge_csv.py
deleted file mode 100755
index 6a5b0e1347b2..000000000000
--- a/tools/hiddenapi/merge_csv.py
+++ /dev/null
@@ -1,69 +0,0 @@
-#!/usr/bin/env python
-#
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-"""
-Merge multiple CSV files, possibly with different columns.
-"""
-
-import argparse
-import csv
-import io
-
-from zipfile import ZipFile
-
-args_parser = argparse.ArgumentParser(description='Merge given CSV files into a single one.')
-args_parser.add_argument('--header', help='Comma separated field names; '
- 'if missing determines the header from input files.')
-args_parser.add_argument('--zip_input', help='ZIP archive with all CSV files to merge.')
-args_parser.add_argument('--output', help='Output file for merged CSV.',
- default='-', type=argparse.FileType('w'))
-args_parser.add_argument('files', nargs=argparse.REMAINDER)
-args = args_parser.parse_args()
-
-
-def dict_reader(input):
- return csv.DictReader(input, delimiter=',', quotechar='|')
-
-
-if args.zip_input and len(args.files) > 0:
- raise ValueError('Expecting either a single ZIP with CSV files'
- ' or a list of CSV files as input; not both.')
-
-csv_readers = []
-if len(args.files) > 0:
- for file in args.files:
- csv_readers.append(dict_reader(open(file, 'r')))
-elif args.zip_input:
- with ZipFile(args.zip_input) as zip:
- for entry in zip.namelist():
- if entry.endswith('.uau'):
- csv_readers.append(dict_reader(io.TextIOWrapper(zip.open(entry, 'r'))))
-
-headers = set()
-if args.header:
- fieldnames = args.header.split(',')
-else:
- # Build union of all columns from source files:
- for reader in csv_readers:
- headers = headers.union(reader.fieldnames)
- fieldnames = sorted(headers)
-
-# Concatenate all files to output:
-writer = csv.DictWriter(args.output, delimiter=',', quotechar='|', quoting=csv.QUOTE_MINIMAL,
- dialect='unix', fieldnames=fieldnames)
-writer.writeheader()
-for reader in csv_readers:
- for row in reader:
- writer.writerow(row)