summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp77
-rw-r--r--ApiDocs.bp6
-rw-r--r--StubLibraries.bp11
-rw-r--r--apex/jobscheduler/framework/java/android/app/job/JobInfo.java35
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/JobStore.java34
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java25
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java12
-rw-r--r--apex/media/framework/Android.bp15
-rw-r--r--core/api/current.txt19
-rw-r--r--core/api/module-lib-current.txt9
-rw-r--r--core/api/system-current.txt78
-rw-r--r--core/api/system-removed.txt8
-rw-r--r--core/api/test-current.txt7
-rw-r--r--core/java/android/annotation/MainThread.java5
-rw-r--r--core/java/android/app/compat/CompatChanges.java9
-rw-r--r--core/java/android/app/compat/PackageOverride.java49
-rw-r--r--core/java/android/bluetooth/BluetoothHeadset.java1
-rw-r--r--core/java/android/bluetooth/le/ScanFilter.java2
-rw-r--r--core/java/android/content/OWNERS2
-rw-r--r--core/java/android/content/pm/ApplicationInfo.java15
-rw-r--r--core/java/android/content/pm/PackageManager.java53
-rw-r--r--core/java/android/net/NetworkPolicyManager.java129
-rw-r--r--core/java/android/net/netstats/provider/INetworkStatsProvider.aidl2
-rw-r--r--core/java/android/net/netstats/provider/INetworkStatsProviderCallback.aidl2
-rw-r--r--core/java/android/net/netstats/provider/NetworkStatsProvider.java51
-rw-r--r--core/java/android/net/vcn/IVcnManagementService.aidl2
-rw-r--r--core/java/android/net/vcn/VcnManager.java8
-rw-r--r--core/java/android/nfc/INfcAdapter.aidl6
-rw-r--r--core/java/android/nfc/NfcAdapter.java24
-rw-r--r--core/java/android/os/Binder.java10
-rw-r--r--core/java/android/os/Process.java1
-rwxr-xr-xcore/java/android/provider/Settings.java4
-rw-r--r--core/java/android/provider/Telephony.java27
-rw-r--r--core/java/android/uwb/AngleMeasurement.java5
-rw-r--r--core/java/android/view/OWNERS1
-rw-r--r--core/java/com/android/internal/compat/CompatibilityOverrideConfig.java5
-rw-r--r--core/java/com/android/internal/compat/IPlatformCompat.aidl14
-rw-r--r--core/java/com/android/internal/telephony/ITelephonyRegistry.aidl1
-rw-r--r--core/jni/android_net_NetworkUtils.cpp6
-rw-r--r--core/jni/android_util_Binder.cpp13
-rw-r--r--core/res/AndroidManifest.xml37
-rw-r--r--core/res/res/values/config.xml9
-rw-r--r--core/res/res/values/symbols.xml2
-rw-r--r--core/tests/coretests/src/android/content/OWNERS2
-rw-r--r--data/etc/OWNERS1
-rw-r--r--data/etc/privapp-permissions-platform.xml2
-rw-r--r--graphics/java/android/graphics/Typeface.java10
-rw-r--r--keystore/java/android/security/AndroidKeyStoreMaintenance.java14
-rw-r--r--keystore/java/android/security/GenerateRkpKey.java99
-rw-r--r--keystore/java/android/security/GenerateRkpKeyException.java31
-rw-r--r--keystore/java/android/security/IGenerateRkpKeyService.aidl36
-rw-r--r--keystore/java/android/security/KeyStore.java1
-rw-r--r--keystore/java/android/security/KeyStore2.java9
-rw-r--r--keystore/java/android/security/keystore/KeyGenParameterSpec.java10
-rw-r--r--keystore/java/android/security/keystore/KeyProperties.java24
-rw-r--r--keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java34
-rw-r--r--keystore/java/android/security/keystore2/AndroidKeyStoreLoadStoreParameter.java8
-rw-r--r--keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java4
-rw-r--r--media/java/android/media/MediaCodec.java148
-rw-r--r--media/jni/android_media_MediaCodec.cpp187
-rw-r--r--media/jni/android_media_MediaCodec.h8
-rw-r--r--packages/Connectivity/framework/api/current.txt4
-rw-r--r--packages/Connectivity/framework/api/module-lib-current.txt75
-rw-r--r--packages/Connectivity/framework/api/system-current.txt30
-rw-r--r--packages/Connectivity/framework/src/android/net/ConnectivityManager.java241
-rw-r--r--packages/Connectivity/framework/src/android/net/ConnectivitySettingsManager.java690
-rw-r--r--packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl2
-rw-r--r--packages/Connectivity/framework/src/android/net/INetworkAgent.aidl2
-rw-r--r--packages/Connectivity/framework/src/android/net/INetworkAgentRegistry.aidl3
-rw-r--r--packages/Connectivity/framework/src/android/net/IQosCallback.aidl3
-rw-r--r--packages/Connectivity/framework/src/android/net/NetworkAgent.java122
-rw-r--r--packages/Connectivity/framework/src/android/net/NetworkAgentConfig.java68
-rw-r--r--packages/Connectivity/framework/src/android/net/NetworkCapabilities.java33
-rw-r--r--packages/Connectivity/framework/src/android/net/NetworkRequest.java67
-rw-r--r--packages/Connectivity/framework/src/android/net/NetworkScore.java5
-rw-r--r--packages/Connectivity/framework/src/android/net/NetworkUtils.java5
-rw-r--r--packages/Connectivity/framework/src/android/net/QosCallbackConnection.java20
-rw-r--r--packages/Connectivity/framework/src/android/net/QosSession.java6
-rw-r--r--packages/Connectivity/framework/src/android/net/SocketKeepalive.java84
-rw-r--r--packages/Shell/AndroidManifest.xml7
-rw-r--r--packages/SystemUI/OWNERS6
-rw-r--r--packages/VpnDialogs/res/values/strings.xml11
-rw-r--r--services/api/current.txt8
-rw-r--r--services/api/non-updatable-current.txt8
-rw-r--r--services/core/Android.bp1
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java317
-rw-r--r--services/core/java/com/android/server/IpSecService.java2
-rw-r--r--services/core/java/com/android/server/PinnerService.java39
-rw-r--r--services/core/java/com/android/server/TelephonyRegistry.java67
-rw-r--r--services/core/java/com/android/server/VcnManagementService.java49
-rw-r--r--services/core/java/com/android/server/apphibernation/AppHibernationService.java76
-rw-r--r--services/core/java/com/android/server/apphibernation/HibernationStateDiskStore.java1
-rw-r--r--services/core/java/com/android/server/clipboard/ClipboardService.java37
-rw-r--r--services/core/java/com/android/server/compat/CompatChange.java14
-rw-r--r--services/core/java/com/android/server/compat/CompatConfig.java17
-rw-r--r--services/core/java/com/android/server/compat/OverrideValidatorImpl.java32
-rw-r--r--services/core/java/com/android/server/compat/PlatformCompat.java28
-rw-r--r--services/core/java/com/android/server/connectivity/KeepaliveTracker.java3
-rw-r--r--services/core/java/com/android/server/connectivity/NetdEventListenerService.java38
-rw-r--r--services/core/java/com/android/server/connectivity/NetworkAgentInfo.java40
-rw-r--r--services/core/java/com/android/server/connectivity/PermissionMonitor.java7
-rw-r--r--services/core/java/com/android/server/connectivity/QosCallbackAgentConnection.java17
-rw-r--r--services/core/java/com/android/server/connectivity/QosCallbackTracker.java23
-rw-r--r--services/core/java/com/android/server/connectivity/Vpn.java92
-rw-r--r--services/core/java/com/android/server/display/BrightnessMappingStrategy.java5
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java27
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiControlShellCommand.java101
-rw-r--r--services/core/java/com/android/server/locksettings/RebootEscrowManager.java151
-rw-r--r--services/core/java/com/android/server/locksettings/RebootEscrowProviderHalImpl.java5
-rw-r--r--services/core/java/com/android/server/locksettings/RebootEscrowProviderInterface.java19
-rw-r--r--services/core/java/com/android/server/locksettings/RebootEscrowProviderServerBasedImpl.java5
-rw-r--r--services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java5
-rw-r--r--services/core/java/com/android/server/net/NetworkPolicyManagerService.java172
-rw-r--r--services/core/java/com/android/server/net/NetworkStatsManagerInternal.java5
-rw-r--r--services/core/java/com/android/server/net/NetworkStatsService.java59
-rw-r--r--services/core/java/com/android/server/notification/PreferencesHelper.java44
-rw-r--r--services/core/java/com/android/server/os/NativeTombstoneManager.java10
-rw-r--r--services/core/java/com/android/server/pm/PackageDexOptimizer.java12
-rw-r--r--services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java47
-rw-r--r--services/core/java/com/android/server/recoverysystem/RecoverySystemService.java23
-rw-r--r--services/core/java/com/android/server/stats/StatsHelper.java45
-rw-r--r--services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java6
-rw-r--r--services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java30
-rw-r--r--services/core/java/com/android/server/vcn/Vcn.java76
-rw-r--r--services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java56
-rw-r--r--services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java13
-rw-r--r--services/tests/servicestests/src/com/android/server/compat/CompatConfigBuilder.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java45
-rw-r--r--services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java2
-rw-r--r--services/tests/servicestests/src/com/android/server/content/OWNERS1
-rw-r--r--services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java124
-rw-r--r--services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java84
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/dex/ArtStatsLogUtilsTest.java58
-rw-r--r--services/tests/servicestests/utils-mockito/com/android/server/testutils/OWNERS1
-rwxr-xr-xservices/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java82
-rw-r--r--services/usb/java/com/android/server/usb/UsbDeviceManager.java37
-rw-r--r--telephony/java/android/telephony/CarrierConfigManager.java105
-rw-r--r--telephony/java/android/telephony/PhysicalChannelConfig.java25
-rw-r--r--telephony/java/android/telephony/ServiceState.java1
-rw-r--r--telephony/java/android/telephony/SmsMessage.java22
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java192
-rw-r--r--telephony/java/android/telephony/data/EpsBearerQosSessionAttributes.java10
-rw-r--r--telephony/java/android/telephony/data/NrQos.java12
-rw-r--r--telephony/java/android/telephony/data/NrQosSessionAttributes.aidl19
-rw-r--r--telephony/java/android/telephony/data/NrQosSessionAttributes.java259
-rw-r--r--telephony/java/android/telephony/ims/RcsContactUceCapability.java28
-rw-r--r--telephony/java/android/telephony/ims/aidl/CapabilityExchangeAidlWrapper.java8
-rw-r--r--telephony/java/android/telephony/ims/feature/RcsFeature.java37
-rw-r--r--telephony/java/android/telephony/ims/stub/CapabilityExchangeEventListener.java7
-rw-r--r--telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java34
-rw-r--r--telephony/java/com/android/internal/telephony/ITelephony.aidl14
-rw-r--r--tests/net/common/java/android/net/NetworkAgentConfigTest.kt9
-rw-r--r--tests/net/common/java/android/net/NetworkCapabilitiesTest.java44
-rw-r--r--tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt2
-rw-r--r--tests/net/java/android/net/ConnectivityManagerTest.java39
-rw-r--r--tests/net/java/com/android/server/ConnectivityServiceTest.java426
-rw-r--r--tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java31
-rw-r--r--tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java28
-rw-r--r--tests/net/java/com/android/server/net/NetworkStatsServiceTest.java86
-rw-r--r--tests/vcn/java/android/net/vcn/VcnManagerTest.java2
-rw-r--r--tests/vcn/java/com/android/server/VcnManagementServiceTest.java81
-rw-r--r--tests/vcn/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java16
-rw-r--r--tests/vcn/java/com/android/server/vcn/VcnTest.java79
163 files changed, 5562 insertions, 1265 deletions
diff --git a/Android.bp b/Android.bp
index c9ed7ede26ba..3fb03c245d25 100644
--- a/Android.bp
+++ b/Android.bp
@@ -306,8 +306,8 @@ filegroup {
genrule {
name: "statslog-telephony-common-java-gen",
tools: ["stats-log-api-gen"],
- cmd: "$(location stats-log-api-gen) --java $(out) --module telephony_common"
- + " --javaPackage com.android.internal.telephony --javaClass TelephonyCommonStatsLog",
+ cmd: "$(location stats-log-api-gen) --java $(out) --module telephony_common" +
+ " --javaPackage com.android.internal.telephony --javaClass TelephonyCommonStatsLog",
out: ["com/android/internal/telephony/TelephonyCommonStatsLog.java"],
}
@@ -383,6 +383,7 @@ filegroup {
":libbluetooth-binder-aidl",
":libcamera_client_aidl",
":libcamera_client_framework_aidl",
+ ":packagemanager_aidl",
":libupdate_engine_aidl",
":resourcemanager_aidl",
":storaged_aidl",
@@ -453,15 +454,6 @@ java_library {
],
}
-filegroup {
- name: "framework-all-sources",
- srcs: [
- ":framework-mime-sources",
- ":framework-non-updatable-sources",
- ":framework-updatable-sources",
- ],
-}
-
// AIDL files under these paths are mixture of public and private ones.
// They shouldn't be exported across module boundaries.
java_defaults {
@@ -607,7 +599,6 @@ java_library {
// TODO: remove gps_debug and protolog.conf.json when the build system propagates "required" properly.
"gps_debug.conf",
"icu4j-platform-compat-config",
- "libcore-platform-compat-config",
"protolog.conf.json.gz",
"services-platform-compat-config",
"documents-ui-compat-config",
@@ -687,7 +678,7 @@ genrule {
name: "statslog-framework-java-gen",
tools: ["stats-log-api-gen"],
cmd: "$(location stats-log-api-gen) --java $(out) --module framework" +
- " --javaPackage com.android.internal.util --javaClass FrameworkStatsLog --worksource",
+ " --javaPackage com.android.internal.util --javaClass FrameworkStatsLog --worksource",
out: ["com/android/internal/util/FrameworkStatsLog.java"],
}
@@ -764,13 +755,21 @@ gensrcs {
filegroup {
name: "framework-annotations",
srcs: [
+ "core/java/android/annotation/AnyThread.java",
+ "core/java/android/annotation/AppIdInt.java",
+ "core/java/android/annotation/BytesLong.java",
"core/java/android/annotation/CallbackExecutor.java",
+ "core/java/android/annotation/CallSuper.java",
"core/java/android/annotation/CheckResult.java",
"core/java/android/annotation/CurrentTimeMillisLong.java",
+ "core/java/android/annotation/CurrentTimeSecondsLong.java",
+ "core/java/android/annotation/DrawableRes.java",
+ "core/java/android/annotation/DurationMillisLong.java",
"core/java/android/annotation/Hide.java",
"core/java/android/annotation/IntDef.java",
"core/java/android/annotation/IntRange.java",
"core/java/android/annotation/LongDef.java",
+ "core/java/android/annotation/MainThread.java",
"core/java/android/annotation/NonNull.java",
"core/java/android/annotation/Nullable.java",
"core/java/android/annotation/RequiresPermission.java",
@@ -779,16 +778,17 @@ filegroup {
"core/java/android/annotation/SystemApi.java",
"core/java/android/annotation/SystemService.java",
"core/java/android/annotation/TestApi.java",
+ "core/java/android/annotation/UserIdInt.java",
"core/java/android/annotation/WorkerThread.java",
"core/java/com/android/internal/annotations/GuardedBy.java",
- "core/java/com/android/internal/annotations/VisibleForTesting.java",
"core/java/com/android/internal/annotations/Immutable.java",
+ "core/java/com/android/internal/annotations/VisibleForTesting.java",
],
}
java_library {
name: "framework-annotations-lib",
- srcs: [ ":framework-annotations" ],
+ srcs: [":framework-annotations"],
sdk_version: "core_current",
}
@@ -796,7 +796,6 @@ filegroup {
name: "framework-ike-shared-srcs",
visibility: ["//packages/modules/IPsec"],
srcs: [
- "core/java/android/annotation/StringDef.java",
"core/java/android/net/annotations/PolicyDirection.java",
"core/java/com/android/internal/util/HexDump.java",
"core/java/com/android/internal/util/IState.java",
@@ -1015,7 +1014,6 @@ cc_library {
},
}
-
// This is the full proto version of libplatformprotos. It may only
// be used by test code that is not shipped on the device.
cc_library {
@@ -1176,7 +1174,7 @@ java_library {
"core/java/android/os/RemoteException.java",
"core/java/android/util/AndroidException.java",
],
- libs: [ "unsupportedappusage" ],
+ libs: ["unsupportedappusage"],
dxflags: ["--core-library"],
installable: false,
@@ -1208,36 +1206,6 @@ python_binary_host {
],
}
-filegroup {
- name: "framework-media-annotation-srcs",
- srcs: [
- ":framework-annotations",
- "core/java/android/annotation/CallbackExecutor.java",
- "core/java/android/annotation/CallSuper.java",
- "core/java/android/annotation/DrawableRes.java",
- "core/java/android/annotation/LongDef.java",
- "core/java/android/annotation/StringDef.java",
- ],
-}
-
-filegroup {
- name: "framework-mediaprovider-annotation-sources",
- srcs: [
- ":framework-annotations",
- "core/java/android/annotation/BytesLong.java",
- "core/java/android/annotation/CurrentTimeSecondsLong.java",
- "core/java/android/annotation/DurationMillisLong.java",
- ],
-}
-
-// Creates an index of AIDL methods; used for adding UnsupportedAppUsage
-// annotations to private apis
-aidl_mapping {
- name: "framework-aidl-mappings",
- srcs: [":framework-all-sources"],
- output: "framework-aidl-mappings.txt",
-}
-
// Avoid including Parcelable classes as we don't want to have two copies of
// Parcelable cross the libraries. This is used by telephony-common (frameworks/opt/telephony)
// and TeleService app (packages/services/Telephony).
@@ -1359,6 +1327,19 @@ metalava_framework_docs_args = "--manifest $(location core/res/AndroidManifest.x
"--api-lint-ignore-prefix junit. " +
"--api-lint-ignore-prefix org. "
+filegroup {
+ name: "framework-non-updatable-stub-sources",
+ srcs: [
+ ":framework-mime-sources", // mimemap builds separately but has no separate droidstubs.
+ ":framework-non-updatable-sources",
+ ":opt-telephony-srcs",
+ ":opt-net-voip-srcs",
+ "core/java/**/*.logtags",
+ "**/package.html",
+ ],
+ visibility: ["//visibility:private"],
+}
+
build = [
"StubLibraries.bp",
"ApiDocs.bp",
diff --git a/ApiDocs.bp b/ApiDocs.bp
index ada80bbc9874..ff3dc8db1ee5 100644
--- a/ApiDocs.bp
+++ b/ApiDocs.bp
@@ -58,13 +58,9 @@ framework_docs_only_libs = [
stubs_defaults {
name: "framework-doc-stubs-default",
srcs: [
- ":framework-mime-sources",
- ":framework-non-updatable-sources",
+ ":framework-non-updatable-stub-sources",
":framework-updatable-sources",
- "core/java/**/*.logtags",
"test-base/src/**/*.java",
- ":opt-telephony-srcs",
- ":opt-net-voip-srcs",
":art.module.public.api{.public.stubs.source}",
":conscrypt.module.public.api{.public.stubs.source}",
":i18n.module.public.api{.public.stubs.source}",
diff --git a/StubLibraries.bp b/StubLibraries.bp
index fd614a7e3dc3..1644a550aca5 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -42,13 +42,7 @@ packages_to_document = [
stubs_defaults {
name: "metalava-non-updatable-api-stubs-default",
- srcs: [
- ":framework-non-updatable-sources",
- "core/java/**/*.logtags",
- ":opt-telephony-srcs",
- ":opt-net-voip-srcs",
- "**/package.html",
- ],
+ srcs: [":framework-non-updatable-stub-sources"],
sdk_version: "none",
system_modules: "none",
java_version: "1.8",
@@ -434,6 +428,7 @@ droidstubs {
"core/java/android/os/RemoteException.java",
"core/java/android/util/AndroidException.java",
],
+ libs: ["framework-annotations-lib"],
installable: false,
sdk_version: "core_platform",
annotations_enabled: true,
@@ -447,7 +442,7 @@ droidstubs {
java_library_static {
name: "hwbinder.stubs",
sdk_version: "core_current",
- libs: ["stub-annotations"],
+ libs: ["framework-annotations-lib"],
srcs: [
":hwbinder-stubs-docs",
],
diff --git a/apex/jobscheduler/framework/java/android/app/job/JobInfo.java b/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
index 24b8055b9a57..a3fa8ac9958c 100644
--- a/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
+++ b/apex/jobscheduler/framework/java/android/app/job/JobInfo.java
@@ -1006,6 +1006,41 @@ public class JobInfo implements Parcelable {
mJobId = jobId;
}
+ /**
+ * Creates a new Builder of JobInfo from an existing instance.
+ * @hide
+ */
+ public Builder(@NonNull JobInfo job) {
+ mJobId = job.getId();
+ mJobService = job.getService();
+ mExtras = job.getExtras();
+ mTransientExtras = job.getTransientExtras();
+ mClipData = job.getClipData();
+ mClipGrantFlags = job.getClipGrantFlags();
+ mPriority = job.getPriority();
+ mFlags = job.getFlags();
+ mConstraintFlags = job.getConstraintFlags();
+ mNetworkRequest = job.getRequiredNetwork();
+ mNetworkDownloadBytes = job.getEstimatedNetworkDownloadBytes();
+ mNetworkUploadBytes = job.getEstimatedNetworkUploadBytes();
+ mTriggerContentUris = job.getTriggerContentUris() != null
+ ? new ArrayList<>(Arrays.asList(job.getTriggerContentUris())) : null;
+ mTriggerContentUpdateDelay = job.getTriggerContentUpdateDelay();
+ mTriggerContentMaxDelay = job.getTriggerContentMaxDelay();
+ mIsPersisted = job.isPersisted();
+ mMinLatencyMillis = job.getMinLatencyMillis();
+ mMaxExecutionDelayMillis = job.getMaxExecutionDelayMillis();
+ mIsPeriodic = job.isPeriodic();
+ mHasEarlyConstraint = job.hasEarlyConstraint();
+ mHasLateConstraint = job.hasLateConstraint();
+ mIntervalMillis = job.getIntervalMillis();
+ mFlexMillis = job.getFlexMillis();
+ mInitialBackoffMillis = job.getInitialBackoffMillis();
+ // mBackoffPolicySet isn't set but it's fine since this is copying from an already valid
+ // job.
+ mBackoffPolicy = job.getBackoffPolicy();
+ }
+
/** @hide */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public Builder setPriority(int priority) {
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobStore.java b/apex/jobscheduler/service/java/com/android/server/job/JobStore.java
index 2f5f555817ec..26010ef6d55c 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobStore.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobStore.java
@@ -532,18 +532,23 @@ public final class JobStore {
/**
* Write out a tag with data identifying this job's constraints. If the constraint isn't here
* it doesn't apply.
+ * TODO: b/183455312 Update this code to use proper serialization for NetworkRequest,
+ * because currently store is not including everything (like, UIDs, bandwidth,
+ * signal strength etc. are lost).
*/
private void writeConstraintsToXml(XmlSerializer out, JobStatus jobStatus) throws IOException {
out.startTag(null, XML_TAG_PARAMS_CONSTRAINTS);
if (jobStatus.hasConnectivityConstraint()) {
final NetworkRequest network = jobStatus.getJob().getRequiredNetwork();
+ // STOPSHIP b/183071974: improve the scheme for backward compatibility and
+ // mainline cleanliness.
out.attribute(null, "net-capabilities", Long.toString(
- BitUtils.packBits(network.networkCapabilities.getCapabilities())));
+ BitUtils.packBits(network.getCapabilities())));
out.attribute(null, "net-unwanted-capabilities", Long.toString(
- BitUtils.packBits(network.networkCapabilities.getUnwantedCapabilities())));
+ BitUtils.packBits(network.getUnwantedCapabilities())));
out.attribute(null, "net-transport-types", Long.toString(
- BitUtils.packBits(network.networkCapabilities.getTransportTypes())));
+ BitUtils.packBits(network.getTransportTypes())));
}
if (jobStatus.hasIdleConstraint()) {
out.attribute(null, "idle", Boolean.toString(true));
@@ -967,18 +972,23 @@ public final class JobStore {
null, "net-unwanted-capabilities");
final String netTransportTypes = parser.getAttributeValue(null, "net-transport-types");
if (netCapabilities != null && netTransportTypes != null) {
- final NetworkRequest request = new NetworkRequest.Builder().build();
+ final NetworkRequest.Builder builder = new NetworkRequest.Builder()
+ .clearCapabilities();
final long unwantedCapabilities = netUnwantedCapabilities != null
? Long.parseLong(netUnwantedCapabilities)
- : BitUtils.packBits(request.networkCapabilities.getUnwantedCapabilities());
-
+ : BitUtils.packBits(builder.build().getUnwantedCapabilities());
// We're okay throwing NFE here; caught by caller
- request.networkCapabilities.setCapabilities(
- BitUtils.unpackBits(Long.parseLong(netCapabilities)),
- BitUtils.unpackBits(unwantedCapabilities));
- request.networkCapabilities.setTransportTypes(
- BitUtils.unpackBits(Long.parseLong(netTransportTypes)));
- jobBuilder.setRequiredNetwork(request);
+ for (int capability : BitUtils.unpackBits(Long.parseLong(netCapabilities))) {
+ builder.addCapability(capability);
+ }
+ for (int unwantedCapability : BitUtils.unpackBits(
+ Long.parseLong(netUnwantedCapabilities))) {
+ builder.addUnwantedCapability(unwantedCapability);
+ }
+ for (int transport : BitUtils.unpackBits(Long.parseLong(netTransportTypes))) {
+ builder.addTransportType(transport);
+ }
+ jobBuilder.setRequiredNetwork(builder.build());
} else {
// Read legacy values
val = parser.getAttributeValue(null, "connectivity");
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
index 4f472dfc31dd..a52223792b7a 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/ConnectivityController.java
@@ -21,6 +21,7 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
import static com.android.server.job.JobSchedulerService.RESTRICTED_INDEX;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.job.JobInfo;
import android.net.ConnectivityManager;
@@ -373,15 +374,23 @@ public final class ConnectivityController extends RestrictingController implemen
}
}
+ private static NetworkCapabilities.Builder copyCapabilities(
+ @NonNull final NetworkRequest request) {
+ final NetworkCapabilities.Builder builder = new NetworkCapabilities.Builder();
+ for (int transport : request.getTransportTypes()) builder.addTransportType(transport);
+ for (int capability : request.getCapabilities()) builder.addCapability(capability);
+ return builder;
+ }
+
private static boolean isStrictSatisfied(JobStatus jobStatus, Network network,
NetworkCapabilities capabilities, Constants constants) {
// A restricted job that's out of quota MUST use an unmetered network.
if (jobStatus.getEffectiveStandbyBucket() == RESTRICTED_INDEX
&& !jobStatus.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA)) {
- final NetworkCapabilities required = new NetworkCapabilities.Builder(
- jobStatus.getJob().getRequiredNetwork().networkCapabilities)
- .addCapability(NET_CAPABILITY_NOT_METERED).build();
- return required.satisfiedByNetworkCapabilities(capabilities);
+ final NetworkCapabilities.Builder builder =
+ copyCapabilities(jobStatus.getJob().getRequiredNetwork());
+ builder.addCapability(NET_CAPABILITY_NOT_METERED);
+ return builder.build().satisfiedByNetworkCapabilities(capabilities);
} else {
return jobStatus.getJob().getRequiredNetwork().canBeSatisfiedBy(capabilities);
}
@@ -395,10 +404,10 @@ public final class ConnectivityController extends RestrictingController implemen
}
// See if we match after relaxing any unmetered request
- final NetworkCapabilities relaxed = new NetworkCapabilities.Builder(
- jobStatus.getJob().getRequiredNetwork().networkCapabilities)
- .removeCapability(NET_CAPABILITY_NOT_METERED).build();
- if (relaxed.satisfiedByNetworkCapabilities(capabilities)) {
+ final NetworkCapabilities.Builder builder =
+ copyCapabilities(jobStatus.getJob().getRequiredNetwork());
+ builder.removeCapability(NET_CAPABILITY_NOT_METERED);
+ if (builder.build().satisfiedByNetworkCapabilities(capabilities)) {
// TODO: treat this as "maybe" response; need to check quotas
return jobStatus.getFractionRunTime() > constants.CONN_PREFETCH_RELAX_FRAC;
} else {
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
index d7be2595e88b..ea8e7bc4ab06 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
@@ -28,6 +28,7 @@ import android.app.job.JobWorkItem;
import android.content.ClipData;
import android.content.ComponentName;
import android.net.Network;
+import android.net.NetworkRequest;
import android.net.Uri;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -35,6 +36,7 @@ import android.provider.MediaStore;
import android.text.format.DateFormat;
import android.util.ArraySet;
import android.util.Pair;
+import android.util.Range;
import android.util.Slog;
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
@@ -52,6 +54,7 @@ import com.android.server.job.JobStatusShortInfoProto;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.function.Predicate;
/**
@@ -486,8 +489,15 @@ public final class JobStatus {
// Later, when we check if a given network satisfies the required
// network, we need to know the UID that is requesting it, so push
// our source UID into place.
- job.getRequiredNetwork().networkCapabilities.setSingleUid(this.sourceUid);
+ final JobInfo.Builder builder = new JobInfo.Builder(job);
+ final NetworkRequest.Builder requestBuilder =
+ new NetworkRequest.Builder(job.getRequiredNetwork());
+ requestBuilder.setUids(
+ Collections.singleton(new Range<Integer>(this.sourceUid, this.sourceUid)));
+ builder.setRequiredNetwork(requestBuilder.build());
+ job = builder.build();
}
+
final JobSchedulerInternal jsi = LocalServices.getService(JobSchedulerInternal.class);
mHasMediaBackupExemption = !job.hasLateConstraint() && exemptedMediaUrisOnly
&& requiresNetwork && this.sourcePackageName.equals(jsi.getMediaBackupPackage());
diff --git a/apex/media/framework/Android.bp b/apex/media/framework/Android.bp
index 3dd0da75d1a8..0501a45ef231 100644
--- a/apex/media/framework/Android.bp
+++ b/apex/media/framework/Android.bp
@@ -41,9 +41,7 @@ java_library {
installable: true,
sdk_version: "module_current",
- libs: [
- "framework_media_annotation",
- ],
+ libs: ["framework-annotations-lib"],
static_libs: [
"exoplayer2-extractor"
],
@@ -107,20 +105,9 @@ java_sdk_library {
srcs: [
":updatable-media-srcs",
],
-
- libs: [
- "framework_media_annotation",
- ],
impl_library_visibility: ["//frameworks/av/apex:__subpackages__"],
}
-java_library {
- name: "framework_media_annotation",
- srcs: [":framework-media-annotation-srcs"],
- installable: false,
- sdk_version: "core_current",
-}
-
cc_library_shared {
name: "libmediaparser-jni",
srcs: [
diff --git a/core/api/current.txt b/core/api/current.txt
index 07bebbeb7859..ef067858c530 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -12139,6 +12139,7 @@ package android.content.pm {
field public static final String FEATURE_FINGERPRINT = "android.hardware.fingerprint";
field public static final String FEATURE_FREEFORM_WINDOW_MANAGEMENT = "android.software.freeform_window_management";
field public static final String FEATURE_GAMEPAD = "android.hardware.gamepad";
+ field public static final String FEATURE_HARDWARE_KEYSTORE = "android.hardware.hardware_keystore";
field public static final String FEATURE_HIFI_SENSORS = "android.hardware.sensor.hifi_sensors";
field public static final String FEATURE_HOME_SCREEN = "android.software.home_screen";
field public static final String FEATURE_IDENTITY_CREDENTIAL_HARDWARE = "android.hardware.identity_credential";
@@ -20445,7 +20446,9 @@ package android.media {
method @NonNull public android.media.MediaFormat getOutputFormat(int);
method @NonNull public android.media.MediaCodec.OutputFrame getOutputFrame(int);
method @Nullable public android.media.Image getOutputImage(int);
+ method @Nullable public android.media.MediaCodec.ParameterDescriptor getParameterDescriptor(@NonNull String);
method @NonNull public android.media.MediaCodec.QueueRequest getQueueRequest(int);
+ method @NonNull public java.util.List<java.lang.String> getSupportedVendorParameters();
method @Nullable public static android.media.Image mapHardwareBuffer(@NonNull android.hardware.HardwareBuffer);
method public void queueInputBuffer(int, int, int, long, int) throws android.media.MediaCodec.CryptoException;
method public void queueSecureInputBuffer(int, int, @NonNull android.media.MediaCodec.CryptoInfo, long, int) throws android.media.MediaCodec.CryptoException;
@@ -20464,6 +20467,8 @@ package android.media {
method public void signalEndOfInputStream();
method public void start();
method public void stop();
+ method public void subscribeToVendorParameters(@NonNull java.util.List<java.lang.String>);
+ method public void unsubscribeFromVendorParameters(@NonNull java.util.List<java.lang.String>);
field public static final int BUFFER_FLAG_CODEC_CONFIG = 2; // 0x2
field public static final int BUFFER_FLAG_END_OF_STREAM = 4; // 0x4
field public static final int BUFFER_FLAG_KEY_FRAME = 1; // 0x1
@@ -20585,6 +20590,11 @@ package android.media {
method public long getPresentationTimeUs();
}
+ public static class MediaCodec.ParameterDescriptor {
+ method @NonNull public String getName();
+ method public int getType();
+ }
+
public final class MediaCodec.QueueRequest {
method public void queue();
method @NonNull public android.media.MediaCodec.QueueRequest setByteBufferParameter(@NonNull String, @NonNull java.nio.ByteBuffer);
@@ -25723,7 +25733,7 @@ package android.net.vcn {
public abstract static class VcnManager.VcnStatusCallback {
ctor public VcnManager.VcnStatusCallback();
method public abstract void onGatewayConnectionError(@NonNull int[], int, @Nullable Throwable);
- method public abstract void onVcnStatusChanged(int);
+ method public abstract void onStatusChanged(int);
}
}
@@ -33591,7 +33601,7 @@ package android.provider {
field public static final String ACTION_LOCATION_SOURCE_SETTINGS = "android.settings.LOCATION_SOURCE_SETTINGS";
field public static final String ACTION_MANAGE_ALL_APPLICATIONS_SETTINGS = "android.settings.MANAGE_ALL_APPLICATIONS_SETTINGS";
field public static final String ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION = "android.settings.MANAGE_ALL_FILES_ACCESS_PERMISSION";
- field public static final String ACTION_MANAGE_ALL_SUBSCRIPTIONS_SETTINGS = "android.settings.MANAGE_ALL_SUBSCRIPTIONS_SETTINGS";
+ field public static final String ACTION_MANAGE_ALL_SIM_PROFILES_SETTINGS = "android.settings.MANAGE_ALL_SIM_PROFILES_SETTINGS";
field public static final String ACTION_MANAGE_APPLICATIONS_SETTINGS = "android.settings.MANAGE_APPLICATIONS_SETTINGS";
field public static final String ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION = "android.settings.MANAGE_APP_ALL_FILES_ACCESS_PERMISSION";
field public static final String ACTION_MANAGE_DEFAULT_APPS_SETTINGS = "android.settings.MANAGE_DEFAULT_APPS_SETTINGS";
@@ -34219,6 +34229,9 @@ package android.provider {
method public static android.net.Uri getUriForSubscriptionIdAndField(int, String);
field public static final String AUTHORITY = "service-state";
field public static final android.net.Uri CONTENT_URI;
+ field public static final String DATA_NETWORK_TYPE = "data_network_type";
+ field public static final String DATA_REG_STATE = "data_reg_state";
+ field public static final String DUPLEX_MODE = "duplex_mode";
field public static final String IS_MANUAL_NETWORK_SELECTION = "is_manual_network_selection";
field public static final String VOICE_OPERATOR_NUMERIC = "voice_operator_numeric";
field public static final String VOICE_REG_STATE = "voice_reg_state";
@@ -39391,6 +39404,7 @@ package android.telephony {
field public static final String KEY_NON_RCS_CAPABILITIES_CACHE_EXPIRATION_SEC_INT = "ims.non_rcs_capabilities_cache_expiration_sec_int";
field public static final String KEY_PREFIX = "ims.";
field public static final String KEY_RCS_BULK_CAPABILITY_EXCHANGE_BOOL = "ims.rcs_bulk_capability_exchange_bool";
+ field public static final String KEY_RCS_FEATURE_TAG_ALLOWED_STRING_ARRAY = "ims.rcs_feature_tag_allowed_string_array";
field public static final String KEY_WIFI_OFF_DEFERRING_TIME_MILLIS_INT = "ims.wifi_off_deferring_time_millis_int";
}
@@ -40662,7 +40676,6 @@ package android.telephony {
method public static int[] calculateLength(String, boolean);
method @Deprecated public static android.telephony.SmsMessage createFromPdu(byte[]);
method public static android.telephony.SmsMessage createFromPdu(byte[], String);
- method @Nullable public static android.telephony.SmsMessage createSmsSubmitPdu(@NonNull byte[], boolean);
method public String getDisplayMessageBody();
method public String getDisplayOriginatingAddress();
method public String getEmailBody();
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index f155a5f07fd7..3b7a617f2e16 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -50,19 +50,10 @@ package android.net {
method @NonNull public static String blockedReasonsToString(int);
method @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public int getMultipathPreference(@NonNull android.net.Network);
method @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public int getRestrictBackgroundStatus(int);
- method public static boolean isUidBlocked(int, boolean);
method @RequiresPermission(android.Manifest.permission.OBSERVE_NETWORK_POLICY) public boolean isUidNetworkingBlocked(int, boolean);
method @RequiresPermission(android.Manifest.permission.OBSERVE_NETWORK_POLICY) public boolean isUidRestrictedOnMeteredNetworks(int);
method @RequiresPermission(android.Manifest.permission.OBSERVE_NETWORK_POLICY) public void registerNetworkPolicyCallback(@Nullable java.util.concurrent.Executor, @NonNull android.net.NetworkPolicyManager.NetworkPolicyCallback);
method @RequiresPermission(android.Manifest.permission.OBSERVE_NETWORK_POLICY) public void unregisterNetworkPolicyCallback(@NonNull android.net.NetworkPolicyManager.NetworkPolicyCallback);
- field public static final int BLOCKED_METERED_REASON_ADMIN_DISABLED = 262144; // 0x40000
- field public static final int BLOCKED_METERED_REASON_DATA_SAVER = 65536; // 0x10000
- field public static final int BLOCKED_METERED_REASON_USER_RESTRICTED = 131072; // 0x20000
- field public static final int BLOCKED_REASON_APP_STANDBY = 4; // 0x4
- field public static final int BLOCKED_REASON_BATTERY_SAVER = 1; // 0x1
- field public static final int BLOCKED_REASON_DOZE = 2; // 0x2
- field public static final int BLOCKED_REASON_NONE = 0; // 0x0
- field public static final int BLOCKED_REASON_RESTRICTED_MODE = 8; // 0x8
}
public static interface NetworkPolicyManager.NetworkPolicyCallback {
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 92c18c68c4ff..e0de9780a7a1 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -155,12 +155,14 @@ package android {
field public static final String NETWORK_SIGNAL_STRENGTH_WAKEUP = "android.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP";
field public static final String NETWORK_STACK = "android.permission.NETWORK_STACK";
field public static final String NETWORK_STATS_PROVIDER = "android.permission.NETWORK_STATS_PROVIDER";
+ field public static final String NFC_SET_CONTROLLER_ALWAYS_ON = "android.permission.NFC_SET_CONTROLLER_ALWAYS_ON";
field public static final String NOTIFICATION_DURING_SETUP = "android.permission.NOTIFICATION_DURING_SETUP";
field public static final String NOTIFY_TV_INPUTS = "android.permission.NOTIFY_TV_INPUTS";
field public static final String OBSERVE_APP_USAGE = "android.permission.OBSERVE_APP_USAGE";
field public static final String OBSERVE_NETWORK_POLICY = "android.permission.OBSERVE_NETWORK_POLICY";
field public static final String OBSERVE_ROLE_HOLDERS = "android.permission.OBSERVE_ROLE_HOLDERS";
field public static final String OPEN_ACCESSIBILITY_DETAILS_SETTINGS = "android.permission.OPEN_ACCESSIBILITY_DETAILS_SETTINGS";
+ field public static final String OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD = "android.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD";
field public static final String OVERRIDE_WIFI_CONFIG = "android.permission.OVERRIDE_WIFI_CONFIG";
field public static final String PACKAGE_VERIFICATION_AGENT = "android.permission.PACKAGE_VERIFICATION_AGENT";
field public static final String PACKET_KEEPALIVE_OFFLOAD = "android.permission.PACKET_KEEPALIVE_OFFLOAD";
@@ -1125,6 +1127,21 @@ package android.app.compat {
method public static boolean isChangeEnabled(long);
method @RequiresPermission(allOf={"android.permission.READ_COMPAT_CHANGE_CONFIG", "android.permission.LOG_COMPAT_CHANGE"}) public static boolean isChangeEnabled(long, @NonNull String, @NonNull android.os.UserHandle);
method @RequiresPermission(allOf={"android.permission.READ_COMPAT_CHANGE_CONFIG", "android.permission.LOG_COMPAT_CHANGE"}) public static boolean isChangeEnabled(long, int);
+ method @RequiresPermission(android.Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD) public static void setPackageOverride(@NonNull String, @NonNull java.util.Map<java.lang.Long,android.app.compat.PackageOverride>);
+ }
+
+ public final class PackageOverride {
+ method public long getMaxVersionCode();
+ method public long getMinVersionCode();
+ method public boolean isEnabled();
+ }
+
+ public static final class PackageOverride.Builder {
+ ctor public PackageOverride.Builder();
+ method @NonNull public android.app.compat.PackageOverride build();
+ method @NonNull public android.app.compat.PackageOverride.Builder setEnabled(boolean);
+ method @NonNull public android.app.compat.PackageOverride.Builder setMaxVersionCode(long);
+ method @NonNull public android.app.compat.PackageOverride.Builder setMinVersionCode(long);
}
}
@@ -1533,7 +1550,6 @@ package android.bluetooth {
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean disconnect(android.bluetooth.BluetoothDevice);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public int getConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
- method @Deprecated @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean setPriority(android.bluetooth.BluetoothDevice, int);
}
public final class BluetoothHearingAid implements android.bluetooth.BluetoothProfile {
@@ -6427,9 +6443,11 @@ package android.net.netstats.provider {
method public void notifyAlertReached();
method public void notifyLimitReached();
method public void notifyStatsUpdated(int, @NonNull android.net.NetworkStats, @NonNull android.net.NetworkStats);
+ method public void notifyWarningReached();
method public abstract void onRequestStatsUpdate(int);
method public abstract void onSetAlert(long);
method public abstract void onSetLimit(@NonNull String, long);
+ method public void onSetWarningAndLimit(@NonNull String, long, long);
field public static final int QUOTA_UNLIMITED = -1; // 0xffffffff
}
@@ -6708,10 +6726,10 @@ package android.nfc {
method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enable();
method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enableNdefPush();
method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enableSecureNfc(boolean);
- method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean isAlwaysOnEnabled();
- method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean isAlwaysOnSupported();
+ method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public boolean isControllerAlwaysOn();
+ method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public boolean isControllerAlwaysOnSupported();
method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean removeNfcUnlockHandler(android.nfc.NfcAdapter.NfcUnlockHandler);
- method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean setAlwaysOn(boolean);
+ method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public boolean setControllerAlwaysOn(boolean);
method public void setNdefPushMessage(android.nfc.NdefMessage, android.app.Activity, int);
field public static final int FLAG_NDEF_PUSH_NO_CONFIRM = 1; // 0x1
}
@@ -9416,7 +9434,14 @@ package android.telephony {
method @NonNull public static android.os.PersistableBundle getDefaultConfig();
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void overrideConfig(int, @Nullable android.os.PersistableBundle);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void updateConfigForPhoneId(int, String);
+ field public static final int GBA_DIGEST = 3; // 0x3
+ field public static final int GBA_ME = 1; // 0x1
+ field public static final int GBA_U = 2; // 0x2
field public static final String KEY_CARRIER_SETUP_APP_STRING = "carrier_setup_app_string";
+ field public static final String KEY_GBA_MODE_INT = "gba_mode_int";
+ field public static final String KEY_GBA_UA_SECURITY_ORGANIZATION_INT = "gba_ua_security_organization_int";
+ field public static final String KEY_GBA_UA_SECURITY_PROTOCOL_INT = "gba_ua_security_protocol_int";
+ field public static final String KEY_GBA_UA_TLS_CIPHER_SUITE_INT = "gba_ua_tls_cipher_suite_int";
field public static final String KEY_SUPPORT_CDMA_1X_VOICE_CALLS_BOOL = "support_cdma_1x_voice_calls_bool";
}
@@ -10687,16 +10712,30 @@ package android.telephony.data {
public final class EpsBearerQosSessionAttributes implements android.os.Parcelable android.net.QosSessionAttributes {
method public int describeContents();
- method public long getGuaranteedDownlinkBitRate();
- method public long getGuaranteedUplinkBitRate();
- method public long getMaxDownlinkBitRate();
- method public long getMaxUplinkBitRate();
- method public int getQci();
+ method public long getGuaranteedDownlinkBitRateKbps();
+ method public long getGuaranteedUplinkBitRateKbps();
+ method public long getMaxDownlinkBitRateKbps();
+ method public long getMaxUplinkBitRateKbps();
+ method public int getQosIdentifier();
method @NonNull public java.util.List<java.net.InetSocketAddress> getRemoteAddresses();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.telephony.data.EpsBearerQosSessionAttributes> CREATOR;
}
+ public final class NrQosSessionAttributes implements android.os.Parcelable android.net.QosSessionAttributes {
+ method public int describeContents();
+ method @NonNull public java.time.Duration getBitRateWindowDuration();
+ method public long getGuaranteedDownlinkBitRateKbps();
+ method public long getGuaranteedUplinkBitRateKbps();
+ method public long getMaxDownlinkBitRateKbps();
+ method public long getMaxUplinkBitRateKbps();
+ method @IntRange(from=1, to=63) public int getQosFlowIdentifier();
+ method public int getQosIdentifier();
+ method @NonNull public java.util.List<java.net.InetSocketAddress> getRemoteAddresses();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.telephony.data.NrQosSessionAttributes> CREATOR;
+ }
+
public abstract class QualifiedNetworksService extends android.app.Service {
ctor public QualifiedNetworksService();
method @NonNull public abstract android.telephony.data.QualifiedNetworksService.NetworkAvailabilityProvider onCreateNetworkAvailabilityProvider(int);
@@ -11745,6 +11784,7 @@ package android.telephony.ims {
method @Nullable public android.telephony.ims.RcsContactPresenceTuple getCapabilityTuple(@NonNull String);
method @NonNull public java.util.List<android.telephony.ims.RcsContactPresenceTuple> getCapabilityTuples();
method @NonNull public android.net.Uri getContactUri();
+ method @NonNull public java.util.Set<java.lang.String> getFeatureTags();
method public int getRequestResult();
method public int getSourceType();
method public void writeToParcel(@NonNull android.os.Parcel, int);
@@ -11759,6 +11799,14 @@ package android.telephony.ims {
field public static final int SOURCE_TYPE_NETWORK = 0; // 0x0
}
+ public static final class RcsContactUceCapability.OptionsBuilder {
+ ctor public RcsContactUceCapability.OptionsBuilder(@NonNull android.net.Uri);
+ method @NonNull public android.telephony.ims.RcsContactUceCapability.OptionsBuilder addFeatureTag(@NonNull String);
+ method @NonNull public android.telephony.ims.RcsContactUceCapability.OptionsBuilder addFeatureTags(@NonNull java.util.Set<java.lang.String>);
+ method @NonNull public android.telephony.ims.RcsContactUceCapability build();
+ method @NonNull public android.telephony.ims.RcsContactUceCapability.OptionsBuilder setRequestResult(int);
+ }
+
public static final class RcsContactUceCapability.PresenceBuilder {
ctor public RcsContactUceCapability.PresenceBuilder(@NonNull android.net.Uri, int, int);
method @NonNull public android.telephony.ims.RcsContactUceCapability.PresenceBuilder addCapabilityTuple(@NonNull android.telephony.ims.RcsContactPresenceTuple);
@@ -12028,13 +12076,13 @@ package android.telephony.ims.feature {
ctor @Deprecated public RcsFeature();
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 @NonNull public android.telephony.ims.stub.RcsCapabilityExchangeImplBase createCapabilityExchangeImpl(@NonNull android.telephony.ims.stub.CapabilityExchangeEventListener);
+ method public void destroyCapabilityExchangeImpl(@NonNull android.telephony.ims.stub.RcsCapabilityExchangeImplBase);
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 {
@@ -12052,7 +12100,7 @@ package android.telephony.ims.feature {
package android.telephony.ims.stub {
public interface CapabilityExchangeEventListener {
- method public void onRemoteCapabilityRequest(@NonNull android.net.Uri, @NonNull java.util.List<java.lang.String>, @NonNull android.telephony.ims.stub.CapabilityExchangeEventListener.OptionsRequestCallback) throws android.telephony.ims.ImsException;
+ method public void onRemoteCapabilityRequest(@NonNull android.net.Uri, @NonNull java.util.Set<java.lang.String>, @NonNull android.telephony.ims.stub.CapabilityExchangeEventListener.OptionsRequestCallback) throws android.telephony.ims.ImsException;
method public void onRequestPublishCapabilities(int) throws android.telephony.ims.ImsException;
method public void onUnpublish() throws android.telephony.ims.ImsException;
}
@@ -12246,9 +12294,9 @@ package android.telephony.ims.stub {
}
public class RcsCapabilityExchangeImplBase {
- ctor public RcsCapabilityExchangeImplBase(@NonNull java.util.concurrent.Executor);
+ ctor public RcsCapabilityExchangeImplBase();
method public void publishCapabilities(@NonNull String, @NonNull android.telephony.ims.stub.RcsCapabilityExchangeImplBase.PublishResponseCallback);
- method public void sendOptionsCapabilityRequest(@NonNull android.net.Uri, @NonNull java.util.List<java.lang.String>, @NonNull android.telephony.ims.stub.RcsCapabilityExchangeImplBase.OptionsResponseCallback);
+ method public void sendOptionsCapabilityRequest(@NonNull android.net.Uri, @NonNull java.util.Set<java.lang.String>, @NonNull android.telephony.ims.stub.RcsCapabilityExchangeImplBase.OptionsResponseCallback);
method public void subscribeForCapabilities(@NonNull java.util.Collection<android.net.Uri>, @NonNull android.telephony.ims.stub.RcsCapabilityExchangeImplBase.SubscribeResponseCallback);
field public static final int COMMAND_CODE_FETCH_ERROR = 3; // 0x3
field public static final int COMMAND_CODE_GENERIC_FAILURE = 1; // 0x1
@@ -12417,7 +12465,7 @@ package android.util {
package android.uwb {
public final class AngleMeasurement implements android.os.Parcelable {
- ctor public AngleMeasurement(double, double, double);
+ ctor public AngleMeasurement(@FloatRange(from=-3.141592653589793, to=3.141592653589793) double, @FloatRange(from=0.0, to=3.141592653589793) double, @FloatRange(from=0.0, to=1.0) double);
method public int describeContents();
method @FloatRange(from=0.0, to=1.0) public double getConfidenceLevel();
method @FloatRange(from=0.0, to=3.141592653589793) public double getErrorRadians();
diff --git a/core/api/system-removed.txt b/core/api/system-removed.txt
index 0c02c43b1084..8895494e01d3 100644
--- a/core/api/system-removed.txt
+++ b/core/api/system-removed.txt
@@ -48,6 +48,14 @@ package android.app.prediction {
}
+package android.bluetooth {
+
+ public final class BluetoothHeadset implements android.bluetooth.BluetoothProfile {
+ method @Deprecated @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean setPriority(android.bluetooth.BluetoothDevice, int);
+ }
+
+}
+
package android.content {
public class Intent implements java.lang.Cloneable android.os.Parcelable {
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 11df05812e21..0c57f4e3b557 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -9,8 +9,10 @@ package android {
field public static final String BRIGHTNESS_SLIDER_USAGE = "android.permission.BRIGHTNESS_SLIDER_USAGE";
field public static final String CHANGE_APP_IDLE_STATE = "android.permission.CHANGE_APP_IDLE_STATE";
field public static final String CLEAR_APP_USER_DATA = "android.permission.CLEAR_APP_USER_DATA";
+ field public static final String CLEAR_FREEZE_PERIOD = "android.permission.CLEAR_FREEZE_PERIOD";
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_DEVICE_POLICY_MANAGER_LOGS = "android.permission.FORCE_DEVICE_POLICY_MANAGER_LOGS";
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";
@@ -19,10 +21,11 @@ package android {
field public static final String NETWORK_SETTINGS = "android.permission.NETWORK_SETTINGS";
field public static final String NETWORK_STACK = "android.permission.NETWORK_STACK";
field public static final String OVERRIDE_DISPLAY_MODE_REQUESTS = "android.permission.OVERRIDE_DISPLAY_MODE_REQUESTS";
- field public static final String QUERY_USERS = "android.permission.QUERY_USERS";
+ field public static final String QUERY_AUDIO_STATE = "android.permission.QUERY_AUDIO_STATE";
field public static final String READ_CELL_BROADCASTS = "android.permission.READ_CELL_BROADCASTS";
field public static final String READ_PRIVILEGED_PHONE_STATE = "android.permission.READ_PRIVILEGED_PHONE_STATE";
field public static final String REMOVE_TASKS = "android.permission.REMOVE_TASKS";
+ field public static final String SET_AND_VERIFY_LOCKSCREEN_CREDENTIALS = "android.permission.SET_AND_VERIFY_LOCKSCREEN_CREDENTIALS";
field public static final String SUSPEND_APPS = "android.permission.SUSPEND_APPS";
field public static final String TEST_MANAGE_ROLLBACKS = "android.permission.TEST_MANAGE_ROLLBACKS";
field public static final String UPGRADE_RUNTIME_PERMISSIONS = "android.permission.UPGRADE_RUNTIME_PERMISSIONS";
@@ -1064,6 +1067,7 @@ package android.os {
field public static final int FIRST_ISOLATED_UID = 99000; // 0x182b8
field public static final int LAST_APP_ZYGOTE_ISOLATED_UID = 98999; // 0x182b7
field public static final int LAST_ISOLATED_UID = 99999; // 0x1869f
+ field public static final int NFC_UID = 1027; // 0x403
field public static final int NUM_UIDS_PER_APP_ZYGOTE = 100; // 0x64
}
@@ -1652,6 +1656,7 @@ package android.telephony {
public class ServiceState implements android.os.Parcelable {
method public void addNetworkRegistrationInfo(android.telephony.NetworkRegistrationInfo);
method public int getDataNetworkType();
+ method public int getDataRegState();
method public void setCdmaSystemAndNetworkId(int, int);
method public void setCellBandwidths(int[]);
method public void setChannelNumber(int);
diff --git a/core/java/android/annotation/MainThread.java b/core/java/android/annotation/MainThread.java
index 556fdb4e7742..a070246e5ef3 100644
--- a/core/java/android/annotation/MainThread.java
+++ b/core/java/android/annotation/MainThread.java
@@ -21,8 +21,6 @@ import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.SOURCE;
-import android.os.Looper;
-
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
@@ -40,8 +38,7 @@ import java.lang.annotation.Target;
* </code>
* </pre>
*
- * @memberDoc This method must be called from the
- * {@linkplain Looper#getMainLooper() main thread} of your app.
+ * @memberDoc This method must be called from the main thread of your app.
* @hide
*/
@Retention(SOURCE)
diff --git a/core/java/android/app/compat/CompatChanges.java b/core/java/android/app/compat/CompatChanges.java
index ab38832458d6..74e1ece3fa89 100644
--- a/core/java/android/app/compat/CompatChanges.java
+++ b/core/java/android/app/compat/CompatChanges.java
@@ -104,16 +104,15 @@ public final class CompatChanges {
*
* @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) {
+ @RequiresPermission(android.Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD)
+ public static void setPackageOverride(@NonNull String packageName,
+ @NonNull 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);
+ platformCompat.setOverridesOnReleaseBuilds(config, packageName);
} catch (RemoteException e) {
e.rethrowFromSystemServer();
}
diff --git a/core/java/android/app/compat/PackageOverride.java b/core/java/android/app/compat/PackageOverride.java
index 9f97cd41128a..59b355523a30 100644
--- a/core/java/android/app/compat/PackageOverride.java
+++ b/core/java/android/app/compat/PackageOverride.java
@@ -17,8 +17,9 @@
package android.app.compat;
import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
import android.os.Parcel;
-import android.os.Parcelable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -32,15 +33,16 @@ import java.lang.annotation.RetentionPolicy;
*
* @hide
*/
-public class PackageOverride implements Parcelable {
+@SystemApi
+public final class PackageOverride {
+ /** @hide */
@IntDef({
VALUE_UNDEFINED,
VALUE_ENABLED,
VALUE_DISABLED
})
@Retention(RetentionPolicy.SOURCE)
- /** @hide */
public @interface EvaluatedOverride {
}
@@ -75,10 +77,6 @@ public class PackageOverride implements Parcelable {
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.
@@ -114,25 +112,23 @@ public class PackageOverride implements Parcelable {
}
/** Returns the enabled value for the override. */
- public boolean getEnabled() {
+ public boolean isEnabled() {
return mEnabled;
}
/** @hide */
- @Override
- public int describeContents() {
- return 0;
- }
-
- /** @hide */
- @Override
- public void writeToParcel(Parcel dest, int flags) {
+ public void writeToParcel(Parcel dest) {
dest.writeLong(mMinVersionCode);
dest.writeLong(mMaxVersionCode);
dest.writeBoolean(mEnabled);
}
/** @hide */
+ public static PackageOverride createFromParcel(Parcel in) {
+ return new PackageOverride(in.readLong(), in.readLong(), in.readBoolean());
+ }
+
+ /** @hide */
@Override
public String toString() {
if (mMinVersionCode == Long.MIN_VALUE && mMaxVersionCode == Long.MAX_VALUE) {
@@ -141,25 +137,10 @@ public class PackageOverride implements Parcelable {
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 {
+ public static final class Builder {
private long mMinVersionCode = Long.MIN_VALUE;
private long mMaxVersionCode = Long.MAX_VALUE;
private boolean mEnabled;
@@ -169,6 +150,7 @@ public class PackageOverride implements Parcelable {
*
* default value: {@code Long.MIN_VALUE}.
*/
+ @NonNull
public Builder setMinVersionCode(long minVersionCode) {
mMinVersionCode = minVersionCode;
return this;
@@ -179,6 +161,7 @@ public class PackageOverride implements Parcelable {
*
* default value: {@code Long.MAX_VALUE}.
*/
+ @NonNull
public Builder setMaxVersionCode(long maxVersionCode) {
mMaxVersionCode = maxVersionCode;
return this;
@@ -189,6 +172,7 @@ public class PackageOverride implements Parcelable {
*
* default value: {@code false}.
*/
+ @NonNull
public Builder setEnabled(boolean enabled) {
mEnabled = enabled;
return this;
@@ -200,6 +184,7 @@ public class PackageOverride implements Parcelable {
* @throws IllegalArgumentException if {@code minVersionCode} is larger than
* {@code maxVersionCode}.
*/
+ @NonNull
public PackageOverride build() {
if (mMinVersionCode > mMaxVersionCode) {
throw new IllegalArgumentException("minVersionCode must not be larger than "
diff --git a/core/java/android/bluetooth/BluetoothHeadset.java b/core/java/android/bluetooth/BluetoothHeadset.java
index 4fb557780d04..632572dea3c6 100644
--- a/core/java/android/bluetooth/BluetoothHeadset.java
+++ b/core/java/android/bluetooth/BluetoothHeadset.java
@@ -567,6 +567,7 @@ public final class BluetoothHeadset implements BluetoothProfile {
* @return true if priority is set, false on error
* @hide
* @deprecated Replaced with {@link #setConnectionPolicy(BluetoothDevice, int)}
+ * @removed
*/
@Deprecated
@SystemApi
diff --git a/core/java/android/bluetooth/le/ScanFilter.java b/core/java/android/bluetooth/le/ScanFilter.java
index 86721502d409..3c20dcac8ca3 100644
--- a/core/java/android/bluetooth/le/ScanFilter.java
+++ b/core/java/android/bluetooth/le/ScanFilter.java
@@ -587,7 +587,7 @@ public final class ScanFilter implements Parcelable {
* @throws IllegalArgumentException If the {@code deviceAddress} is invalid.
*/
public Builder setDeviceAddress(String deviceAddress) {
- return setDeviceAddress(mDeviceAddress, BluetoothDevice.ADDRESS_TYPE_PUBLIC);
+ return setDeviceAddress(deviceAddress, BluetoothDevice.ADDRESS_TYPE_PUBLIC);
}
/**
diff --git a/core/java/android/content/OWNERS b/core/java/android/content/OWNERS
index d0d406a0c9e6..01b554a56720 100644
--- a/core/java/android/content/OWNERS
+++ b/core/java/android/content/OWNERS
@@ -8,3 +8,5 @@ per-file Intent.java = patb@google.com
per-file AutofillOptions* = file:/core/java/android/service/autofill/OWNERS
per-file ContentCaptureOptions* = file:/core/java/android/service/contentcapture/OWNERS
per-file LocusId* = file:/core/java/android/service/contentcapture/OWNERS
+per-file ComponentCallbacksController = file:/services/core/java/com/android/server/wm/OWNERS
+per-file ComponentCallbacksController = charlesccchen@google.com
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 6ec11693d69b..ad9e31b6cbf4 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -2167,7 +2167,10 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
return (flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) == 0;
}
- /** @hide */
+ /**
+ * True if the application is pre-installed on the OEM partition of the system image.
+ * @hide
+ */
@SystemApi
public boolean isOem() {
return (privateFlags & ApplicationInfo.PRIVATE_FLAG_OEM) != 0;
@@ -2215,13 +2218,19 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
return (flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0;
}
- /** @hide */
+ /**
+ * True if the application is pre-installed on the vendor partition of the system image.
+ * @hide
+ */
@SystemApi
public boolean isVendor() {
return (privateFlags & ApplicationInfo.PRIVATE_FLAG_VENDOR) != 0;
}
- /** @hide */
+ /**
+ * True if the application is pre-installed on the product partition of the system image.
+ * @hide
+ */
@SystemApi
public boolean isProduct() {
return (privateFlags & ApplicationInfo.PRIVATE_FLAG_PRODUCT) != 0;
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 7e17256f0229..23f5e3ab6c1f 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -3167,8 +3167,57 @@ public abstract class PackageManager {
public static final String FEATURE_VR_HEADTRACKING = "android.hardware.vr.headtracking";
/**
- * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}:
- * The device has a StrongBox hardware-backed Keystore.
+ * Feature for {@link #getSystemAvailableFeatures} and
+ * {@link #hasSystemFeature(String, int)}: If this feature is supported, the device implements
+ * the Android Keystore backed by an isolated execution environment. The version indicates
+ * which features are implemented in the isolated execution environment:
+ * <ul>
+ * <li>100: Hardware support for ECDH (see {@link javax.crypto.KeyAgreement}) and support
+ * for app-generated attestation keys (see {@link
+ * android.security.keystore.KeyGenParameterSpec.Builder#setAttestKeyAlias(String)}).
+ * <li>41: Hardware enforcement of device-unlocked keys (see {@link
+ * android.security.keystore.KeyGenParameterSpec.Builder#setUnlockedDeviceRequired(boolean)}).
+ * <li>40: Support for wrapped key import (see {@link
+ * android.security.keystore.WrappedKeyEntry}), optional support for ID attestation (see {@link
+ * android.security.keystore.KeyGenParameterSpec.Builder#setDevicePropertiesAttestationIncluded(boolean)}),
+ * attestation (see {@link
+ * android.security.keystore.KeyGenParameterSpec.Builder#setAttestationChallenge(byte[])}),
+ * AES, HMAC, ECDSA and RSA support where the secret or private key never leaves secure
+ * hardware, and support for requiring user authentication before a key can be used.
+ * </ul>
+ * This feature version is guaranteed to be set for all devices launching with Android 12 and
+ * may be set on devices launching with an earlier version. If the feature version is set, it
+ * will at least have the value 40. If it's not set the device may have a version of
+ * hardware-backed keystore but it may not support all features listed above.
+ */
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_HARDWARE_KEYSTORE = "android.hardware.hardware_keystore";
+
+ /**
+ * Feature for {@link #getSystemAvailableFeatures}, {@link #hasSystemFeature(String)}, and
+ * {@link #hasSystemFeature(String, int)}: If this feature is supported, the device implements
+ * the Android Keystore backed by a dedicated secure processor referred to as
+ * <a href="https://source.android.com/security/best-practices/hardware#strongbox-keymaster">
+ * StrongBox</a>. If this feature has a version, the version number indicates which features are
+ * implemented in StrongBox:
+ * <ul>
+ * <li>100: Hardware support for ECDH (see {@link javax.crypto.KeyAgreement}) and support
+ * for app-generated attestation keys (see {@link
+ * android.security.keystore.KeyGenParameterSpec.Builder#setAttestKeyAlias(String)}).
+ * <li>41: Hardware enforcement of device-unlocked keys (see {@link
+ * android.security.keystore.KeyGenParameterSpec.Builder#setUnlockedDeviceRequired(boolean)}).
+ * <li>40: Support for wrapped key import (see {@link
+ * android.security.keystore.WrappedKeyEntry}), optional support for ID attestation (see {@link
+ * android.security.keystore.KeyGenParameterSpec.Builder#setDevicePropertiesAttestationIncluded(boolean)}),
+ * attestation (see {@link
+ * android.security.keystore.KeyGenParameterSpec.Builder#setAttestationChallenge(byte[])}),
+ * AES, HMAC, ECDSA and RSA support where the secret or private key never leaves secure
+ * hardware, and support for requiring user authentication before a key can be used.
+ * </ul>
+ * If a device has StrongBox, this feature version number is guaranteed to be set for all
+ * devices launching with Android 12 and may be set on devices launching with an earlier
+ * version. If the feature version is set, it will at least have the value 40. If it's not
+ * set the device may have StrongBox but it may not support all features listed above.
*/
@SdkConstant(SdkConstantType.FEATURE)
public static final String FEATURE_STRONGBOX_KEYSTORE =
diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java
index 10be02c414cd..68606ec90dc9 100644
--- a/core/java/android/net/NetworkPolicyManager.java
+++ b/core/java/android/net/NetworkPolicyManager.java
@@ -204,81 +204,6 @@ public class NetworkPolicyManager {
public @interface SubscriptionOverrideMask {}
/**
- * Flag to indicate that an app is not subject to any restrictions that could result in its
- * network access blocked.
- *
- * @hide
- */
- @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
- public static final int BLOCKED_REASON_NONE = 0;
-
- /**
- * Flag to indicate that an app is subject to Battery saver restrictions that would
- * result in its network access being blocked.
- *
- * @hide
- */
- @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
- public static final int BLOCKED_REASON_BATTERY_SAVER = 1 << 0;
-
- /**
- * Flag to indicate that an app is subject to Doze restrictions that would
- * result in its network access being blocked.
- *
- * @hide
- */
- @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
- public static final int BLOCKED_REASON_DOZE = 1 << 1;
-
- /**
- * Flag to indicate that an app is subject to App Standby restrictions that would
- * result in its network access being blocked.
- *
- * @hide
- */
- @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
- public static final int BLOCKED_REASON_APP_STANDBY = 1 << 2;
-
- /**
- * Flag to indicate that an app is subject to Restricted mode restrictions that would
- * result in its network access being blocked.
- *
- * @hide
- */
- @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
- public static final int BLOCKED_REASON_RESTRICTED_MODE = 1 << 3;
-
- /**
- * Flag to indicate that an app is subject to Data saver restrictions that would
- * result in its metered network access being blocked.
- *
- * @hide
- */
- @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
- public static final int BLOCKED_METERED_REASON_DATA_SAVER = 1 << 16;
-
- /**
- * Flag to indicate that an app is subject to user restrictions that would
- * result in its metered network access being blocked.
- *
- * @hide
- */
- @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
- public static final int BLOCKED_METERED_REASON_USER_RESTRICTED = 1 << 17;
-
- /**
- * Flag to indicate that an app is subject to Device admin restrictions that would
- * result in its metered network access being blocked.
- *
- * @hide
- */
- @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
- public static final int BLOCKED_METERED_REASON_ADMIN_DISABLED = 1 << 18;
-
- /** @hide */
- public static final int BLOCKED_METERED_REASON_MASK = 0xffff0000;
-
- /**
* Flag to indicate that app is not exempt from any network restrictions.
*
* @hide
@@ -344,22 +269,6 @@ public class NetworkPolicyManager {
/** @hide */
public static final int ALLOWED_METERED_REASON_MASK = 0xffff0000;
- /**
- * @hide
- */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(flag = true, prefix = {"BLOCKED_"}, value = {
- BLOCKED_REASON_NONE,
- BLOCKED_REASON_BATTERY_SAVER,
- BLOCKED_REASON_DOZE,
- BLOCKED_REASON_APP_STANDBY,
- BLOCKED_REASON_RESTRICTED_MODE,
- BLOCKED_METERED_REASON_DATA_SAVER,
- BLOCKED_METERED_REASON_USER_RESTRICTED,
- BLOCKED_METERED_REASON_ADMIN_DISABLED,
- })
- public @interface BlockedReason {}
-
private final Context mContext;
@UnsupportedAppUsage
private INetworkPolicyManager mService;
@@ -876,35 +785,6 @@ public class NetworkPolicyManager {
}
/**
- * Returns whether network access of an UID is blocked or not based on {@code blockedReasons}
- * corresponding to it.
- *
- * {@code blockedReasons} would be a bitwise {@code OR} combination of the
- * {@code BLOCKED_REASON_*} and/or {@code BLOCKED_METERED_REASON_*} constants.
- *
- * @param blockedReasons Value indicating the reasons for why the network access of an UID is
- * blocked. If the value is equal to {@link #BLOCKED_REASON_NONE}, then
- * it indicates that an app's network access is not blocked.
- * @param meteredNetwork Value indicating whether the network is metered or not.
- * @return Whether network access is blocked or not.
- * @hide
- */
- @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
- public static boolean isUidBlocked(@BlockedReason int blockedReasons, boolean meteredNetwork) {
- if (blockedReasons == BLOCKED_REASON_NONE) {
- return false;
- }
- final int blockedOnAllNetworksReason = (blockedReasons & ~BLOCKED_METERED_REASON_MASK);
- if (blockedOnAllNetworksReason != BLOCKED_REASON_NONE) {
- return true;
- }
- if (meteredNetwork) {
- return blockedReasons != BLOCKED_REASON_NONE;
- }
- return false;
- }
-
- /**
* Returns the {@code string} representation of {@code blockedReasons} argument.
*
* @param blockedReasons Value indicating the reasons for why the network access of an UID is
@@ -913,7 +793,7 @@ public class NetworkPolicyManager {
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
@NonNull
- public static String blockedReasonsToString(@BlockedReason int blockedReasons) {
+ public static String blockedReasonsToString(int blockedReasons) {
return DebugUtils.flagsToString(NetworkPolicyManager.class, "BLOCKED_", blockedReasons);
}
@@ -977,7 +857,7 @@ public class NetworkPolicyManager {
* @hide
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
- default void onUidBlockedReasonChanged(int uid, @BlockedReason int blockedReasons) {}
+ default void onUidBlockedReasonChanged(int uid, int blockedReasons) {}
}
/** @hide */
@@ -992,8 +872,7 @@ public class NetworkPolicyManager {
}
@Override
- public void onBlockedReasonChanged(int uid, @BlockedReason int oldBlockedReasons,
- @BlockedReason int newBlockedReasons) {
+ public void onBlockedReasonChanged(int uid, int oldBlockedReasons, int newBlockedReasons) {
if (oldBlockedReasons != newBlockedReasons) {
dispatchOnUidBlockedReasonChanged(mExecutor, mCallback, uid, newBlockedReasons);
}
@@ -1001,7 +880,7 @@ public class NetworkPolicyManager {
}
private static void dispatchOnUidBlockedReasonChanged(@Nullable Executor executor,
- @NonNull NetworkPolicyCallback callback, int uid, @BlockedReason int blockedReasons) {
+ @NonNull NetworkPolicyCallback callback, int uid, int blockedReasons) {
if (executor == null) {
callback.onUidBlockedReasonChanged(uid, blockedReasons);
} else {
diff --git a/core/java/android/net/netstats/provider/INetworkStatsProvider.aidl b/core/java/android/net/netstats/provider/INetworkStatsProvider.aidl
index 4078b249218c..74c3ba44b69e 100644
--- a/core/java/android/net/netstats/provider/INetworkStatsProvider.aidl
+++ b/core/java/android/net/netstats/provider/INetworkStatsProvider.aidl
@@ -23,6 +23,6 @@ package android.net.netstats.provider;
*/
oneway interface INetworkStatsProvider {
void onRequestStatsUpdate(int token);
- void onSetLimit(String iface, long quotaBytes);
void onSetAlert(long quotaBytes);
+ void onSetWarningAndLimit(String iface, long warningBytes, long limitBytes);
}
diff --git a/core/java/android/net/netstats/provider/INetworkStatsProviderCallback.aidl b/core/java/android/net/netstats/provider/INetworkStatsProviderCallback.aidl
index bd336dd348fe..7eaa01e262fe 100644
--- a/core/java/android/net/netstats/provider/INetworkStatsProviderCallback.aidl
+++ b/core/java/android/net/netstats/provider/INetworkStatsProviderCallback.aidl
@@ -26,6 +26,6 @@ import android.net.NetworkStats;
oneway interface INetworkStatsProviderCallback {
void notifyStatsUpdated(int token, in NetworkStats ifaceStats, in NetworkStats uidStats);
void notifyAlertReached();
- void notifyLimitReached();
+ void notifyWarningOrLimitReached();
void unregister();
}
diff --git a/core/java/android/net/netstats/provider/NetworkStatsProvider.java b/core/java/android/net/netstats/provider/NetworkStatsProvider.java
index 7639d2244cfe..23fc06927ef9 100644
--- a/core/java/android/net/netstats/provider/NetworkStatsProvider.java
+++ b/core/java/android/net/netstats/provider/NetworkStatsProvider.java
@@ -29,7 +29,8 @@ import android.os.RemoteException;
@SystemApi
public abstract class NetworkStatsProvider {
/**
- * A value used by {@link #onSetLimit} and {@link #onSetAlert} indicates there is no limit.
+ * A value used by {@link #onSetLimit}, {@link #onSetAlert} and {@link #onSetWarningAndLimit}
+ * indicates there is no limit.
*/
public static final int QUOTA_UNLIMITED = -1;
@@ -42,13 +43,13 @@ public abstract class NetworkStatsProvider {
}
@Override
- public void onSetLimit(String iface, long quotaBytes) {
- NetworkStatsProvider.this.onSetLimit(iface, quotaBytes);
+ public void onSetAlert(long quotaBytes) {
+ NetworkStatsProvider.this.onSetAlert(quotaBytes);
}
@Override
- public void onSetAlert(long quotaBytes) {
- NetworkStatsProvider.this.onSetAlert(quotaBytes);
+ public void onSetWarningAndLimit(String iface, long warningBytes, long limitBytes) {
+ NetworkStatsProvider.this.onSetWarningAndLimit(iface, warningBytes, limitBytes);
}
};
@@ -145,11 +146,25 @@ public abstract class NetworkStatsProvider {
}
/**
- * Notify system that the quota set by {@code onSetLimit} has been reached.
+ * Notify system that the warning set by {@link #onSetWarningAndLimit} has been reached.
+ */
+ public void notifyWarningReached() {
+ try {
+ // Reuse the code path to notify warning reached with limit reached
+ // since framework handles them in the same way.
+ getProviderCallbackBinderOrThrow().notifyWarningOrLimitReached();
+ } catch (RemoteException e) {
+ e.rethrowAsRuntimeException();
+ }
+ }
+
+ /**
+ * Notify system that the quota set by {@link #onSetLimit} or limit set by
+ * {@link #onSetWarningAndLimit} has been reached.
*/
public void notifyLimitReached() {
try {
- getProviderCallbackBinderOrThrow().notifyLimitReached();
+ getProviderCallbackBinderOrThrow().notifyWarningOrLimitReached();
} catch (RemoteException e) {
e.rethrowAsRuntimeException();
}
@@ -183,6 +198,28 @@ public abstract class NetworkStatsProvider {
public abstract void onSetLimit(@NonNull String iface, long quotaBytes);
/**
+ * Called by {@code NetworkStatsService} when setting the interface quotas for the specified
+ * upstream interface. If a provider implements {@link #onSetWarningAndLimit}, the system
+ * will not call {@link #onSetLimit}. When this method is called, the implementation
+ * should behave as follows:
+ * 1. If {@code warningBytes} is reached on {@code iface}, block all further traffic on
+ * {@code iface} and call {@link NetworkStatsProvider@notifyWarningReached()}.
+ * 2. If {@code limitBytes} is reached on {@code iface}, block all further traffic on
+ * {@code iface} and call {@link NetworkStatsProvider#notifyLimitReached()}.
+ *
+ * @param iface the interface requiring the operation.
+ * @param warningBytes the warning defined as the number of bytes, starting from zero and
+ * counting from now. A value of {@link #QUOTA_UNLIMITED} indicates
+ * there is no warning.
+ * @param limitBytes the limit defined as the number of bytes, starting from zero and counting
+ * from now. A value of {@link #QUOTA_UNLIMITED} indicates there is no limit.
+ */
+ public void onSetWarningAndLimit(@NonNull String iface, long warningBytes, long limitBytes) {
+ // Backward compatibility for those who didn't override this function.
+ onSetLimit(iface, limitBytes);
+ }
+
+ /**
* Called by {@code NetworkStatsService} when setting the alert bytes. Custom implementations
* MUST call {@link NetworkStatsProvider#notifyAlertReached()} when {@code quotaBytes} bytes
* have been reached. Unlike {@link #onSetLimit(String, long)}, the custom implementation should
diff --git a/core/java/android/net/vcn/IVcnManagementService.aidl b/core/java/android/net/vcn/IVcnManagementService.aidl
index 6a3cb42ed75d..5b79f7311b6d 100644
--- a/core/java/android/net/vcn/IVcnManagementService.aidl
+++ b/core/java/android/net/vcn/IVcnManagementService.aidl
@@ -29,7 +29,7 @@ import android.os.ParcelUuid;
*/
interface IVcnManagementService {
void setVcnConfig(in ParcelUuid subscriptionGroup, in VcnConfig config, in String opPkgName);
- void clearVcnConfig(in ParcelUuid subscriptionGroup);
+ void clearVcnConfig(in ParcelUuid subscriptionGroup, in String opPkgName);
void addVcnUnderlyingNetworkPolicyListener(in IVcnUnderlyingNetworkPolicyListener listener);
void removeVcnUnderlyingNetworkPolicyListener(in IVcnUnderlyingNetworkPolicyListener listener);
diff --git a/core/java/android/net/vcn/VcnManager.java b/core/java/android/net/vcn/VcnManager.java
index b73fdbff8ef3..abd41dacdeb6 100644
--- a/core/java/android/net/vcn/VcnManager.java
+++ b/core/java/android/net/vcn/VcnManager.java
@@ -154,7 +154,7 @@ public class VcnManager {
requireNonNull(subscriptionGroup, "subscriptionGroup was null");
try {
- mService.clearVcnConfig(subscriptionGroup);
+ mService.clearVcnConfig(subscriptionGroup, mContext.getOpPackageName());
} catch (ServiceSpecificException e) {
throw new IOException(e);
} catch (RemoteException e) {
@@ -439,7 +439,7 @@ public class VcnManager {
* @param statusCode the code for the status change encountered by this {@link
* VcnStatusCallback}'s subscription group.
*/
- public abstract void onVcnStatusChanged(@VcnStatusCode int statusCode);
+ public abstract void onStatusChanged(@VcnStatusCode int statusCode);
/**
* Invoked when a VCN Gateway Connection corresponding to this callback's subscription group
@@ -476,7 +476,7 @@ public class VcnManager {
* and there is a VCN active for its specified subscription group (this may happen after the
* callback is registered).
*
- * <p>{@link VcnStatusCallback#onVcnStatusChanged(int)} will be invoked on registration with the
+ * <p>{@link VcnStatusCallback#onStatusChanged(int)} will be invoked on registration with the
* current status for the specified subscription group's VCN. If the registrant is not
* privileged for this subscription group, {@link #VCN_STATUS_CODE_NOT_CONFIGURED} will be
* returned.
@@ -580,7 +580,7 @@ public class VcnManager {
@Override
public void onVcnStatusChanged(@VcnStatusCode int statusCode) {
Binder.withCleanCallingIdentity(
- () -> mExecutor.execute(() -> mCallback.onVcnStatusChanged(statusCode)));
+ () -> mExecutor.execute(() -> mCallback.onStatusChanged(statusCode)));
}
// TODO(b/180521637): use ServiceSpecificException for safer Exception 'parceling'
diff --git a/core/java/android/nfc/INfcAdapter.aidl b/core/java/android/nfc/INfcAdapter.aidl
index bc3d5c4ab1ac..11445e9aec5a 100644
--- a/core/java/android/nfc/INfcAdapter.aidl
+++ b/core/java/android/nfc/INfcAdapter.aidl
@@ -72,7 +72,7 @@ interface INfcAdapter
boolean deviceSupportsNfcSecure();
boolean setNfcSecure(boolean enable);
- boolean setAlwaysOn(boolean value);
- boolean isAlwaysOnEnabled();
- boolean isAlwaysOnSupported();
+ boolean setControllerAlwaysOn(boolean value);
+ boolean isControllerAlwaysOn();
+ boolean isControllerAlwaysOnSupported();
}
diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java
index e85eb935a8e7..eed2c77b06b9 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -2254,13 +2254,13 @@ public final class NfcAdapter {
* @hide
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
- public boolean setAlwaysOn(boolean value) {
+ @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON)
+ public boolean setControllerAlwaysOn(boolean value) {
if (!sHasNfcFeature) {
throw new UnsupportedOperationException();
}
try {
- return sService.setAlwaysOn(value);
+ return sService.setControllerAlwaysOn(value);
} catch (RemoteException e) {
attemptDeadServiceRecovery(e);
// Try one more time
@@ -2269,7 +2269,7 @@ public final class NfcAdapter {
return false;
}
try {
- return sService.setAlwaysOn(value);
+ return sService.setControllerAlwaysOn(value);
} catch (RemoteException ee) {
Log.e(TAG, "Failed to recover NFC Service.");
}
@@ -2286,10 +2286,10 @@ public final class NfcAdapter {
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
- public boolean isAlwaysOnEnabled() {
+ @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON)
+ public boolean isControllerAlwaysOn() {
try {
- return sService.isAlwaysOnEnabled();
+ return sService.isControllerAlwaysOn();
} catch (RemoteException e) {
attemptDeadServiceRecovery(e);
// Try one more time
@@ -2298,7 +2298,7 @@ public final class NfcAdapter {
return false;
}
try {
- return sService.isAlwaysOnEnabled();
+ return sService.isControllerAlwaysOn();
} catch (RemoteException ee) {
Log.e(TAG, "Failed to recover NFC Service.");
}
@@ -2315,13 +2315,13 @@ public final class NfcAdapter {
*/
@SystemApi
- @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
- public boolean isAlwaysOnSupported() {
+ @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON)
+ public boolean isControllerAlwaysOnSupported() {
if (!sHasNfcFeature) {
throw new UnsupportedOperationException();
}
try {
- return sService.isAlwaysOnSupported();
+ return sService.isControllerAlwaysOnSupported();
} catch (RemoteException e) {
attemptDeadServiceRecovery(e);
// Try one more time
@@ -2330,7 +2330,7 @@ public final class NfcAdapter {
return false;
}
try {
- return sService.isAlwaysOnSupported();
+ return sService.isControllerAlwaysOnSupported();
} catch (RemoteException ee) {
Log.e(TAG, "Failed to recover NFC Service.");
}
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index 6425c250f317..f5130bcf3088 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -543,6 +543,16 @@ public class Binder implements IBinder {
public final native void markVintfStability();
/**
+ * Use a VINTF-stability binder w/o VINTF requirements. Should be called
+ * on a binder before it is sent out of process.
+ *
+ * This must be called before the object is sent to another process.
+ *
+ * @hide
+ */
+ public final native void forceDowngradeToSystemStability();
+
+ /**
* Flush any Binder commands pending in the current thread to the kernel
* driver. This can be
* useful to call before performing an operation that may block for a long
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 9d16f18ab848..9b29fb1dfaac 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -127,6 +127,7 @@ public class Process {
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ @TestApi
public static final int NFC_UID = 1027;
/**
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 6d3b58c7db20..385a815798dc 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1009,8 +1009,8 @@ public final class Settings {
* Output: Nothing.
*/
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
- public static final String ACTION_MANAGE_ALL_SUBSCRIPTIONS_SETTINGS =
- "android.settings.MANAGE_ALL_SUBSCRIPTIONS_SETTINGS";
+ public static final String ACTION_MANAGE_ALL_SIM_PROFILES_SETTINGS =
+ "android.settings.MANAGE_ALL_SIM_PROFILES_SETTINGS";
/**
* Activity Action: Show screen for controlling which apps can draw on top of other apps.
diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
index 753abea2cfe2..a3a910acae63 100644
--- a/core/java/android/provider/Telephony.java
+++ b/core/java/android/provider/Telephony.java
@@ -4557,6 +4557,15 @@ public final class Telephony {
public static final String VOICE_REG_STATE = "voice_reg_state";
/**
+ * An integer value indicating the current data service state.
+ * <p>
+ * Valid values: {@link ServiceState#STATE_IN_SERVICE},
+ * {@link ServiceState#STATE_OUT_OF_SERVICE}, {@link ServiceState#STATE_EMERGENCY_ONLY},
+ * {@link ServiceState#STATE_POWER_OFF}.
+ */
+ public static final String DATA_REG_STATE = "data_reg_state";
+
+ /**
* The current registered operator numeric id.
* <p>
* In GSM/UMTS, numeric format is 3 digit country code plus 2 or 3 digit
@@ -4572,6 +4581,24 @@ public final class Telephony {
* This is the same as {@link ServiceState#getIsManualSelection()}.
*/
public static final String IS_MANUAL_NETWORK_SELECTION = "is_manual_network_selection";
+
+ /**
+ * The current data network type.
+ * <p>
+ * This is the same as {@link TelephonyManager#getDataNetworkType()}.
+ */
+ public static final String DATA_NETWORK_TYPE = "data_network_type";
+
+ /**
+ * An integer value indicating the current duplex mode if the radio technology is LTE,
+ * LTE-CA or NR.
+ * <p>
+ * Valid values: {@link ServiceState#DUPLEX_MODE_UNKNOWN},
+ * {@link ServiceState#DUPLEX_MODE_FDD}, {@link ServiceState#DUPLEX_MODE_TDD}.
+ * <p>
+ * This is the same as {@link ServiceState#getDuplexMode()}.
+ */
+ public static final String DUPLEX_MODE = "duplex_mode";
}
/**
diff --git a/core/java/android/uwb/AngleMeasurement.java b/core/java/android/uwb/AngleMeasurement.java
index 8c771baaea37..3d603737c48c 100644
--- a/core/java/android/uwb/AngleMeasurement.java
+++ b/core/java/android/uwb/AngleMeasurement.java
@@ -48,7 +48,10 @@ public final class AngleMeasurement implements Parcelable {
* @throws IllegalArgumentException if the radians, errorRadians, or confidenceLevel is out of
* allowed range
*/
- public AngleMeasurement(double radians, double errorRadians, double confidenceLevel) {
+ public AngleMeasurement(
+ @FloatRange(from = -Math.PI, to = +Math.PI) double radians,
+ @FloatRange(from = 0.0, to = +Math.PI) double errorRadians,
+ @FloatRange(from = 0.0, to = 1.0) double confidenceLevel) {
if (radians < -Math.PI || radians > Math.PI) {
throw new IllegalArgumentException("Invalid radians: " + radians);
}
diff --git a/core/java/android/view/OWNERS b/core/java/android/view/OWNERS
index 31f6f6afdd53..4a1d68547f70 100644
--- a/core/java/android/view/OWNERS
+++ b/core/java/android/view/OWNERS
@@ -9,6 +9,7 @@ sumir@google.com
ogunwale@google.com
jjaggi@google.com
roosa@google.com
+jreck@google.com
# Display
per-file Display*.java = file:/services/core/java/com/android/server/display/OWNERS
diff --git a/core/java/com/android/internal/compat/CompatibilityOverrideConfig.java b/core/java/com/android/internal/compat/CompatibilityOverrideConfig.java
index 1c222a73eabc..9a02b7b7aae9 100644
--- a/core/java/com/android/internal/compat/CompatibilityOverrideConfig.java
+++ b/core/java/com/android/internal/compat/CompatibilityOverrideConfig.java
@@ -40,8 +40,7 @@ public final class CompatibilityOverrideConfig implements Parcelable {
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);
+ overrides.put(key, PackageOverride.createFromParcel(in));
}
}
@@ -55,7 +54,7 @@ public final class CompatibilityOverrideConfig implements Parcelable {
dest.writeInt(overrides.size());
for (Long key : overrides.keySet()) {
dest.writeLong(key);
- dest.writeParcelable(overrides.get(key), 0);
+ overrides.get(key).writeToParcel(dest);
}
}
diff --git a/core/java/com/android/internal/compat/IPlatformCompat.aidl b/core/java/com/android/internal/compat/IPlatformCompat.aidl
index 60213e4411c3..78d1d22c401e 100644
--- a/core/java/com/android/internal/compat/IPlatformCompat.aidl
+++ b/core/java/com/android/internal/compat/IPlatformCompat.aidl
@@ -151,15 +151,23 @@ interface IPlatformCompat {
void setOverrides(in CompatibilityChangeConfig overrides, in String packageName);
/**
- * Adds overrides to compatibility changes.
+ * Adds overrides to compatibility changes on release builds.
*
- * <p>Kills the app to allow the changes to take effect.
+ * <p>The caller to this API needs to hold
+ * {@code android.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD} and all change ids
+ * in {@code overrides} need to annotated with {@link android.compat.annotation.Overridable}.
+ *
+ * A release build in this definition means that {@link android.os.Build#IS_DEBUGGABLE} needs to
+ * be {@code false}.
+ *
+ * <p>Note that this does not kill the app, and therefore overrides read from the app process
+ * will not be updated. Overrides read from the system process do 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);
+ void setOverridesOnReleaseBuilds(in CompatibilityOverrideConfig overrides, in String packageName);
/**
* Adds overrides to compatibility changes.
diff --git a/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
index 0e35c84fa226..965971d18241 100644
--- a/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
+++ b/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
@@ -60,7 +60,6 @@ interface ITelephonyRegistry {
void notifyDataConnectionForSubscriber(
int phoneId, int subId, in PreciseDataConnectionState preciseState);
// Uses CellIdentity which is Parcelable here; will convert to CellLocation in client.
- void notifyCellLocation(in CellIdentity cellLocation);
void notifyCellLocationForSubscriber(in int subId, in CellIdentity cellLocation);
@UnsupportedAppUsage
void notifyCellInfo(in List<CellInfo> cellInfo);
diff --git a/core/jni/android_net_NetworkUtils.cpp b/core/jni/android_net_NetworkUtils.cpp
index a781a377694b..1cee8955a7a2 100644
--- a/core/jni/android_net_NetworkUtils.cpp
+++ b/core/jni/android_net_NetworkUtils.cpp
@@ -102,11 +102,6 @@ static jint android_net_utils_bindSocketToNetwork(JNIEnv *env, jobject thiz, job
return setNetworkForSocket(netId, AFileDescriptor_getFD(env, javaFd));
}
-static jboolean android_net_utils_queryUserAccess(JNIEnv *env, jobject thiz, jint uid, jint netId)
-{
- return (jboolean) !queryUserAccess(uid, netId);
-}
-
static bool checkLenAndCopy(JNIEnv* env, const jbyteArray& addr, int len, void* dst)
{
if (env->GetArrayLength(addr) != len) {
@@ -246,7 +241,6 @@ static const JNINativeMethod gNetworkUtilMethods[] = {
{ "getBoundNetworkForProcess", "()I", (void*) android_net_utils_getBoundNetworkForProcess },
{ "bindProcessToNetworkForHostResolution", "(I)Z", (void*) android_net_utils_bindProcessToNetworkForHostResolution },
{ "bindSocketToNetwork", "(Ljava/io/FileDescriptor;I)I", (void*) android_net_utils_bindSocketToNetwork },
- { "queryUserAccess", "(II)Z", (void*)android_net_utils_queryUserAccess },
{ "attachDropAllBPFFilter", "(Ljava/io/FileDescriptor;)V", (void*) android_net_utils_attachDropAllBPFFilter },
{ "detachBPFFilter", "(Ljava/io/FileDescriptor;)V", (void*) android_net_utils_detachBPFFilter },
{ "getTcpRepairWindow", "(Ljava/io/FileDescriptor;)Landroid/net/TcpRepairWindow;", (void*) android_net_utils_getTcpRepairWindow },
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index 249950419441..e4dddd277b0b 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -486,9 +486,15 @@ public:
}
void markVintf() {
+ AutoMutex _l(mLock);
mVintf = true;
}
+ void forceDowngradeToSystemStability() {
+ AutoMutex _l(mLock);
+ mVintf = false;
+ }
+
sp<IBinder> getExtension() {
AutoMutex _l(mLock);
sp<JavaBBinder> b = mBinder.promote();
@@ -1013,6 +1019,12 @@ static void android_os_Binder_markVintfStability(JNIEnv* env, jobject clazz) {
jbh->markVintf();
}
+static void android_os_Binder_forceDowngradeToSystemStability(JNIEnv* env, jobject clazz) {
+ JavaBBinderHolder* jbh =
+ (JavaBBinderHolder*) env->GetLongField(clazz, gBinderOffsets.mObject);
+ jbh->forceDowngradeToSystemStability();
+}
+
static void android_os_Binder_flushPendingCommands(JNIEnv* env, jobject clazz)
{
IPCThreadState::self()->flushCommands();
@@ -1076,6 +1088,7 @@ static const JNINativeMethod gBinderMethods[] = {
{ "clearCallingWorkSource", "()J", (void*)android_os_Binder_clearCallingWorkSource },
{ "restoreCallingWorkSource", "(J)V", (void*)android_os_Binder_restoreCallingWorkSource },
{ "markVintfStability", "()V", (void*)android_os_Binder_markVintfStability},
+ { "forceDowngradeToSystemStability", "()V", (void*)android_os_Binder_forceDowngradeToSystemStability},
{ "flushPendingCommands", "()V", (void*)android_os_Binder_flushPendingCommands },
{ "getNativeBBinderHolder", "()J", (void*)android_os_Binder_getNativeBBinderHolder },
{ "getNativeFinalizer", "()J", (void*)android_os_Binder_getNativeFinalizer },
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 61e7d0ad9a73..1f7695eb7fc0 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1882,6 +1882,12 @@
android:label="@string/permlab_preferredPaymentInfo"
android:protectionLevel="normal" />
+ <!-- @SystemApi Allows access to set NFC controller always on states.
+ <p>Protection level: signature|privileged
+ @hide -->
+ <permission android:name="android.permission.NFC_SET_CONTROLLER_ALWAYS_ON"
+ android:protectionLevel="signature|privileged" />
+
<!-- @SystemApi Allows an internal user to use privileged SecureElement APIs.
Applications holding this permission can access OMAPI reset system API
and bypass OMAPI AccessControlEnforcer.
@@ -2545,10 +2551,6 @@
<permission android:name="android.permission.CREATE_USERS"
android:protectionLevel="signature" />
- <!-- @TestApi @hide Allows an application to query user info for all users on the device. -->
- <permission android:name="android.permission.QUERY_USERS"
- android:protectionLevel="signature" />
-
<!-- @hide Allows an application to set the profile owners and the device owner.
This permission is not available to third party applications.-->
<permission android:name="android.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS"
@@ -2556,6 +2558,16 @@
android:label="@string/permlab_manageProfileAndDeviceOwners"
android:description="@string/permdesc_manageProfileAndDeviceOwners" />
+ <!-- @TestApi @hide Allows an application to reset the record of previous system update freeze
+ periods. -->
+ <permission android:name="android.permission.CLEAR_FREEZE_PERIOD"
+ android:protectionLevel="signature" />
+
+ <!-- @TestApi @hide Allows an application to force available DevicePolicyManager logs to
+ DPC. -->
+ <permission android:name="android.permission.FORCE_DEVICE_POLICY_MANAGER_LOGS"
+ android:protectionLevel="signature" />
+
<!-- Allows an application to get full detailed information about
recently running tasks, with full fidelity to the real state.
@hide -->
@@ -4101,6 +4113,11 @@
<permission android:name="android.permission.MODIFY_AUDIO_ROUTING"
android:protectionLevel="signature|privileged" />
+ <!-- @TestApi Allows an application to query audio related state.
+ @hide -->
+ <permission android:name="android.permission.QUERY_AUDIO_STATE"
+ android:protectionLevel="signature" />
+
<!-- Allows an application to modify what effects are applied to all audio
(matching certain criteria) from any application.
<p>Not for use by third-party applications.</p>
@@ -4578,6 +4595,11 @@
<permission android:name="android.permission.SET_INITIAL_LOCK"
android:protectionLevel="signature|setup"/>
+ <!-- @TestApi Allows applications to set and verify lockscreen credentials.
+ @hide -->
+ <permission android:name="android.permission.SET_AND_VERIFY_LOCKSCREEN_CREDENTIALS"
+ android:protectionLevel="signature"/>
+
<!-- Allows managing (adding, removing) fingerprint templates. Reserved for the system. @hide -->
<permission android:name="android.permission.MANAGE_FINGERPRINT"
android:protectionLevel="signature|privileged" />
@@ -5123,9 +5145,16 @@
<permission android:name="android.permission.READ_COMPAT_CHANGE_CONFIG"
android:protectionLevel="signature|privileged" />
<!-- Allows an app to override compat change config.
+ This permission only allows to override config on debuggable builds or test-apks and is
+ therefore a less powerful version of OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD.
@hide <p>Not for use by third-party applications.</p> -->
<permission android:name="android.permission.OVERRIDE_COMPAT_CHANGE_CONFIG"
android:protectionLevel="signature|privileged" />
+ <!-- @SystemApi Allows an app to override compat change config on release builds.
+ Only ChangeIds that are annotated as @Overridable can be overridden on release builds.
+ @hide -->
+ <permission android:name="android.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD"
+ android:protectionLevel="signature|privileged" />
<!-- Allows input events to be monitored. Very dangerous! @hide -->
<permission android:name="android.permission.MONITOR_INPUT"
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 0f6f15de6458..bfe7802726a3 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -3415,10 +3415,6 @@
<!-- True if assistant app should be pinned via Pinner Service -->
<bool name="config_pinnerAssistantApp">false</bool>
- <!-- List of files pinned by the Pinner Service with the JIT Zygote boot image b/119800099 -->
- <string-array translatable="false" name="config_jitzygoteBootImagePinnerServiceFiles">
- </string-array>
-
<!-- Number of days preloaded file cache should be preserved on a device before it can be
deleted -->
<integer name="config_keepPreloadsMinDays">7</integer>
@@ -4343,6 +4339,11 @@
check after reboot or airplane mode toggling -->
<bool translatable="false" name="reset_geo_fencing_check_after_boot_or_apm">false</bool>
+ <!-- Boolean indicating whether all CB messages should be disabled on this device. This config
+ is intended to be used by OEMs who need to disable CB messages for regulatory requirements,
+ (e.g. the device is a tablet in a country where tablets should not receive CB messages) -->
+ <bool translatable="false" name="config_disable_all_cb_messages">false</bool>
+
<!-- Screen Wake Keys
Determines whether the specified key groups can be used to wake up the device. -->
<bool name="config_wakeOnDpadKeyPress">true</bool>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index ad24b79779d4..2901de5b57a2 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3062,7 +3062,6 @@
<java-symbol type="bool" name="config_pinnerCameraApp" />
<java-symbol type="bool" name="config_pinnerHomeApp" />
<java-symbol type="bool" name="config_pinnerAssistantApp" />
- <java-symbol type="array" name="config_jitzygoteBootImagePinnerServiceFiles" />
<java-symbol type="string" name="config_doubleTouchGestureEnableFile" />
@@ -3848,6 +3847,7 @@
<java-symbol type="layout" name="chooser_action_button" />
<java-symbol type="dimen" name="chooser_action_button_icon_size" />
<java-symbol type="string" name="config_defaultNearbySharingComponent" />
+ <java-symbol type="bool" name="config_disable_all_cb_messages" />
<java-symbol type="drawable" name="ic_close" />
<java-symbol type="bool" name="config_automotiveHideNavBarForKeyboard" />
diff --git a/core/tests/coretests/src/android/content/OWNERS b/core/tests/coretests/src/android/content/OWNERS
index c61a4b538a44..0b945895ad7f 100644
--- a/core/tests/coretests/src/android/content/OWNERS
+++ b/core/tests/coretests/src/android/content/OWNERS
@@ -2,3 +2,5 @@ per-file AssetTest.java = file:/core/java/android/content/res/OWNERS
per-file ContextTest.java = file:/services/core/java/com/android/server/wm/OWNERS
per-file *Launcher* = file:/core/java/android/content/pm/LAUNCHER_OWNERS
per-file *Shortcut* = file:/core/java/android/content/pm/SHORTCUT_OWNERS
+per-file ComponentCallbacksControllerTest = file:/services/core/java/com/android/server/wm/OWNERS
+per-file ComponentCallbacksControllerTest = charlesccchen@google.com
diff --git a/data/etc/OWNERS b/data/etc/OWNERS
index 549e074d297c..5aacfddab28c 100644
--- a/data/etc/OWNERS
+++ b/data/etc/OWNERS
@@ -13,3 +13,4 @@ toddke@google.com
yamasani@google.com
per-file preinstalled-packages* = file:/MULTIUSER_OWNERS
+per-file services.core.protolog.json = file:/services/core/java/com/android/server/wm/OWNERS
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 653e690506bc..009421b05b34 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -444,6 +444,8 @@ applications that come with the platform
<permission name="android.permission.MANAGE_TIME_AND_ZONE_DETECTION" />
<!-- Permissions required for CTS test - CtsHdmiCecHostTestCases -->
<permission name="android.permission.HDMI_CEC"/>
+ <!-- Permission required for CTS test - MediaPlayerTest -->
+ <permission name="android.permission.BIND_IMS_SERVICE" />
<!-- Permission needed for CTS test - WifiManagerTest -->
<permission name="android.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS" />
<permission name="android.permission.WIFI_UPDATE_COEX_UNSAFE_CHANNELS" />
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index fe5c1be05927..d048efcfd12c 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -1196,13 +1196,11 @@ public class Typeface {
/** @hide */
public boolean isSupportedAxes(int axis) {
- if (mSupportedAxes == null) {
- synchronized (this) {
+ synchronized (this) {
+ if (mSupportedAxes == null) {
+ mSupportedAxes = nativeGetSupportedAxes(native_instance);
if (mSupportedAxes == null) {
- mSupportedAxes = nativeGetSupportedAxes(native_instance);
- if (mSupportedAxes == null) {
- mSupportedAxes = EMPTY_AXES;
- }
+ mSupportedAxes = EMPTY_AXES;
}
}
}
diff --git a/keystore/java/android/security/AndroidKeyStoreMaintenance.java b/keystore/java/android/security/AndroidKeyStoreMaintenance.java
index 35b1c169f283..72cea0cacd12 100644
--- a/keystore/java/android/security/AndroidKeyStoreMaintenance.java
+++ b/keystore/java/android/security/AndroidKeyStoreMaintenance.java
@@ -139,4 +139,18 @@ public class AndroidKeyStoreMaintenance {
return SYSTEM_ERROR;
}
}
+
+ /**
+ * Informs Keystore 2.0 that an off body event was detected.
+ */
+ public static void onDeviceOffBody() {
+ if (!android.security.keystore2.AndroidKeyStoreProvider.isInstalled()) return;
+ try {
+ getService().onDeviceOffBody();
+ } catch (Exception e) {
+ // TODO This fails open. This is not a regression with respect to keystore1 but it
+ // should get fixed.
+ Log.e(TAG, "Error while reporting device off body event.", e);
+ }
+ }
}
diff --git a/keystore/java/android/security/GenerateRkpKey.java b/keystore/java/android/security/GenerateRkpKey.java
new file mode 100644
index 000000000000..a1a7aa85519f
--- /dev/null
+++ b/keystore/java/android/security/GenerateRkpKey.java
@@ -0,0 +1,99 @@
+/*
+ * 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.security;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.IBinder;
+import android.os.RemoteException;
+
+/**
+ * GenerateKey is a helper class to handle interactions between Keystore and the RemoteProvisioner
+ * app. There are two cases where Keystore should use this class.
+ *
+ * (1) : An app generates a new attested key pair, so Keystore calls notifyKeyGenerated to let the
+ * RemoteProvisioner app check if the state of the attestation key pool is getting low enough
+ * to warrant provisioning more attestation certificates early.
+ *
+ * (2) : An app attempts to generate a new key pair, but the keystore service discovers it is out of
+ * attestation key pairs and cannot provide one for the given application. Keystore can then
+ * make a blocking call on notifyEmpty to allow the RemoteProvisioner app to get another
+ * attestation certificate chain provisioned.
+ *
+ * In most cases, the proper usage of (1) should preclude the need for (2).
+ *
+ * @hide
+ */
+public class GenerateRkpKey {
+
+ private IGenerateRkpKeyService mBinder;
+ private Context mContext;
+
+ private ServiceConnection mConnection = new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName className, IBinder service) {
+ mBinder = IGenerateRkpKeyService.Stub.asInterface(service);
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName className) {
+ mBinder = null;
+ }
+ };
+
+ /**
+ * Constructor which takes a Context object.
+ */
+ public GenerateRkpKey(Context context) {
+ mContext = context;
+ }
+
+ /**
+ * Fulfills the use case of (2) described in the class documentation. Blocks until the
+ * RemoteProvisioner application can get new attestation keys signed by the server.
+ */
+ public void notifyEmpty(int securityLevel) throws RemoteException {
+ Intent intent = new Intent(IGenerateRkpKeyService.class.getName());
+ ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
+ intent.setComponent(comp);
+ if (comp == null || !mContext.bindService(intent, mConnection, Context.BIND_AUTO_CREATE)) {
+ throw new RemoteException("Failed to bind to GenerateKeyService");
+ }
+ if (mBinder != null) {
+ mBinder.generateKey(securityLevel);
+ }
+ mContext.unbindService(mConnection);
+ }
+
+ /**
+ * FUlfills the use case of (1) described in the class documentation. Non blocking call.
+ */
+ public void notifyKeyGenerated(int securityLevel) throws RemoteException {
+ Intent intent = new Intent(IGenerateRkpKeyService.class.getName());
+ ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
+ intent.setComponent(comp);
+ if (comp == null || !mContext.bindService(intent, mConnection, Context.BIND_AUTO_CREATE)) {
+ throw new RemoteException("Failed to bind to GenerateKeyService");
+ }
+ if (mBinder != null) {
+ mBinder.notifyKeyGenerated(securityLevel);
+ }
+ mContext.unbindService(mConnection);
+ }
+}
diff --git a/keystore/java/android/security/GenerateRkpKeyException.java b/keystore/java/android/security/GenerateRkpKeyException.java
new file mode 100644
index 000000000000..a2d65e4e7119
--- /dev/null
+++ b/keystore/java/android/security/GenerateRkpKeyException.java
@@ -0,0 +1,31 @@
+/*
+ * 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.security;
+
+/**
+ * Thrown on problems in attempting to attest to a key using a remotely provisioned key.
+ *
+ * @hide
+ */
+public class GenerateRkpKeyException extends Exception {
+
+ /**
+ * Constructs a new {@code GenerateRkpKeyException}.
+ */
+ public GenerateRkpKeyException() {
+ }
+}
diff --git a/keystore/java/android/security/IGenerateRkpKeyService.aidl b/keystore/java/android/security/IGenerateRkpKeyService.aidl
new file mode 100644
index 000000000000..5f1d6693c23a
--- /dev/null
+++ b/keystore/java/android/security/IGenerateRkpKeyService.aidl
@@ -0,0 +1,36 @@
+/**
+ * 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.security;
+
+/**
+ * Interface to allow the framework to notify the RemoteProvisioner app when keys are empty. This
+ * will be used if Keystore replies with an error code NO_KEYS_AVAILABLE in response to an
+ * attestation request. The framework can then synchronously call generateKey() to get more
+ * attestation keys generated and signed. Upon return, the caller can be certain an attestation key
+ * is available.
+ *
+ * @hide
+ */
+interface IGenerateRkpKeyService {
+ /**
+ * Ping the provisioner service to let it know an app generated a key. This may or may not have
+ * consumed a remotely provisioned attestation key, so the RemoteProvisioner app should check.
+ */
+ oneway void notifyKeyGenerated(in int securityLevel);
+ /** Ping the provisioner service to indicate there are no remaining attestation keys left. */
+ void generateKey(in int securityLevel);
+}
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index a08f390c9fd3..b05149ef75bc 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -1204,6 +1204,7 @@ public class KeyStore {
* Notify keystore that the device went off-body.
*/
public void onDeviceOffBody() {
+ AndroidKeyStoreMaintenance.onDeviceOffBody();
try {
mBinder.onDeviceOffBody();
} catch (RemoteException e) {
diff --git a/keystore/java/android/security/KeyStore2.java b/keystore/java/android/security/KeyStore2.java
index 6ac3821d0f9c..df579bba9dc2 100644
--- a/keystore/java/android/security/KeyStore2.java
+++ b/keystore/java/android/security/KeyStore2.java
@@ -18,8 +18,7 @@ package android.security;
import android.annotation.NonNull;
import android.compat.annotation.ChangeId;
-import android.compat.annotation.EnabledAfter;
-import android.os.Build;
+import android.compat.annotation.Disabled;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.ServiceSpecificException;
@@ -86,7 +85,7 @@ public class KeyStore2 {
* successfully conclude an operation.
*/
@ChangeId
- @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.R)
+ @Disabled // See b/180133780
static final long KEYSTORE_OPERATION_CREATION_MAY_FAIL = 169897160L;
// Never use mBinder directly, use KeyStore2.getService() instead or better yet
@@ -126,6 +125,8 @@ public class KeyStore2 {
}
}
+ private static final String KEYSTORE2_SERVICE_NAME =
+ "android.system.keystore2.IKeystoreService/default";
private KeyStore2() {
mBinder = null;
@@ -138,7 +139,7 @@ public class KeyStore2 {
private synchronized IKeystoreService getService(boolean retryLookup) {
if (mBinder == null || retryLookup) {
mBinder = IKeystoreService.Stub.asInterface(ServiceManager
- .getService("android.system.keystore2"));
+ .getService(KEYSTORE2_SERVICE_NAME));
}
return mBinder;
}
diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
index 5cb2c3b41517..9ca551b26aab 100644
--- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java
+++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
@@ -288,7 +288,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu
private static final Date DEFAULT_CERT_NOT_AFTER = new Date(2461449600000L); // Jan 1 2048
private final String mKeystoreAlias;
- private final int mNamespace;
+ private final @KeyProperties.Namespace int mNamespace;
private final int mKeySize;
private final AlgorithmParameterSpec mSpec;
private final X500Principal mCertificateSubject;
@@ -331,7 +331,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu
*/
public KeyGenParameterSpec(
String keyStoreAlias,
- int namespace,
+ @KeyProperties.Namespace int namespace,
int keySize,
AlgorithmParameterSpec spec,
X500Principal certificateSubject,
@@ -472,7 +472,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu
* @hide
*/
@SystemApi
- public int getNamespace() {
+ public @KeyProperties.Namespace int getNamespace() {
return mNamespace;
}
@@ -896,7 +896,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu
private final String mKeystoreAlias;
private @KeyProperties.PurposeEnum int mPurposes;
- private int mNamespace = KeyProperties.NAMESPACE_APPLICATION;
+ private @KeyProperties.Namespace int mNamespace = KeyProperties.NAMESPACE_APPLICATION;
private int mKeySize = -1;
private AlgorithmParameterSpec mSpec;
private X500Principal mCertificateSubject;
@@ -1051,7 +1051,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAu
*/
@SystemApi
@NonNull
- public Builder setNamespace(int namespace) {
+ public Builder setNamespace(@KeyProperties.Namespace int namespace) {
mNamespace = namespace;
return this;
}
diff --git a/keystore/java/android/security/keystore/KeyProperties.java b/keystore/java/android/security/keystore/KeyProperties.java
index 7b0fa91380e1..682d12a65ea3 100644
--- a/keystore/java/android/security/keystore/KeyProperties.java
+++ b/keystore/java/android/security/keystore/KeyProperties.java
@@ -892,6 +892,22 @@ public abstract class KeyProperties {
}
/**
+ * Namespaces provide system developers and vendors with a way to use keystore without
+ * requiring an applications uid. Namespaces can be configured using SEPolicy.
+ * See <a href="https://source.android.com/security/keystore#access-control">
+ * Keystore 2.0 access-control</a>
+ * {@See KeyGenParameterSpec.Builder#setNamespace}
+ * {@See android.security.keystore2.AndroidKeyStoreLoadStoreParameter}
+ * @hide
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = { "NAMESPACE_" }, value = {
+ NAMESPACE_APPLICATION,
+ NAMESPACE_WIFI,
+ })
+ public @interface Namespace {}
+
+ /**
* This value indicates the implicit keystore namespace of the calling application.
* It is used by default. Only select system components can choose a different namespace
* which it must be configured in SEPolicy.
@@ -912,14 +928,12 @@ public abstract class KeyProperties {
* For legacy support, translate namespaces into known UIDs.
* @hide
*/
- public static int namespaceToLegacyUid(int namespace) {
+ public static int namespaceToLegacyUid(@Namespace int namespace) {
switch (namespace) {
case NAMESPACE_APPLICATION:
return KeyStore.UID_SELF;
case NAMESPACE_WIFI:
return Process.WIFI_UID;
- // TODO Translate WIFI and VPN UIDs once the namespaces are defined.
- // b/171305388 and b/171305607
default:
throw new IllegalArgumentException("No UID corresponding to namespace "
+ namespace);
@@ -930,14 +944,12 @@ public abstract class KeyProperties {
* For legacy support, translate namespaces into known UIDs.
* @hide
*/
- public static int legacyUidToNamespace(int uid) {
+ public static @Namespace int legacyUidToNamespace(int uid) {
switch (uid) {
case KeyStore.UID_SELF:
return NAMESPACE_APPLICATION;
case Process.WIFI_UID:
return NAMESPACE_WIFI;
- // TODO Translate WIFI and VPN UIDs once the namespaces are defined.
- // b/171305388 and b/171305607
default:
throw new IllegalArgumentException("No namespace corresponding to uid "
+ uid);
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
index e401add9ece7..2d8901a37c05 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
@@ -24,6 +24,9 @@ import android.hardware.security.keymint.KeyPurpose;
import android.hardware.security.keymint.SecurityLevel;
import android.hardware.security.keymint.Tag;
import android.os.Build;
+import android.os.RemoteException;
+import android.security.GenerateRkpKey;
+import android.security.GenerateRkpKeyException;
import android.security.KeyPairGeneratorSpec;
import android.security.KeyStore;
import android.security.KeyStore2;
@@ -520,6 +523,18 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
@Override
public KeyPair generateKeyPair() {
+ try {
+ return generateKeyPairHelper();
+ } catch (GenerateRkpKeyException e) {
+ try {
+ return generateKeyPairHelper();
+ } catch (GenerateRkpKeyException f) {
+ throw new ProviderException("Failed to provision new attestation keys.");
+ }
+ }
+ }
+
+ private KeyPair generateKeyPairHelper() throws GenerateRkpKeyException {
if (mKeyStore == null || mSpec == null) {
throw new IllegalStateException("Not initialized");
}
@@ -557,13 +572,30 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
AndroidKeyStorePublicKey publicKey =
AndroidKeyStoreProvider.makeAndroidKeyStorePublicKeyFromKeyEntryResponse(
descriptor, metadata, iSecurityLevel, mKeymasterAlgorithm);
-
+ GenerateRkpKey keyGen = new GenerateRkpKey(KeyStore.getApplicationContext());
+ try {
+ if (mSpec.getAttestationChallenge() != null) {
+ keyGen.notifyKeyGenerated(securityLevel);
+ }
+ } catch (RemoteException e) {
+ // This is not really an error state, and necessarily does not apply to non RKP
+ // systems or hybrid systems where RKP is not currently turned on.
+ Log.d(TAG, "Couldn't connect to the RemoteProvisioner backend.");
+ }
success = true;
return new KeyPair(publicKey, publicKey.getPrivateKey());
} catch (android.security.KeyStoreException e) {
switch(e.getErrorCode()) {
case KeymasterDefs.KM_ERROR_HARDWARE_TYPE_UNAVAILABLE:
throw new StrongBoxUnavailableException("Failed to generated key pair.", e);
+ case ResponseCode.OUT_OF_KEYS:
+ GenerateRkpKey keyGen = new GenerateRkpKey(KeyStore.getApplicationContext());
+ try {
+ keyGen.notifyEmpty(securityLevel);
+ } catch (RemoteException f) {
+ throw new ProviderException("Failed to talk to RemoteProvisioner", f);
+ }
+ throw new GenerateRkpKeyException();
default:
ProviderException p = new ProviderException("Failed to generate key pair.", e);
if ((mSpec.getPurposes() & KeyProperties.PURPOSE_WRAP_KEY) != 0) {
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreLoadStoreParameter.java b/keystore/java/android/security/keystore2/AndroidKeyStoreLoadStoreParameter.java
index 0c6744f9822c..25b1c864b5d1 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreLoadStoreParameter.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreLoadStoreParameter.java
@@ -16,6 +16,8 @@
package android.security.keystore2;
+import android.security.keystore.KeyProperties;
+
import java.security.KeyStore;
import java.security.KeyStore.ProtectionParameter;
@@ -24,9 +26,9 @@ import java.security.KeyStore.ProtectionParameter;
*/
public class AndroidKeyStoreLoadStoreParameter implements KeyStore.LoadStoreParameter {
- private final int mNamespace;
+ private final @KeyProperties.Namespace int mNamespace;
- public AndroidKeyStoreLoadStoreParameter(int namespace) {
+ public AndroidKeyStoreLoadStoreParameter(@KeyProperties.Namespace int namespace) {
mNamespace = namespace;
}
@@ -35,7 +37,7 @@ public class AndroidKeyStoreLoadStoreParameter implements KeyStore.LoadStorePara
return null;
}
- int getNamespace() {
+ @KeyProperties.Namespace int getNamespace() {
return mNamespace;
}
}
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java
index 39607aeb3852..32f98a2538f3 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java
@@ -100,7 +100,7 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi {
public static final String NAME = "AndroidKeyStore";
private KeyStore2 mKeyStore;
- private int mNamespace = KeyProperties.NAMESPACE_APPLICATION;
+ private @KeyProperties.Namespace int mNamespace = KeyProperties.NAMESPACE_APPLICATION;
@Override
public Key engineGetKey(String alias, char[] password) throws NoSuchAlgorithmException,
@@ -1125,7 +1125,7 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi {
@Override
public void engineLoad(LoadStoreParameter param) throws IOException,
NoSuchAlgorithmException, CertificateException {
- int namespace = KeyProperties.NAMESPACE_APPLICATION;
+ @KeyProperties.Namespace int namespace = KeyProperties.NAMESPACE_APPLICATION;
if (param != null) {
if (param instanceof AndroidKeyStoreLoadStoreParameter) {
namespace = ((AndroidKeyStoreLoadStoreParameter) param).getNamespace();
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index 0780c6875eb5..5633236a122e 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -45,6 +45,7 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
@@ -4411,14 +4412,25 @@ final public class MediaCodec {
int i = 0;
for (final String key: params.keySet()) {
- keys[i] = key;
- Object value = params.get(key);
-
- // Bundle's byte array is a byte[], JNI layer only takes ByteBuffer
- if (value instanceof byte[]) {
- values[i] = ByteBuffer.wrap((byte[])value);
+ if (key.equals(MediaFormat.KEY_AUDIO_SESSION_ID)) {
+ int sessionId = 0;
+ try {
+ sessionId = (Integer)params.get(key);
+ } catch (Exception e) {
+ throw new IllegalArgumentException("Wrong Session ID Parameter!");
+ }
+ keys[i] = "audio-hw-sync";
+ values[i] = AudioSystem.getAudioHwSyncForSession(sessionId);
} else {
- values[i] = value;
+ keys[i] = key;
+ Object value = params.get(key);
+
+ // Bundle's byte array is a byte[], JNI layer only takes ByteBuffer
+ if (value instanceof byte[]) {
+ values[i] = ByteBuffer.wrap((byte[])value);
+ } else {
+ values[i] = value;
+ }
}
++i;
}
@@ -4554,6 +4566,128 @@ final public class MediaCodec {
private native void native_enableOnFrameRenderedListener(boolean enable);
+ /**
+ * Returns a list of vendor parameter names.
+ * <p>
+ * This method can be called in any codec state except for released state.
+ *
+ * @return a list containing supported vendor parameters; an empty
+ * list if no vendor parameters are supported. The order of the
+ * parameters is arbitrary.
+ * @throws IllegalStateException if in the Released state.
+ */
+ @NonNull
+ public List<String> getSupportedVendorParameters() {
+ return native_getSupportedVendorParameters();
+ }
+
+ @NonNull
+ private native List<String> native_getSupportedVendorParameters();
+
+ /**
+ * Contains description of a parameter.
+ */
+ public static class ParameterDescriptor {
+ private ParameterDescriptor() {}
+
+ /**
+ * Returns the name of the parameter.
+ */
+ @NonNull
+ public String getName() {
+ return mName;
+ }
+
+ /**
+ * Returns the type of the parameter.
+ * {@link MediaFormat#TYPE_NULL} is never returned.
+ */
+ @MediaFormat.Type
+ public int getType() {
+ return mType;
+ }
+
+ private String mName;
+ private @MediaFormat.Type int mType;
+ }
+
+ /**
+ * Describe a parameter with the name.
+ * <p>
+ * This method can be called in any codec state except for released state.
+ *
+ * @param name name of the parameter to describe, typically one from
+ * {@link #getSupportedVendorParameters}.
+ * @return {@link ParameterDescriptor} object that describes the parameter.
+ * {@code null} if unrecognized / not able to describe.
+ * @throws IllegalStateException if in the Released state.
+ */
+ @Nullable
+ public ParameterDescriptor getParameterDescriptor(@NonNull String name) {
+ return native_getParameterDescriptor(name);
+ }
+
+ @Nullable
+ private native ParameterDescriptor native_getParameterDescriptor(@NonNull String name);
+
+ /**
+ * Subscribe to vendor parameters, so that changes to these parameters generate
+ * output format change event.
+ * <p>
+ * Unrecognized parameter names or standard (non-vendor) parameter names will be ignored.
+ * {@link #reset} also resets the list of subscribed parameters.
+ * If a parameter in {@code names} is already subscribed, it will remain subscribed.
+ * <p>
+ * This method can be called in any codec state except for released state. When called in
+ * running state with newly subscribed parameters, it takes effect no later than the
+ * processing of the subsequently queued buffer. For the new parameters, the codec will generate
+ * output format change event.
+ * <p>
+ * Note that any vendor parameters set in a {@link #configure} or
+ * {@link #setParameters} call are automatically subscribed.
+ * <p>
+ * See also {@link #INFO_OUTPUT_FORMAT_CHANGED} or {@link Callback#onOutputFormatChanged}
+ * for output format change events.
+ *
+ * @param names names of the vendor parameters to subscribe. This may be an empty list,
+ * and in that case this method will not change the list of subscribed parameters.
+ * @throws IllegalStateException if in the Released state.
+ */
+ public void subscribeToVendorParameters(@NonNull List<String> names) {
+ native_subscribeToVendorParameters(names);
+ }
+
+ private native void native_subscribeToVendorParameters(@NonNull List<String> names);
+
+ /**
+ * Unsubscribe from vendor parameters, so that changes to these parameters
+ * no longer generate output format change event.
+ * <p>
+ * Unrecognized parameter names, standard (non-vendor) parameter names will be ignored.
+ * {@link #reset} also resets the list of subscribed parameters.
+ * If a parameter in {@code names} is already unsubscribed, it will remain unsubscribed.
+ * <p>
+ * This method can be called in any codec state except for released state. When called in
+ * running state with newly unsubscribed parameters, it takes effect no later than the
+ * processing of the subsequently queued buffer.
+ * <p>
+ * Note that any vendor parameters set in a {@link #configure} or
+ * {@link #setParameters} call are automatically subscribed, and with this method
+ * they can be unsubscribed.
+ * <p>
+ * See also {@link #INFO_OUTPUT_FORMAT_CHANGED} or {@link Callback#onOutputFormatChanged}
+ * for output format change events.
+ *
+ * @param names names of the vendor parameters to unsubscribe. This may be an empty list,
+ * and in that case this method will not change the list of subscribed parameters.
+ * @throws IllegalStateException if in the Released state.
+ */
+ public void unsubscribeFromVendorParameters(@NonNull List<String> names) {
+ native_unsubscribeFromVendorParameters(names);
+ }
+
+ private native void native_unsubscribeFromVendorParameters(@NonNull List<String> names);
+
private EventHandler getEventHandlerOn(
@Nullable Handler handler, @NonNull EventHandler lastHandler) {
if (handler == null) {
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index 0b0e162d4faf..b3eb8ba77639 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -53,6 +53,7 @@
#include <media/MediaCodecBuffer.h>
#include <media/hardware/VideoAPI.h>
+#include <media/stagefright/CodecBase.h>
#include <media/stagefright/MediaCodec.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
@@ -82,6 +83,16 @@ enum {
EVENT_FRAME_RENDERED = 3,
};
+// From MediaFormat.java
+enum {
+ TYPE_NULL = 0,
+ TYPE_INTEGER = 1,
+ TYPE_LONG = 2,
+ TYPE_FLOAT = 3,
+ TYPE_STRING = 4,
+ TYPE_BYTE_BUFFER = 5,
+};
+
static struct CryptoErrorCodes {
jint cryptoErrorNoKey;
jint cryptoErrorKeyExpired;
@@ -138,6 +149,8 @@ static struct {
} gByteBufferInfo;
static struct {
+ jclass clazz;
+ jmethodID ctorId;
jmethodID sizeId;
jmethodID getId;
jmethodID addId;
@@ -152,6 +165,13 @@ static struct {
jfieldID lockId;
} gLinearBlockInfo;
+static struct {
+ jclass clazz;
+ jmethodID ctorId;
+ jfieldID nameId;
+ jfieldID typeId;
+} gDescriptorInfo;
+
struct fields_t {
jmethodID postEventFromNativeID;
jmethodID lockAndGetContextID;
@@ -922,6 +942,74 @@ void JMediaCodec::selectAudioPresentation(const int32_t presentationId, const in
(void)mCodec->setParameters(msg);
}
+status_t JMediaCodec::querySupportedVendorParameters(JNIEnv *env, jobject *namesObj) {
+ std::vector<std::string> names;
+ status_t status = mCodec->querySupportedVendorParameters(&names);
+ if (status != OK) {
+ return status;
+ }
+ *namesObj = env->NewObject(gArrayListInfo.clazz, gArrayListInfo.ctorId);
+ for (const std::string &name : names) {
+ ScopedLocalRef<jstring> nameStr{env, env->NewStringUTF(name.c_str())};
+ (void)env->CallBooleanMethod(*namesObj, gArrayListInfo.addId, nameStr.get());
+ }
+ return OK;
+}
+
+status_t JMediaCodec::describeParameter(JNIEnv *env, jstring name, jobject *descObj) {
+ const char *tmp = env->GetStringUTFChars(name, nullptr);
+ CodecParameterDescriptor desc;
+ status_t status = mCodec->describeParameter(tmp, &desc);
+ env->ReleaseStringUTFChars(name, tmp);
+ if (status != OK) {
+ return status;
+ }
+ jint type = TYPE_NULL;
+ switch (desc.type) {
+ case AMessage::kTypeInt32: type = TYPE_INTEGER; break;
+ case AMessage::kTypeSize:
+ case AMessage::kTypeInt64: type = TYPE_LONG; break;
+ case AMessage::kTypeFloat: type = TYPE_FLOAT; break;
+ case AMessage::kTypeString: type = TYPE_STRING; break;
+ case AMessage::kTypeBuffer: type = TYPE_BYTE_BUFFER; break;
+ default: type = TYPE_NULL; break;
+ }
+ if (type == TYPE_NULL) {
+ return BAD_VALUE;
+ }
+ *descObj = env->NewObject(gDescriptorInfo.clazz, gDescriptorInfo.ctorId);
+ env->SetObjectField(*descObj, gDescriptorInfo.nameId, name);
+ env->SetIntField(*descObj, gDescriptorInfo.typeId, type);
+ return OK;
+}
+
+static void BuildVectorFromList(JNIEnv *env, jobject list, std::vector<std::string> *vec) {
+ ScopedLocalRef<jclass> listClazz{env, env->FindClass("java/util/List")};
+ ScopedLocalRef<jclass> iterClazz{env, env->FindClass("java/util/Iterator")};
+ jmethodID hasNextID = env->GetMethodID(iterClazz.get(), "hasNext", "()Z");
+ jmethodID nextID = env->GetMethodID(iterClazz.get(), "next", "()Ljava/lang/Object;");
+ jobject it = env->CallObjectMethod(
+ list, env->GetMethodID(listClazz.get(), "iterator", "()Ljava/util/Iterator;"));
+ while (env->CallBooleanMethod(it, hasNextID)) {
+ jstring name = (jstring)env->CallObjectMethod(it, nextID);
+ const char *tmp = env->GetStringUTFChars(name, nullptr);
+ vec->push_back(tmp);
+ env->ReleaseStringUTFChars(name, tmp);
+ }
+}
+
+status_t JMediaCodec::subscribeToVendorParameters(JNIEnv *env, jobject namesObj) {
+ std::vector<std::string> names;
+ BuildVectorFromList(env, namesObj, &names);
+ return mCodec->subscribeToVendorParameters(names);
+}
+
+status_t JMediaCodec::unsubscribeFromVendorParameters(JNIEnv *env, jobject namesObj) {
+ std::vector<std::string> names;
+ BuildVectorFromList(env, namesObj, &names);
+ return mCodec->unsubscribeFromVendorParameters(names);
+}
+
static jthrowable createCodecException(
JNIEnv *env, status_t err, int32_t actionCode, const char *msg = NULL) {
ScopedLocalRef<jclass> clazz(
@@ -2602,6 +2690,73 @@ static void android_media_MediaCodec_setAudioPresentation(
codec->selectAudioPresentation((int32_t)presentationId, (int32_t)programId);
}
+static jobject android_media_MediaCodec_getSupportedVendorParameters(
+ JNIEnv *env, jobject thiz) {
+ sp<JMediaCodec> codec = getMediaCodec(env, thiz);
+
+ if (codec == NULL || codec->initCheck() != OK) {
+ throwExceptionAsNecessary(env, INVALID_OPERATION);
+ return NULL;
+ }
+
+ jobject ret = NULL;
+ status_t status = codec->querySupportedVendorParameters(env, &ret);
+ if (status != OK) {
+ throwExceptionAsNecessary(env, status);
+ }
+
+ return ret;
+}
+
+static jobject android_media_MediaCodec_getParameterDescriptor(
+ JNIEnv *env, jobject thiz, jstring name) {
+ sp<JMediaCodec> codec = getMediaCodec(env, thiz);
+
+ if (codec == NULL || codec->initCheck() != OK) {
+ throwExceptionAsNecessary(env, INVALID_OPERATION);
+ return NULL;
+ }
+
+ jobject ret = NULL;
+ status_t status = codec->describeParameter(env, name, &ret);
+ if (status != OK) {
+ ret = NULL;
+ }
+ return ret;
+}
+
+static void android_media_MediaCodec_subscribeToVendorParameters(
+ JNIEnv *env, jobject thiz, jobject names) {
+ sp<JMediaCodec> codec = getMediaCodec(env, thiz);
+
+ if (codec == NULL || codec->initCheck() != OK) {
+ throwExceptionAsNecessary(env, INVALID_OPERATION);
+ return;
+ }
+
+ status_t status = codec->subscribeToVendorParameters(env, names);
+ if (status != OK) {
+ throwExceptionAsNecessary(env, status);
+ }
+ return;
+}
+
+static void android_media_MediaCodec_unsubscribeFromVendorParameters(
+ JNIEnv *env, jobject thiz, jobject names) {
+ sp<JMediaCodec> codec = getMediaCodec(env, thiz);
+
+ if (codec == NULL || codec->initCheck() != OK) {
+ throwExceptionAsNecessary(env, INVALID_OPERATION);
+ return;
+ }
+
+ status_t status = codec->unsubscribeFromVendorParameters(env, names);
+ if (status != OK) {
+ throwExceptionAsNecessary(env, status);
+ }
+ return;
+}
+
static void android_media_MediaCodec_native_init(JNIEnv *env, jclass) {
ScopedLocalRef<jclass> clazz(
env, env->FindClass("android/media/MediaCodec"));
@@ -2861,6 +3016,10 @@ static void android_media_MediaCodec_native_init(JNIEnv *env, jclass) {
clazz.reset(env->FindClass("java/util/ArrayList"));
CHECK(clazz.get() != NULL);
+ gArrayListInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
+
+ gArrayListInfo.ctorId = env->GetMethodID(clazz.get(), "<init>", "()V");
+ CHECK(gArrayListInfo.ctorId != NULL);
gArrayListInfo.sizeId = env->GetMethodID(clazz.get(), "size", "()I");
CHECK(gArrayListInfo.sizeId != NULL);
@@ -2891,6 +3050,19 @@ static void android_media_MediaCodec_native_init(JNIEnv *env, jclass) {
gLinearBlockInfo.lockId = env->GetFieldID(clazz.get(), "mLock", "Ljava/lang/Object;");
CHECK(gLinearBlockInfo.lockId != NULL);
+
+ clazz.reset(env->FindClass("android/media/MediaCodec$ParameterDescriptor"));
+ CHECK(clazz.get() != NULL);
+ gDescriptorInfo.clazz = (jclass)env->NewGlobalRef(clazz.get());
+
+ gDescriptorInfo.ctorId = env->GetMethodID(clazz.get(), "<init>", "()V");
+ CHECK(gDescriptorInfo.ctorId != NULL);
+
+ gDescriptorInfo.nameId = env->GetFieldID(clazz.get(), "mName", "Ljava/lang/String;");
+ CHECK(gDescriptorInfo.nameId != NULL);
+
+ gDescriptorInfo.typeId = env->GetFieldID(clazz.get(), "mType", "I");
+ CHECK(gDescriptorInfo.typeId != NULL);
}
static void android_media_MediaCodec_native_setup(
@@ -3217,6 +3389,21 @@ static const JNINativeMethod gMethods[] = {
{ "native_setAudioPresentation", "(II)V",
(void *)android_media_MediaCodec_setAudioPresentation },
+ { "native_getSupportedVendorParameters", "()Ljava/util/List;",
+ (void *)android_media_MediaCodec_getSupportedVendorParameters },
+
+ { "native_getParameterDescriptor",
+ "(Ljava/lang/String;)Landroid/media/MediaCodec$ParameterDescriptor;",
+ (void *)android_media_MediaCodec_getParameterDescriptor },
+
+ { "native_subscribeToVendorParameters",
+ "(Ljava/util/List;)V",
+ (void *)android_media_MediaCodec_subscribeToVendorParameters},
+
+ { "native_unsubscribeFromVendorParameters",
+ "(Ljava/util/List;)V",
+ (void *)android_media_MediaCodec_unsubscribeFromVendorParameters},
+
{ "native_init", "()V", (void *)android_media_MediaCodec_native_init },
{ "native_setup", "(Ljava/lang/String;ZZ)V",
diff --git a/media/jni/android_media_MediaCodec.h b/media/jni/android_media_MediaCodec.h
index a58f9a74b563..33f481d746c1 100644
--- a/media/jni/android_media_MediaCodec.h
+++ b/media/jni/android_media_MediaCodec.h
@@ -162,6 +162,14 @@ struct JMediaCodec : public AHandler {
void selectAudioPresentation(const int32_t presentationId, const int32_t programId);
+ status_t querySupportedVendorParameters(JNIEnv *env, jobject *names);
+
+ status_t describeParameter(JNIEnv *env, jstring name, jobject *desc);
+
+ status_t subscribeToVendorParameters(JNIEnv *env, jobject names);
+
+ status_t unsubscribeFromVendorParameters(JNIEnv *env, jobject names);
+
bool hasCryptoOrDescrambler() { return mHasCryptoOrDescrambler; }
protected:
diff --git a/packages/Connectivity/framework/api/current.txt b/packages/Connectivity/framework/api/current.txt
index e415e01fea3a..0a9560a5c56d 100644
--- a/packages/Connectivity/framework/api/current.txt
+++ b/packages/Connectivity/framework/api/current.txt
@@ -68,6 +68,7 @@ package android.net {
method public boolean bindProcessToNetwork(@Nullable android.net.Network);
method @NonNull public android.net.SocketKeepalive createSocketKeepalive(@NonNull android.net.Network, @NonNull android.net.IpSecManager.UdpEncapsulationSocket, @NonNull java.net.InetAddress, @NonNull java.net.InetAddress, @NonNull java.util.concurrent.Executor, @NonNull android.net.SocketKeepalive.Callback);
method @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.Network getActiveNetwork();
+ method @Nullable @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public android.net.Network getActiveNetworkForUid(int);
method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.NetworkInfo getActiveNetworkInfo();
method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.NetworkInfo[] getAllNetworkInfo();
method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.Network[] getAllNetworks();
@@ -387,7 +388,9 @@ package android.net {
public class NetworkRequest implements android.os.Parcelable {
method public boolean canBeSatisfiedBy(@Nullable android.net.NetworkCapabilities);
method public int describeContents();
+ method @NonNull public int[] getCapabilities();
method @Nullable public android.net.NetworkSpecifier getNetworkSpecifier();
+ method @NonNull public int[] getTransportTypes();
method public boolean hasCapability(int);
method public boolean hasTransport(int);
method public void writeToParcel(android.os.Parcel, int);
@@ -396,6 +399,7 @@ package android.net {
public static class NetworkRequest.Builder {
ctor public NetworkRequest.Builder();
+ ctor public NetworkRequest.Builder(@NonNull android.net.NetworkRequest);
method public android.net.NetworkRequest.Builder addCapability(int);
method public android.net.NetworkRequest.Builder addTransportType(int);
method public android.net.NetworkRequest build();
diff --git a/packages/Connectivity/framework/api/module-lib-current.txt b/packages/Connectivity/framework/api/module-lib-current.txt
index aa7a0ac46598..cd96a1b481b6 100644
--- a/packages/Connectivity/framework/api/module-lib-current.txt
+++ b/packages/Connectivity/framework/api/module-lib-current.txt
@@ -11,16 +11,31 @@ package android.net {
method @Nullable public android.net.ProxyInfo getGlobalProxy();
method @NonNull public static android.util.Range<java.lang.Integer> getIpSecNetIdRange();
method @NonNull public static String getPrivateDnsMode(@NonNull android.content.Context);
+ method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public void registerDefaultNetworkCallbackAsUid(int, @NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler);
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, @NonNull android.os.Handler, @NonNull android.net.ConnectivityManager.NetworkCallback);
+ method @Deprecated public boolean requestRouteToHostAddress(int, java.net.InetAddress);
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void setAcceptPartialConnectivity(@NonNull android.net.Network, boolean, boolean);
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void setAcceptUnvalidated(@NonNull android.net.Network, boolean, boolean);
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void setAvoidUnvalidated(@NonNull android.net.Network);
method @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public void setGlobalProxy(@Nullable android.net.ProxyInfo);
+ method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public void setLegacyLockdownVpnEnabled(boolean);
+ method public static void setPrivateDnsMode(@NonNull android.content.Context, @NonNull String);
method @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public void setProfileNetworkPreference(@NonNull android.os.UserHandle, int, @Nullable java.util.concurrent.Executor, @Nullable Runnable);
+ method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public void setRequireVpnForUids(boolean, @NonNull java.util.Collection<android.util.Range<java.lang.Integer>>);
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);
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void startCaptivePortalApp(@NonNull android.net.Network);
method public void systemReady();
+ field public static final int BLOCKED_METERED_REASON_ADMIN_DISABLED = 262144; // 0x40000
+ field public static final int BLOCKED_METERED_REASON_DATA_SAVER = 65536; // 0x10000
+ field public static final int BLOCKED_METERED_REASON_MASK = -65536; // 0xffff0000
+ field public static final int BLOCKED_METERED_REASON_USER_RESTRICTED = 131072; // 0x20000
+ field public static final int BLOCKED_REASON_APP_STANDBY = 4; // 0x4
+ field public static final int BLOCKED_REASON_BATTERY_SAVER = 1; // 0x1
+ field public static final int BLOCKED_REASON_DOZE = 2; // 0x2
+ field public static final int BLOCKED_REASON_LOCKDOWN_VPN = 16; // 0x10
+ field public static final int BLOCKED_REASON_NONE = 0; // 0x0
+ field public static final int BLOCKED_REASON_RESTRICTED_MODE = 8; // 0x8
field public static final String PRIVATE_DNS_MODE_OFF = "off";
field public static final String PRIVATE_DNS_MODE_OPPORTUNISTIC = "opportunistic";
field public static final String PRIVATE_DNS_MODE_PROVIDER_HOSTNAME = "hostname";
@@ -28,17 +43,70 @@ package android.net {
field public static final int PROFILE_NETWORK_PREFERENCE_ENTERPRISE = 1; // 0x1
}
+ public static class ConnectivityManager.NetworkCallback {
+ method public void onBlockedStatusChanged(@NonNull android.net.Network, int);
+ }
+
+ public class ConnectivitySettingsManager {
+ method public static void clearGlobalProxy(@NonNull android.content.Context);
+ method @Nullable public static String getCaptivePortalHttpUrl(@NonNull android.content.Context);
+ method public static int getCaptivePortalMode(@NonNull android.content.Context, int);
+ method @NonNull public static java.time.Duration getConnectivityKeepPendingIntentDuration(@NonNull android.content.Context, @NonNull java.time.Duration);
+ method @NonNull public static android.util.Range<java.lang.Integer> getDnsResolverSampleRanges(@NonNull android.content.Context);
+ method @NonNull public static java.time.Duration getDnsResolverSampleValidityDuration(@NonNull android.content.Context, @NonNull java.time.Duration);
+ method public static int getDnsResolverSuccessThresholdPercent(@NonNull android.content.Context, int);
+ method @Nullable public static android.net.ProxyInfo getGlobalProxy(@NonNull android.content.Context);
+ method @NonNull public static java.time.Duration getMobileDataActivityTimeout(@NonNull android.content.Context, @NonNull java.time.Duration);
+ method public static boolean getMobileDataAlwaysOn(@NonNull android.content.Context, boolean);
+ method @Nullable public static String getMobileDataPreferredApps(@NonNull android.content.Context);
+ method public static int getNetworkAvoidBadWifi(@NonNull android.content.Context);
+ method @Nullable public static String getNetworkMeteredMultipathPreference(@NonNull android.content.Context);
+ method public static int getNetworkSwitchNotificationMaximumDailyCount(@NonNull android.content.Context, int);
+ method @NonNull public static java.time.Duration getNetworkSwitchNotificationRateDuration(@NonNull android.content.Context, @NonNull java.time.Duration);
+ method @NonNull public static String getPrivateDnsDefaultMode(@NonNull android.content.Context);
+ method @Nullable public static String getPrivateDnsHostname(@NonNull android.content.Context);
+ method public static boolean getWifiAlwaysRequested(@NonNull android.content.Context, boolean);
+ method @NonNull public static java.time.Duration getWifiDataActivityTimeout(@NonNull android.content.Context, @NonNull java.time.Duration);
+ method public static void setCaptivePortalHttpUrl(@NonNull android.content.Context, @Nullable String);
+ method public static void setCaptivePortalMode(@NonNull android.content.Context, int);
+ method public static void setConnectivityKeepPendingIntentDuration(@NonNull android.content.Context, @NonNull java.time.Duration);
+ method public static void setDnsResolverSampleRanges(@NonNull android.content.Context, @NonNull android.util.Range<java.lang.Integer>);
+ method public static void setDnsResolverSampleValidityDuration(@NonNull android.content.Context, @NonNull java.time.Duration);
+ method public static void setDnsResolverSuccessThresholdPercent(@NonNull android.content.Context, @IntRange(from=0, to=100) int);
+ method public static void setGlobalProxy(@NonNull android.content.Context, @NonNull android.net.ProxyInfo);
+ method public static void setMobileDataActivityTimeout(@NonNull android.content.Context, @NonNull java.time.Duration);
+ method public static void setMobileDataAlwaysOn(@NonNull android.content.Context, boolean);
+ method public static void setMobileDataPreferredApps(@NonNull android.content.Context, @Nullable String);
+ method public static void setNetworkAvoidBadWifi(@NonNull android.content.Context, int);
+ method public static void setNetworkMeteredMultipathPreference(@NonNull android.content.Context, @NonNull String);
+ method public static void setNetworkSwitchNotificationMaximumDailyCount(@NonNull android.content.Context, @IntRange(from=0) int);
+ method public static void setNetworkSwitchNotificationRateDuration(@NonNull android.content.Context, @NonNull java.time.Duration);
+ method public static void setPrivateDnsDefaultMode(@NonNull android.content.Context, @NonNull String);
+ method public static void setPrivateDnsHostname(@NonNull android.content.Context, @Nullable String);
+ method public static void setWifiAlwaysRequested(@NonNull android.content.Context, boolean);
+ method public static void setWifiDataActivityTimeout(@NonNull android.content.Context, @NonNull java.time.Duration);
+ field public static final int CAPTIVE_PORTAL_MODE_AVOID = 2; // 0x2
+ field public static final int CAPTIVE_PORTAL_MODE_IGNORE = 0; // 0x0
+ field public static final int CAPTIVE_PORTAL_MODE_PROMPT = 1; // 0x1
+ field public static final int NETWORK_AVOID_BAD_WIFI_AVOID = 2; // 0x2
+ field public static final int NETWORK_AVOID_BAD_WIFI_IGNORE = 0; // 0x0
+ field public static final int NETWORK_AVOID_BAD_WIFI_PROMPT = 1; // 0x1
+ }
+
public final class NetworkAgentConfig implements android.os.Parcelable {
method @Nullable public String getSubscriberId();
+ method public boolean isBypassableVpn();
}
public static final class NetworkAgentConfig.Builder {
+ method @NonNull public android.net.NetworkAgentConfig.Builder setBypassableVpn(boolean);
method @NonNull public android.net.NetworkAgentConfig.Builder setSubscriberId(@Nullable String);
}
public final class NetworkCapabilities implements android.os.Parcelable {
ctor public NetworkCapabilities(@Nullable android.net.NetworkCapabilities, long);
method @Nullable public java.util.Set<android.util.Range<java.lang.Integer>> getUids();
+ method public boolean hasUnwantedCapability(int);
field public static final long REDACT_ALL = -1L; // 0xffffffffffffffffL
field public static final long REDACT_FOR_ACCESS_FINE_LOCATION = 1L; // 0x1L
field public static final long REDACT_FOR_LOCAL_MAC_ADDRESS = 2L; // 0x2L
@@ -51,7 +119,14 @@ package android.net {
method @NonNull public android.net.NetworkCapabilities.Builder setUids(@Nullable java.util.Set<android.util.Range<java.lang.Integer>>);
}
+ public class NetworkRequest implements android.os.Parcelable {
+ method @NonNull public int[] getUnwantedCapabilities();
+ method public boolean hasUnwantedCapability(int);
+ }
+
public static class NetworkRequest.Builder {
+ method @NonNull public android.net.NetworkRequest.Builder addUnwantedCapability(int);
+ method @NonNull public android.net.NetworkRequest.Builder removeUnwantedCapability(int);
method @NonNull public android.net.NetworkRequest.Builder setUids(@Nullable java.util.Set<android.util.Range<java.lang.Integer>>);
}
diff --git a/packages/Connectivity/framework/api/system-current.txt b/packages/Connectivity/framework/api/system-current.txt
index 703fca408f7a..95ad694293f2 100644
--- a/packages/Connectivity/framework/api/system-current.txt
+++ b/packages/Connectivity/framework/api/system-current.txt
@@ -212,10 +212,14 @@ package android.net {
public abstract class NetworkAgent {
ctor public NetworkAgent(@NonNull android.content.Context, @NonNull android.os.Looper, @NonNull String, @NonNull android.net.NetworkCapabilities, @NonNull android.net.LinkProperties, int, @NonNull android.net.NetworkAgentConfig, @Nullable android.net.NetworkProvider);
+ ctor public NetworkAgent(@NonNull android.content.Context, @NonNull android.os.Looper, @NonNull String, @NonNull android.net.NetworkCapabilities, @NonNull android.net.LinkProperties, @NonNull android.net.NetworkScore, @NonNull android.net.NetworkAgentConfig, @Nullable android.net.NetworkProvider);
method @Nullable public android.net.Network getNetwork();
method public void markConnected();
method public void onAddKeepalivePacketFilter(int, @NonNull android.net.KeepalivePacketData);
method public void onAutomaticReconnectDisabled();
+ method public void onBandwidthUpdateRequested();
+ method public void onNetworkCreated();
+ method public void onNetworkDestroyed();
method public void onNetworkUnwanted();
method public void onQosCallbackRegistered(int, @NonNull android.net.QosFilter);
method public void onQosCallbackUnregistered(int);
@@ -230,9 +234,11 @@ package android.net {
method public final void sendNetworkCapabilities(@NonNull android.net.NetworkCapabilities);
method public final void sendNetworkScore(@IntRange(from=0, to=99) int);
method public final void sendQosCallbackError(int, int);
- method public final void sendQosSessionAvailable(int, int, @NonNull android.telephony.data.EpsBearerQosSessionAttributes);
- method public final void sendQosSessionLost(int, int);
+ method public final void sendQosSessionAvailable(int, int, @NonNull android.net.QosSessionAttributes);
+ method public final void sendQosSessionLost(int, int, int);
method public final void sendSocketKeepaliveEvent(int, int);
+ method @Deprecated public void setLegacySubtype(int, @NonNull String);
+ method public void setTeardownDelayMs(@IntRange(from=0, to=0x1388) int);
method public final void setUnderlyingNetworks(@Nullable java.util.List<android.net.Network>);
method public void unregister();
field public static final int VALIDATION_STATUS_NOT_VALID = 2; // 0x2
@@ -253,7 +259,12 @@ package android.net {
public static final class NetworkAgentConfig.Builder {
ctor public NetworkAgentConfig.Builder();
method @NonNull public android.net.NetworkAgentConfig build();
+ method @NonNull public android.net.NetworkAgentConfig.Builder disableNat64Detection();
+ method @NonNull public android.net.NetworkAgentConfig.Builder disableProvisioningNotification();
method @NonNull public android.net.NetworkAgentConfig.Builder setExplicitlySelected(boolean);
+ method @NonNull public android.net.NetworkAgentConfig.Builder setLegacyExtraInfo(@NonNull String);
+ method @NonNull public android.net.NetworkAgentConfig.Builder setLegacySubType(int);
+ method @NonNull public android.net.NetworkAgentConfig.Builder setLegacySubTypeName(@NonNull String);
method @NonNull public android.net.NetworkAgentConfig.Builder setLegacyType(int);
method @NonNull public android.net.NetworkAgentConfig.Builder setLegacyTypeName(@NonNull String);
method @NonNull public android.net.NetworkAgentConfig.Builder setPartialConnectivityAcceptable(boolean);
@@ -316,6 +327,19 @@ package android.net {
method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP) public android.net.NetworkRequest.Builder setSignalStrength(int);
}
+ public final class NetworkScore implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getLegacyInt();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkScore> CREATOR;
+ }
+
+ public static final class NetworkScore.Builder {
+ ctor public NetworkScore.Builder();
+ method @NonNull public android.net.NetworkScore build();
+ method @NonNull public android.net.NetworkScore.Builder setLegacyInt(int);
+ }
+
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();
@@ -363,6 +387,7 @@ package android.net {
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.net.QosSession> CREATOR;
field public static final int TYPE_EPS_BEARER = 1; // 0x1
+ field public static final int TYPE_NR_BEARER = 2; // 0x2
}
public interface QosSessionAttributes {
@@ -388,6 +413,7 @@ package android.net {
}
public abstract class SocketKeepalive implements java.lang.AutoCloseable {
+ field public static final int ERROR_NO_SUCH_SLOT = -33; // 0xffffffdf
field public static final int SUCCESS = 0; // 0x0
}
diff --git a/packages/Connectivity/framework/src/android/net/ConnectivityManager.java b/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
index 30ccb206db3d..c6f4e0b354c4 100644
--- a/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
+++ b/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
@@ -38,7 +38,9 @@ import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.app.PendingIntent;
+import android.app.admin.DevicePolicyManager;
import android.compat.annotation.UnsupportedAppUsage;
+import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
@@ -826,6 +828,114 @@ public class ConnectivityManager {
})
public @interface PrivateDnsMode {}
+ /**
+ * Flag to indicate that an app is not subject to any restrictions that could result in its
+ * network access blocked.
+ *
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public static final int BLOCKED_REASON_NONE = 0;
+
+ /**
+ * Flag to indicate that an app is subject to Battery saver restrictions that would
+ * result in its network access being blocked.
+ *
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public static final int BLOCKED_REASON_BATTERY_SAVER = 1 << 0;
+
+ /**
+ * Flag to indicate that an app is subject to Doze restrictions that would
+ * result in its network access being blocked.
+ *
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public static final int BLOCKED_REASON_DOZE = 1 << 1;
+
+ /**
+ * Flag to indicate that an app is subject to App Standby restrictions that would
+ * result in its network access being blocked.
+ *
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public static final int BLOCKED_REASON_APP_STANDBY = 1 << 2;
+
+ /**
+ * Flag to indicate that an app is subject to Restricted mode restrictions that would
+ * result in its network access being blocked.
+ *
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public static final int BLOCKED_REASON_RESTRICTED_MODE = 1 << 3;
+
+ /**
+ * Flag to indicate that an app is blocked because it is subject to an always-on VPN but the VPN
+ * is not currently connected.
+ *
+ * @see DevicePolicyManager#setAlwaysOnVpnPackage(ComponentName, String, boolean)
+ *
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public static final int BLOCKED_REASON_LOCKDOWN_VPN = 1 << 4;
+
+ /**
+ * Flag to indicate that an app is subject to Data saver restrictions that would
+ * result in its metered network access being blocked.
+ *
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public static final int BLOCKED_METERED_REASON_DATA_SAVER = 1 << 16;
+
+ /**
+ * Flag to indicate that an app is subject to user restrictions that would
+ * result in its metered network access being blocked.
+ *
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public static final int BLOCKED_METERED_REASON_USER_RESTRICTED = 1 << 17;
+
+ /**
+ * Flag to indicate that an app is subject to Device admin restrictions that would
+ * result in its metered network access being blocked.
+ *
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public static final int BLOCKED_METERED_REASON_ADMIN_DISABLED = 1 << 18;
+
+ /**
+ * @hide
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag = true, prefix = {"BLOCKED_"}, value = {
+ BLOCKED_REASON_NONE,
+ BLOCKED_REASON_BATTERY_SAVER,
+ BLOCKED_REASON_DOZE,
+ BLOCKED_REASON_APP_STANDBY,
+ BLOCKED_REASON_RESTRICTED_MODE,
+ BLOCKED_REASON_LOCKDOWN_VPN,
+ BLOCKED_METERED_REASON_DATA_SAVER,
+ BLOCKED_METERED_REASON_USER_RESTRICTED,
+ BLOCKED_METERED_REASON_ADMIN_DISABLED,
+ })
+ public @interface BlockedReason {}
+
+ /**
+ * Set of blocked reasons that are only applicable on metered networks.
+ *
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public static final int BLOCKED_METERED_REASON_MASK = 0xffff0000;
+
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562)
private final IConnectivityManager mService;
@@ -1080,8 +1190,7 @@ public class ConnectivityManager {
*
* @return a {@link Network} object for the current default network for the
* given UID or {@code null} if no default network is currently active
- *
- * @hide
+ * TODO: b/183465229 Cleanup getActiveNetworkForUid once b/165835257 is fixed
*/
@RequiresPermission(android.Manifest.permission.NETWORK_STACK)
@Nullable
@@ -1122,12 +1231,13 @@ public class ConnectivityManager {
* @param ranges the UID ranges to restrict
* @param requireVpn whether the specified UID ranges must use a VPN
*
- * TODO: expose as @SystemApi.
* @hide
*/
@RequiresPermission(anyOf = {
NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
- android.Manifest.permission.NETWORK_STACK})
+ android.Manifest.permission.NETWORK_STACK,
+ android.Manifest.permission.NETWORK_SETTINGS})
+ @SystemApi(client = MODULE_LIBRARIES)
public void setRequireVpnForUids(boolean requireVpn,
@NonNull Collection<Range<Integer>> ranges) {
Objects.requireNonNull(ranges);
@@ -1171,13 +1281,13 @@ public class ConnectivityManager {
*
* @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_STACK,
android.Manifest.permission.NETWORK_SETTINGS})
+ @SystemApi(client = MODULE_LIBRARIES)
public void setLegacyLockdownVpnEnabled(boolean enabled) {
try {
mService.setLegacyLockdownVpnEnabled(enabled);
@@ -2124,6 +2234,7 @@ public class ConnectivityManager {
*/
@Deprecated
@UnsupportedAppUsage
+ @SystemApi(client = MODULE_LIBRARIES)
public boolean requestRouteToHostAddress(int networkType, InetAddress hostAddress) {
checkLegacyRoutingApiAccess();
try {
@@ -3352,12 +3463,30 @@ public class ConnectivityManager {
* @param blocked Whether access to the {@link Network} is blocked due to system policy.
* @hide
*/
- public void onAvailable(@NonNull Network network,
+ public final void onAvailable(@NonNull Network network,
@NonNull NetworkCapabilities networkCapabilities,
- @NonNull LinkProperties linkProperties, boolean blocked) {
+ @NonNull LinkProperties linkProperties, @BlockedReason int blocked) {
// Internally only this method is called when a new network is available, and
// it calls the callback in the same way and order that older versions used
// to call so as not to change the behavior.
+ onAvailable(network, networkCapabilities, linkProperties, blocked != 0);
+ onBlockedStatusChanged(network, blocked);
+ }
+
+ /**
+ * Legacy variant of onAvailable that takes a boolean blocked reason.
+ *
+ * This method has never been public API, but it's not final, so there may be apps that
+ * implemented it and rely on it being called. Do our best not to break them.
+ * Note: such apps will also get a second call to onBlockedStatusChanged immediately after
+ * this method is called. There does not seem to be a way to avoid this.
+ * TODO: add a compat check to move apps off this method, and eventually stop calling it.
+ *
+ * @hide
+ */
+ public void onAvailable(@NonNull Network network,
+ @NonNull NetworkCapabilities networkCapabilities,
+ @NonNull LinkProperties linkProperties, boolean blocked) {
onAvailable(network);
if (!networkCapabilities.hasCapability(
NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED)) {
@@ -3365,7 +3494,7 @@ public class ConnectivityManager {
}
onCapabilitiesChanged(network, networkCapabilities);
onLinkPropertiesChanged(network, linkProperties);
- onBlockedStatusChanged(network, blocked);
+ // No call to onBlockedStatusChanged here. That is done by the caller.
}
/**
@@ -3529,6 +3658,27 @@ public class ConnectivityManager {
*/
public void onBlockedStatusChanged(@NonNull Network network, boolean blocked) {}
+ /**
+ * Called when access to the specified network is blocked or unblocked, or the reason for
+ * access being blocked changes.
+ *
+ * If a NetworkCallback object implements this method,
+ * {@link #onBlockedStatusChanged(Network, boolean)} will not be called.
+ *
+ * <p>Do NOT call {@link #getNetworkCapabilities(Network)} or
+ * {@link #getLinkProperties(Network)} or other synchronous ConnectivityManager methods in
+ * this callback as this is prone to race conditions : calling these methods while in a
+ * callback may return an outdated or even a null object.
+ *
+ * @param network The {@link Network} whose blocked status has changed.
+ * @param blocked The blocked status of this {@link Network}.
+ * @hide
+ */
+ @SystemApi(client = MODULE_LIBRARIES)
+ public void onBlockedStatusChanged(@NonNull Network network, @BlockedReason int blocked) {
+ onBlockedStatusChanged(network, blocked != 0);
+ }
+
private NetworkRequest networkRequest;
private final int mFlags;
}
@@ -3643,7 +3793,7 @@ public class ConnectivityManager {
case CALLBACK_AVAILABLE: {
NetworkCapabilities cap = getObject(message, NetworkCapabilities.class);
LinkProperties lp = getObject(message, LinkProperties.class);
- callback.onAvailable(network, cap, lp, message.arg1 != 0);
+ callback.onAvailable(network, cap, lp, message.arg1);
break;
}
case CALLBACK_LOSING: {
@@ -3677,8 +3827,7 @@ public class ConnectivityManager {
break;
}
case CALLBACK_BLK_CHANGED: {
- boolean blocked = message.arg1 != 0;
- callback.onBlockedStatusChanged(network, blocked);
+ callback.onBlockedStatusChanged(network, message.arg1);
}
}
}
@@ -3700,8 +3849,9 @@ public class ConnectivityManager {
private static final HashMap<NetworkRequest, NetworkCallback> sCallbacks = new HashMap<>();
private static CallbackHandler sCallbackHandler;
- private NetworkRequest sendRequestForNetwork(NetworkCapabilities need, NetworkCallback callback,
- int timeoutMs, NetworkRequest.Type reqType, int legacyType, CallbackHandler handler) {
+ private NetworkRequest sendRequestForNetwork(int asUid, NetworkCapabilities need,
+ NetworkCallback callback, int timeoutMs, NetworkRequest.Type reqType, int legacyType,
+ CallbackHandler handler) {
printStackTrace();
checkCallbackNotNull(callback);
if (reqType != TRACK_DEFAULT && reqType != TRACK_SYSTEM_DEFAULT && need == null) {
@@ -3726,8 +3876,8 @@ public class ConnectivityManager {
getAttributionTag());
} else {
request = mService.requestNetwork(
- need, reqType.ordinal(), messenger, timeoutMs, binder, legacyType,
- callbackFlags, callingPackageName, getAttributionTag());
+ asUid, need, reqType.ordinal(), messenger, timeoutMs, binder,
+ legacyType, callbackFlags, callingPackageName, getAttributionTag());
}
if (request != null) {
sCallbacks.put(request, callback);
@@ -3742,6 +3892,12 @@ public class ConnectivityManager {
return request;
}
+ private NetworkRequest sendRequestForNetwork(NetworkCapabilities need, NetworkCallback callback,
+ int timeoutMs, NetworkRequest.Type reqType, int legacyType, CallbackHandler handler) {
+ return sendRequestForNetwork(Process.INVALID_UID, need, callback, timeoutMs, reqType,
+ legacyType, handler);
+ }
+
/**
* Helper function to request a network with a particular legacy type.
*
@@ -4227,8 +4383,40 @@ public class ConnectivityManager {
@RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
public void registerDefaultNetworkCallback(@NonNull NetworkCallback networkCallback,
@NonNull Handler handler) {
+ registerDefaultNetworkCallbackAsUid(Process.INVALID_UID, networkCallback, handler);
+ }
+
+ /**
+ * Registers to receive notifications about changes in the default network for the specified
+ * UID. This may be a physical network or a virtual network, such as a VPN that applies to the
+ * UID. 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
+ * 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 uid the UID for which to track default network changes.
+ * @param networkCallback The {@link NetworkCallback} that the system will call as the
+ * UID'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.
+ * @hide
+ */
+ @SystemApi(client = MODULE_LIBRARIES)
+ @SuppressLint({"ExecutorRegistration", "PairedRegistration"})
+ @RequiresPermission(anyOf = {
+ NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
+ android.Manifest.permission.NETWORK_SETTINGS})
+ public void registerDefaultNetworkCallbackAsUid(int uid,
+ @NonNull NetworkCallback networkCallback, @NonNull Handler handler) {
CallbackHandler cbHandler = new CallbackHandler(handler);
- sendRequestForNetwork(null /* NetworkCapabilities need */, networkCallback, 0,
+ sendRequestForNetwork(uid, null /* need */, networkCallback, 0 /* timeoutMs */,
TRACK_DEFAULT, TYPE_NONE, cbHandler);
}
@@ -5242,4 +5430,23 @@ public class ConnectivityManager {
if (TextUtils.isEmpty(mode)) mode = PRIVATE_DNS_MODE_OPPORTUNISTIC;
return mode;
}
+
+ /**
+ * Set private DNS mode to settings.
+ *
+ * @param context The {@link Context} to set the private DNS mode.
+ * @param mode The private dns mode. This should be one of the PRIVATE_DNS_MODE_* constants.
+ *
+ * @hide
+ */
+ @SystemApi(client = MODULE_LIBRARIES)
+ public static void setPrivateDnsMode(@NonNull Context context,
+ @NonNull @PrivateDnsMode String mode) {
+ if (!(mode == PRIVATE_DNS_MODE_OFF
+ || mode == PRIVATE_DNS_MODE_OPPORTUNISTIC
+ || mode == PRIVATE_DNS_MODE_PROVIDER_HOSTNAME)) {
+ throw new IllegalArgumentException("Invalid private dns mode");
+ }
+ Settings.Global.putString(context.getContentResolver(), PRIVATE_DNS_MODE, mode);
+ }
}
diff --git a/packages/Connectivity/framework/src/android/net/ConnectivitySettingsManager.java b/packages/Connectivity/framework/src/android/net/ConnectivitySettingsManager.java
index bbd83931ee0d..9a00055e0079 100644
--- a/packages/Connectivity/framework/src/android/net/ConnectivitySettingsManager.java
+++ b/packages/Connectivity/framework/src/android/net/ConnectivitySettingsManager.java
@@ -16,16 +16,38 @@
package android.net;
+import static android.net.ConnectivityManager.MULTIPATH_PREFERENCE_HANDOVER;
+import static android.net.ConnectivityManager.MULTIPATH_PREFERENCE_PERFORMANCE;
+import static android.net.ConnectivityManager.MULTIPATH_PREFERENCE_RELIABILITY;
+import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OFF;
+import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC;
+import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME;
+
import android.annotation.IntDef;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.content.Context;
+import android.net.ConnectivityManager.MultipathPreference;
+import android.net.ConnectivityManager.PrivateDnsMode;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.Range;
+
+import com.android.net.module.util.ProxyUtils;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.time.Duration;
+import java.util.List;
/**
* A manager class for connectivity module settings.
*
* @hide
*/
+@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public class ConnectivitySettingsManager {
private ConnectivitySettingsManager() {}
@@ -45,12 +67,16 @@ public class ConnectivitySettingsManager {
* Network activity refers to transmitting or receiving data on the network interfaces.
*
* Tracking is disabled if set to zero or negative value.
+ *
+ * @hide
*/
public static final String DATA_ACTIVITY_TIMEOUT_MOBILE = "data_activity_timeout_mobile";
/**
* Timeout to tracking Wifi data activity. Same as {@code DATA_ACTIVITY_TIMEOUT_MOBILE}
* but for Wifi network.
+ *
+ * @hide
*/
public static final String DATA_ACTIVITY_TIMEOUT_WIFI = "data_activity_timeout_wifi";
@@ -58,12 +84,16 @@ public class ConnectivitySettingsManager {
/**
* Sample validity in seconds to configure for the system DNS resolver.
+ *
+ * @hide
*/
public static final String DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS =
"dns_resolver_sample_validity_seconds";
/**
* Success threshold in percent for use with the system DNS resolver.
+ *
+ * @hide
*/
public static final String DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT =
"dns_resolver_success_threshold_percent";
@@ -71,24 +101,35 @@ public class ConnectivitySettingsManager {
/**
* Minimum number of samples needed for statistics to be considered meaningful in the
* system DNS resolver.
+ *
+ * @hide
*/
public static final String DNS_RESOLVER_MIN_SAMPLES = "dns_resolver_min_samples";
/**
* Maximum number taken into account for statistics purposes in the system DNS resolver.
+ *
+ * @hide
*/
public static final String DNS_RESOLVER_MAX_SAMPLES = "dns_resolver_max_samples";
+ private static final int DNS_RESOLVER_DEFAULT_MIN_SAMPLES = 8;
+ private static final int DNS_RESOLVER_DEFAULT_MAX_SAMPLES = 64;
+
/** Network switch notification settings */
/**
* The maximum number of notifications shown in 24 hours when switching networks.
+ *
+ * @hide
*/
public static final String NETWORK_SWITCH_NOTIFICATION_DAILY_LIMIT =
"network_switch_notification_daily_limit";
/**
* The minimum time in milliseconds between notifications when switching networks.
+ *
+ * @hide
*/
public static final String NETWORK_SWITCH_NOTIFICATION_RATE_LIMIT_MILLIS =
"network_switch_notification_rate_limit_millis";
@@ -98,14 +139,18 @@ public class ConnectivitySettingsManager {
/**
* The URL used for HTTP captive portal detection upon a new connection.
* A 204 response code from the server is used for validation.
+ *
+ * @hide
*/
public static final String CAPTIVE_PORTAL_HTTP_URL = "captive_portal_http_url";
/**
* What to do when connecting a network that presents a captive portal.
- * Must be one of the CAPTIVE_PORTAL_MODE_* constants above.
+ * Must be one of the CAPTIVE_PORTAL_MODE_* constants below.
*
* The default for this setting is CAPTIVE_PORTAL_MODE_PROMPT.
+ *
+ * @hide
*/
public static final String CAPTIVE_PORTAL_MODE = "captive_portal_mode";
@@ -139,11 +184,15 @@ public class ConnectivitySettingsManager {
/**
* Host name for global http proxy. Set via ConnectivityManager.
+ *
+ * @hide
*/
public static final String GLOBAL_HTTP_PROXY_HOST = "global_http_proxy_host";
/**
* Integer host port for global http proxy. Set via ConnectivityManager.
+ *
+ * @hide
*/
public static final String GLOBAL_HTTP_PROXY_PORT = "global_http_proxy_port";
@@ -153,12 +202,16 @@ public class ConnectivitySettingsManager {
* Domains should be listed in a comma- separated list. Example of
* acceptable formats: ".domain1.com,my.domain2.com" Use
* ConnectivityManager to set/get.
+ *
+ * @hide
*/
public static final String GLOBAL_HTTP_PROXY_EXCLUSION_LIST =
"global_http_proxy_exclusion_list";
/**
* The location PAC File for the proxy.
+ *
+ * @hide
*/
public static final String GLOBAL_HTTP_PROXY_PAC = "global_proxy_pac_url";
@@ -171,11 +224,15 @@ public class ConnectivitySettingsManager {
* a specific provider. It may be used to store the provider name even when the
* mode changes so that temporarily disabling and re-enabling the specific
* provider mode does not necessitate retyping the provider hostname.
+ *
+ * @hide
*/
public static final String PRIVATE_DNS_MODE = "private_dns_mode";
/**
* The specific Private DNS provider name.
+ *
+ * @hide
*/
public static final String PRIVATE_DNS_SPECIFIER = "private_dns_specifier";
@@ -185,6 +242,8 @@ public class ConnectivitySettingsManager {
* all of which require explicit user action to enable/configure. See also b/79719289.
*
* Value is a string, suitable for assignment to PRIVATE_DNS_MODE above.
+ *
+ * @hide
*/
public static final String PRIVATE_DNS_DEFAULT_MODE = "private_dns_default_mode";
@@ -194,6 +253,8 @@ public class ConnectivitySettingsManager {
* The number of milliseconds to hold on to a PendingIntent based request. This delay gives
* the receivers of the PendingIntent an opportunity to make a new network request before
* the Network satisfying the request is potentially removed.
+ *
+ * @hide
*/
public static final String CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS =
"connectivity_release_pending_intent_delay_ms";
@@ -205,6 +266,8 @@ public class ConnectivitySettingsManager {
* See ConnectivityService for more info.
*
* (0 = disabled, 1 = enabled)
+ *
+ * @hide
*/
public static final String MOBILE_DATA_ALWAYS_ON = "mobile_data_always_on";
@@ -217,6 +280,8 @@ public class ConnectivitySettingsManager {
* See ConnectivityService for more info.
*
* (0 = disabled, 1 = enabled)
+ *
+ * @hide
*/
public static final String WIFI_ALWAYS_REQUESTED = "wifi_always_requested";
@@ -228,14 +293,637 @@ public class ConnectivitySettingsManager {
* 0: Don't avoid bad wifi, don't prompt the user. Get stuck on bad wifi like it's 2013.
* null: Ask the user whether to switch away from bad wifi.
* 1: Avoid bad wifi.
+ *
+ * @hide
*/
public static final String NETWORK_AVOID_BAD_WIFI = "network_avoid_bad_wifi";
/**
+ * Don't avoid bad wifi, don't prompt the user. Get stuck on bad wifi like it's 2013.
+ */
+ public static final int NETWORK_AVOID_BAD_WIFI_IGNORE = 0;
+
+ /**
+ * Ask the user whether to switch away from bad wifi.
+ */
+ public static final int NETWORK_AVOID_BAD_WIFI_PROMPT = 1;
+
+ /**
+ * Avoid bad wifi.
+ */
+ public static final int NETWORK_AVOID_BAD_WIFI_AVOID = 2;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(value = {
+ NETWORK_AVOID_BAD_WIFI_IGNORE,
+ NETWORK_AVOID_BAD_WIFI_PROMPT,
+ NETWORK_AVOID_BAD_WIFI_AVOID,
+ })
+ public @interface NetworkAvoidBadWifi {}
+
+ /**
* User setting for ConnectivityManager.getMeteredMultipathPreference(). This value may be
* overridden by the system based on device or application state. If null, the value
* specified by config_networkMeteredMultipathPreference is used.
+ *
+ * @hide
*/
public static final String NETWORK_METERED_MULTIPATH_PREFERENCE =
"network_metered_multipath_preference";
+
+ /**
+ * A list of apps that should go on cellular networks in preference even when higher-priority
+ * networks are connected.
+ *
+ * @hide
+ */
+ public static final String MOBILE_DATA_PREFERRED_APPS = "mobile_data_preferred_apps";
+
+ /**
+ * Get mobile data activity timeout from {@link Settings}.
+ *
+ * @param context The {@link Context} to query the setting.
+ * @param def The default timeout if no setting value.
+ * @return The {@link Duration} of timeout to track mobile data activity.
+ */
+ @NonNull
+ public static Duration getMobileDataActivityTimeout(@NonNull Context context,
+ @NonNull Duration def) {
+ final int timeout = Settings.Global.getInt(
+ context.getContentResolver(), DATA_ACTIVITY_TIMEOUT_MOBILE, (int) def.getSeconds());
+ return Duration.ofSeconds(timeout);
+ }
+
+ /**
+ * Set mobile data activity timeout to {@link Settings}.
+ * Tracking is disabled if set to zero or negative value.
+ *
+ * Note: Only use the number of seconds in this duration, lower second(nanoseconds) will be
+ * ignored.
+ *
+ * @param context The {@link Context} to set the setting.
+ * @param timeout The mobile data activity timeout.
+ */
+ public static void setMobileDataActivityTimeout(@NonNull Context context,
+ @NonNull Duration timeout) {
+ Settings.Global.putInt(context.getContentResolver(), DATA_ACTIVITY_TIMEOUT_MOBILE,
+ (int) timeout.getSeconds());
+ }
+
+ /**
+ * Get wifi data activity timeout from {@link Settings}.
+ *
+ * @param context The {@link Context} to query the setting.
+ * @param def The default timeout if no setting value.
+ * @return The {@link Duration} of timeout to track wifi data activity.
+ */
+ @NonNull
+ public static Duration getWifiDataActivityTimeout(@NonNull Context context,
+ @NonNull Duration def) {
+ final int timeout = Settings.Global.getInt(
+ context.getContentResolver(), DATA_ACTIVITY_TIMEOUT_WIFI, (int) def.getSeconds());
+ return Duration.ofSeconds(timeout);
+ }
+
+ /**
+ * Set wifi data activity timeout to {@link Settings}.
+ * Tracking is disabled if set to zero or negative value.
+ *
+ * Note: Only use the number of seconds in this duration, lower second(nanoseconds) will be
+ * ignored.
+ *
+ * @param context The {@link Context} to set the setting.
+ * @param timeout The wifi data activity timeout.
+ */
+ public static void setWifiDataActivityTimeout(@NonNull Context context,
+ @NonNull Duration timeout) {
+ Settings.Global.putInt(context.getContentResolver(), DATA_ACTIVITY_TIMEOUT_WIFI,
+ (int) timeout.getSeconds());
+ }
+
+ /**
+ * Get dns resolver sample validity duration from {@link Settings}.
+ *
+ * @param context The {@link Context} to query the setting.
+ * @param def The default duration if no setting value.
+ * @return The {@link Duration} of sample validity duration to configure for the system DNS
+ * resolver.
+ */
+ @NonNull
+ public static Duration getDnsResolverSampleValidityDuration(@NonNull Context context,
+ @NonNull Duration def) {
+ final int duration = Settings.Global.getInt(context.getContentResolver(),
+ DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS, (int) def.getSeconds());
+ return Duration.ofSeconds(duration);
+ }
+
+ /**
+ * Set dns resolver sample validity duration to {@link Settings}. The duration must be a
+ * positive number of seconds.
+ *
+ * @param context The {@link Context} to set the setting.
+ * @param duration The sample validity duration.
+ */
+ public static void setDnsResolverSampleValidityDuration(@NonNull Context context,
+ @NonNull Duration duration) {
+ final int time = (int) duration.getSeconds();
+ if (time <= 0) {
+ throw new IllegalArgumentException("Invalid duration");
+ }
+ Settings.Global.putInt(
+ context.getContentResolver(), DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS, time);
+ }
+
+ /**
+ * Get dns resolver success threshold percent from {@link Settings}.
+ *
+ * @param context The {@link Context} to query the setting.
+ * @param def The default value if no setting value.
+ * @return The success threshold in percent for use with the system DNS resolver.
+ */
+ public static int getDnsResolverSuccessThresholdPercent(@NonNull Context context, int def) {
+ return Settings.Global.getInt(
+ context.getContentResolver(), DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT, def);
+ }
+
+ /**
+ * Set dns resolver success threshold percent to {@link Settings}. The threshold percent must
+ * be 0~100.
+ *
+ * @param context The {@link Context} to set the setting.
+ * @param percent The success threshold percent.
+ */
+ public static void setDnsResolverSuccessThresholdPercent(@NonNull Context context,
+ @IntRange(from = 0, to = 100) int percent) {
+ if (percent < 0 || percent > 100) {
+ throw new IllegalArgumentException("Percent must be 0~100");
+ }
+ Settings.Global.putInt(
+ context.getContentResolver(), DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT, percent);
+ }
+
+ /**
+ * Get dns resolver samples range from {@link Settings}.
+ *
+ * @param context The {@link Context} to query the setting.
+ * @return The {@link Range<Integer>} of samples needed for statistics to be considered
+ * meaningful in the system DNS resolver.
+ */
+ @NonNull
+ public static Range<Integer> getDnsResolverSampleRanges(@NonNull Context context) {
+ final int minSamples = Settings.Global.getInt(context.getContentResolver(),
+ DNS_RESOLVER_MIN_SAMPLES, DNS_RESOLVER_DEFAULT_MIN_SAMPLES);
+ final int maxSamples = Settings.Global.getInt(context.getContentResolver(),
+ DNS_RESOLVER_MAX_SAMPLES, DNS_RESOLVER_DEFAULT_MAX_SAMPLES);
+ return new Range<>(minSamples, maxSamples);
+ }
+
+ /**
+ * Set dns resolver samples range to {@link Settings}.
+ *
+ * @param context The {@link Context} to set the setting.
+ * @param range The samples range. The minimum number should be more than 0 and the maximum
+ * number should be less that 64.
+ */
+ public static void setDnsResolverSampleRanges(@NonNull Context context,
+ @NonNull Range<Integer> range) {
+ if (range.getLower() < 0 || range.getUpper() > 64) {
+ throw new IllegalArgumentException("Argument must be 0~64");
+ }
+ Settings.Global.putInt(
+ context.getContentResolver(), DNS_RESOLVER_MIN_SAMPLES, range.getLower());
+ Settings.Global.putInt(
+ context.getContentResolver(), DNS_RESOLVER_MAX_SAMPLES, range.getUpper());
+ }
+
+ /**
+ * Get maximum count (from {@link Settings}) of switching network notifications shown in 24
+ * hours.
+ *
+ * @param context The {@link Context} to query the setting.
+ * @param def The default value if no setting value.
+ * @return The maximum count of notifications shown in 24 hours when switching networks.
+ */
+ public static int getNetworkSwitchNotificationMaximumDailyCount(@NonNull Context context,
+ int def) {
+ return Settings.Global.getInt(
+ context.getContentResolver(), NETWORK_SWITCH_NOTIFICATION_DAILY_LIMIT, def);
+ }
+
+ /**
+ * Set maximum count (to {@link Settings}) of switching network notifications shown in 24 hours.
+ * The count must be at least 0.
+ *
+ * @param context The {@link Context} to set the setting.
+ * @param count The maximum count of switching network notifications shown in 24 hours.
+ */
+ public static void setNetworkSwitchNotificationMaximumDailyCount(@NonNull Context context,
+ @IntRange(from = 0) int count) {
+ if (count < 0) {
+ throw new IllegalArgumentException("Count must be 0~10.");
+ }
+ Settings.Global.putInt(
+ context.getContentResolver(), NETWORK_SWITCH_NOTIFICATION_DAILY_LIMIT, count);
+ }
+
+ /**
+ * Get minimum duration (from {@link Settings}) between each switching network notifications.
+ *
+ * @param context The {@link Context} to query the setting.
+ * @param def The default time if no setting value.
+ * @return The minimum duration between notifications when switching networks.
+ */
+ @NonNull
+ public static Duration getNetworkSwitchNotificationRateDuration(@NonNull Context context,
+ @NonNull Duration def) {
+ final int duration = Settings.Global.getInt(context.getContentResolver(),
+ NETWORK_SWITCH_NOTIFICATION_RATE_LIMIT_MILLIS, (int) def.toMillis());
+ return Duration.ofMillis(duration);
+ }
+
+ /**
+ * Set minimum duration (to {@link Settings}) between each switching network notifications.
+ *
+ * @param context The {@link Context} to set the setting.
+ * @param duration The minimum duration between notifications when switching networks.
+ */
+ public static void setNetworkSwitchNotificationRateDuration(@NonNull Context context,
+ @NonNull Duration duration) {
+ final int time = (int) duration.toMillis();
+ if (time < 0) {
+ throw new IllegalArgumentException("Invalid duration.");
+ }
+ Settings.Global.putInt(context.getContentResolver(),
+ NETWORK_SWITCH_NOTIFICATION_RATE_LIMIT_MILLIS, time);
+ }
+
+ /**
+ * Get URL (from {@link Settings}) used for HTTP captive portal detection upon a new connection.
+ *
+ * @param context The {@link Context} to query the setting.
+ * @return The URL used for HTTP captive portal detection upon a new connection.
+ */
+ @Nullable
+ public static String getCaptivePortalHttpUrl(@NonNull Context context) {
+ return Settings.Global.getString(context.getContentResolver(), CAPTIVE_PORTAL_HTTP_URL);
+ }
+
+ /**
+ * Set URL (to {@link Settings}) used for HTTP captive portal detection upon a new connection.
+ * This URL should respond with a 204 response to a GET request to indicate no captive portal is
+ * present. And this URL must be HTTP as redirect responses are used to find captive portal
+ * sign-in pages. If the URL set to null or be incorrect, it will result in captive portal
+ * detection failed and lost the connection.
+ *
+ * @param context The {@link Context} to set the setting.
+ * @param url The URL used for HTTP captive portal detection upon a new connection.
+ */
+ public static void setCaptivePortalHttpUrl(@NonNull Context context, @Nullable String url) {
+ Settings.Global.putString(context.getContentResolver(), CAPTIVE_PORTAL_HTTP_URL, url);
+ }
+
+ /**
+ * Get mode (from {@link Settings}) when connecting a network that presents a captive portal.
+ *
+ * @param context The {@link Context} to query the setting.
+ * @param def The default mode if no setting value.
+ * @return The mode when connecting a network that presents a captive portal.
+ */
+ @CaptivePortalMode
+ public static int getCaptivePortalMode(@NonNull Context context,
+ @CaptivePortalMode int def) {
+ return Settings.Global.getInt(context.getContentResolver(), CAPTIVE_PORTAL_MODE, def);
+ }
+
+ /**
+ * Set mode (to {@link Settings}) when connecting a network that presents a captive portal.
+ *
+ * @param context The {@link Context} to set the setting.
+ * @param mode The mode when connecting a network that presents a captive portal.
+ */
+ public static void setCaptivePortalMode(@NonNull Context context, @CaptivePortalMode int mode) {
+ if (!(mode == CAPTIVE_PORTAL_MODE_IGNORE
+ || mode == CAPTIVE_PORTAL_MODE_PROMPT
+ || mode == CAPTIVE_PORTAL_MODE_AVOID)) {
+ throw new IllegalArgumentException("Invalid captive portal mode");
+ }
+ Settings.Global.putInt(context.getContentResolver(), CAPTIVE_PORTAL_MODE, mode);
+ }
+
+ /**
+ * Get the global HTTP proxy applied to the device, or null if none.
+ *
+ * @param context The {@link Context} to query the setting.
+ * @return The {@link ProxyInfo} which build from global http proxy settings.
+ */
+ @Nullable
+ public static ProxyInfo getGlobalProxy(@NonNull Context context) {
+ final String host = Settings.Global.getString(
+ context.getContentResolver(), GLOBAL_HTTP_PROXY_HOST);
+ final int port = Settings.Global.getInt(
+ context.getContentResolver(), GLOBAL_HTTP_PROXY_PORT, 0 /* def */);
+ final String exclusionList = Settings.Global.getString(
+ context.getContentResolver(), GLOBAL_HTTP_PROXY_EXCLUSION_LIST);
+ final String pacFileUrl = Settings.Global.getString(
+ context.getContentResolver(), GLOBAL_HTTP_PROXY_PAC);
+
+ if (TextUtils.isEmpty(host) && TextUtils.isEmpty(pacFileUrl)) {
+ return null; // No global proxy.
+ }
+
+ if (TextUtils.isEmpty(pacFileUrl)) {
+ return ProxyInfo.buildDirectProxy(
+ host, port, ProxyUtils.exclusionStringAsList(exclusionList));
+ } else {
+ return ProxyInfo.buildPacProxy(Uri.parse(pacFileUrl));
+ }
+ }
+
+ /**
+ * Set global http proxy settings from given {@link ProxyInfo}.
+ *
+ * @param context The {@link Context} to set the setting.
+ * @param proxyInfo The {@link ProxyInfo} for global http proxy settings which build from
+ * {@link ProxyInfo#buildPacProxy(Uri)} or
+ * {@link ProxyInfo#buildDirectProxy(String, int, List)}
+ */
+ public static void setGlobalProxy(@NonNull Context context, @NonNull ProxyInfo proxyInfo) {
+ final String host = proxyInfo.getHost();
+ final int port = proxyInfo.getPort();
+ final String exclusionList = proxyInfo.getExclusionListAsString();
+ final String pacFileUrl = proxyInfo.getPacFileUrl().toString();
+
+ if (TextUtils.isEmpty(pacFileUrl)) {
+ Settings.Global.putString(context.getContentResolver(), GLOBAL_HTTP_PROXY_HOST, host);
+ Settings.Global.putInt(context.getContentResolver(), GLOBAL_HTTP_PROXY_PORT, port);
+ Settings.Global.putString(
+ context.getContentResolver(), GLOBAL_HTTP_PROXY_EXCLUSION_LIST, exclusionList);
+ Settings.Global.putString(
+ context.getContentResolver(), GLOBAL_HTTP_PROXY_PAC, "" /* value */);
+ } else {
+ Settings.Global.putString(
+ context.getContentResolver(), GLOBAL_HTTP_PROXY_PAC, pacFileUrl);
+ Settings.Global.putString(
+ context.getContentResolver(), GLOBAL_HTTP_PROXY_HOST, "" /* value */);
+ Settings.Global.putInt(
+ context.getContentResolver(), GLOBAL_HTTP_PROXY_PORT, 0 /* value */);
+ Settings.Global.putString(
+ context.getContentResolver(), GLOBAL_HTTP_PROXY_EXCLUSION_LIST, "" /* value */);
+ }
+ }
+
+ /**
+ * Clear all global http proxy settings.
+ *
+ * @param context The {@link Context} to set the setting.
+ */
+ public static void clearGlobalProxy(@NonNull Context context) {
+ Settings.Global.putString(
+ context.getContentResolver(), GLOBAL_HTTP_PROXY_HOST, "" /* value */);
+ Settings.Global.putInt(
+ context.getContentResolver(), GLOBAL_HTTP_PROXY_PORT, 0 /* value */);
+ Settings.Global.putString(
+ context.getContentResolver(), GLOBAL_HTTP_PROXY_EXCLUSION_LIST, "" /* value */);
+ Settings.Global.putString(
+ context.getContentResolver(), GLOBAL_HTTP_PROXY_PAC, "" /* value */);
+ }
+
+ /**
+ * Get specific private dns provider name from {@link Settings}.
+ *
+ * @param context The {@link Context} to query the setting.
+ * @return The specific private dns provider name, or null if no setting value.
+ */
+ @Nullable
+ public static String getPrivateDnsHostname(@NonNull Context context) {
+ return Settings.Global.getString(context.getContentResolver(), PRIVATE_DNS_SPECIFIER);
+ }
+
+ /**
+ * Set specific private dns provider name to {@link Settings}.
+ *
+ * @param context The {@link Context} to set the setting.
+ * @param specifier The specific private dns provider name.
+ */
+ public static void setPrivateDnsHostname(@NonNull Context context,
+ @Nullable String specifier) {
+ Settings.Global.putString(context.getContentResolver(), PRIVATE_DNS_SPECIFIER, specifier);
+ }
+
+ /**
+ * Get default private dns mode from {@link Settings}.
+ *
+ * @param context The {@link Context} to query the setting.
+ * @return The default private dns mode.
+ */
+ @PrivateDnsMode
+ @NonNull
+ public static String getPrivateDnsDefaultMode(@NonNull Context context) {
+ return Settings.Global.getString(context.getContentResolver(), PRIVATE_DNS_DEFAULT_MODE);
+ }
+
+ /**
+ * Set default private dns mode to {@link Settings}.
+ *
+ * @param context The {@link Context} to set the setting.
+ * @param mode The default private dns mode. This should be one of the PRIVATE_DNS_MODE_*
+ * constants.
+ */
+ public static void setPrivateDnsDefaultMode(@NonNull Context context,
+ @NonNull @PrivateDnsMode String mode) {
+ if (!(mode == PRIVATE_DNS_MODE_OFF
+ || mode == PRIVATE_DNS_MODE_OPPORTUNISTIC
+ || mode == PRIVATE_DNS_MODE_PROVIDER_HOSTNAME)) {
+ throw new IllegalArgumentException("Invalid private dns mode");
+ }
+ Settings.Global.putString(context.getContentResolver(), PRIVATE_DNS_DEFAULT_MODE, mode);
+ }
+
+ /**
+ * Get duration (from {@link Settings}) to keep a PendingIntent-based request.
+ *
+ * @param context The {@link Context} to query the setting.
+ * @param def The default duration if no setting value.
+ * @return The duration to keep a PendingIntent-based request.
+ */
+ @NonNull
+ public static Duration getConnectivityKeepPendingIntentDuration(@NonNull Context context,
+ @NonNull Duration def) {
+ final int duration = Settings.Secure.getInt(context.getContentResolver(),
+ CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS, (int) def.toMillis());
+ return Duration.ofMillis(duration);
+ }
+
+ /**
+ * Set duration (to {@link Settings}) to keep a PendingIntent-based request.
+ *
+ * @param context The {@link Context} to set the setting.
+ * @param duration The duration to keep a PendingIntent-based request.
+ */
+ public static void setConnectivityKeepPendingIntentDuration(@NonNull Context context,
+ @NonNull Duration duration) {
+ final int time = (int) duration.toMillis();
+ if (time < 0) {
+ throw new IllegalArgumentException("Invalid duration.");
+ }
+ Settings.Secure.putInt(
+ context.getContentResolver(), CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS, time);
+ }
+
+ /**
+ * Read from {@link Settings} whether the mobile data connection should remain active
+ * even when higher priority networks are active.
+ *
+ * @param context The {@link Context} to query the setting.
+ * @param def The default value if no setting value.
+ * @return Whether the mobile data connection should remain active even when higher
+ * priority networks are active.
+ */
+ public static boolean getMobileDataAlwaysOn(@NonNull Context context, boolean def) {
+ final int enable = Settings.Global.getInt(
+ context.getContentResolver(), MOBILE_DATA_ALWAYS_ON, (def ? 1 : 0));
+ return (enable != 0) ? true : false;
+ }
+
+ /**
+ * Write into {@link Settings} whether the mobile data connection should remain active
+ * even when higher priority networks are active.
+ *
+ * @param context The {@link Context} to set the setting.
+ * @param enable Whether the mobile data connection should remain active even when higher
+ * priority networks are active.
+ */
+ public static void setMobileDataAlwaysOn(@NonNull Context context, boolean enable) {
+ Settings.Global.putInt(
+ context.getContentResolver(), MOBILE_DATA_ALWAYS_ON, (enable ? 1 : 0));
+ }
+
+ /**
+ * Read from {@link Settings} whether the wifi data connection should remain active
+ * even when higher priority networks are active.
+ *
+ * @param context The {@link Context} to query the setting.
+ * @param def The default value if no setting value.
+ * @return Whether the wifi data connection should remain active even when higher
+ * priority networks are active.
+ */
+ public static boolean getWifiAlwaysRequested(@NonNull Context context, boolean def) {
+ final int enable = Settings.Global.getInt(
+ context.getContentResolver(), WIFI_ALWAYS_REQUESTED, (def ? 1 : 0));
+ return (enable != 0) ? true : false;
+ }
+
+ /**
+ * Write into {@link Settings} whether the wifi data connection should remain active
+ * even when higher priority networks are active.
+ *
+ * @param context The {@link Context} to set the setting.
+ * @param enable Whether the wifi data connection should remain active even when higher
+ * priority networks are active
+ */
+ public static void setWifiAlwaysRequested(@NonNull Context context, boolean enable) {
+ Settings.Global.putInt(
+ context.getContentResolver(), WIFI_ALWAYS_REQUESTED, (enable ? 1 : 0));
+ }
+
+ /**
+ * Get avoid bad wifi setting from {@link Settings}.
+ *
+ * @param context The {@link Context} to query the setting.
+ * @return The setting whether to automatically switch away from wifi networks that lose
+ * internet access.
+ */
+ @NetworkAvoidBadWifi
+ public static int getNetworkAvoidBadWifi(@NonNull Context context) {
+ final String setting =
+ Settings.Global.getString(context.getContentResolver(), NETWORK_AVOID_BAD_WIFI);
+ if ("0".equals(setting)) {
+ return NETWORK_AVOID_BAD_WIFI_IGNORE;
+ } else if ("1".equals(setting)) {
+ return NETWORK_AVOID_BAD_WIFI_AVOID;
+ } else {
+ return NETWORK_AVOID_BAD_WIFI_PROMPT;
+ }
+ }
+
+ /**
+ * Set avoid bad wifi setting to {@link Settings}.
+ *
+ * @param context The {@link Context} to set the setting.
+ * @param value Whether to automatically switch away from wifi networks that lose internet
+ * access.
+ */
+ public static void setNetworkAvoidBadWifi(@NonNull Context context,
+ @NetworkAvoidBadWifi int value) {
+ final String setting;
+ if (value == NETWORK_AVOID_BAD_WIFI_IGNORE) {
+ setting = "0";
+ } else if (value == NETWORK_AVOID_BAD_WIFI_AVOID) {
+ setting = "1";
+ } else if (value == NETWORK_AVOID_BAD_WIFI_PROMPT) {
+ setting = null;
+ } else {
+ throw new IllegalArgumentException("Invalid avoid bad wifi setting");
+ }
+ Settings.Global.putString(context.getContentResolver(), NETWORK_AVOID_BAD_WIFI, setting);
+ }
+
+ /**
+ * Get network metered multipath preference from {@link Settings}.
+ *
+ * @param context The {@link Context} to query the setting.
+ * @return The network metered multipath preference which should be one of
+ * ConnectivityManager#MULTIPATH_PREFERENCE_* value or null if the value specified
+ * by config_networkMeteredMultipathPreference is used.
+ */
+ @Nullable
+ public static String getNetworkMeteredMultipathPreference(@NonNull Context context) {
+ return Settings.Global.getString(
+ context.getContentResolver(), NETWORK_METERED_MULTIPATH_PREFERENCE);
+ }
+
+ /**
+ * Set network metered multipath preference to {@link Settings}.
+ *
+ * @param context The {@link Context} to set the setting.
+ * @param preference The network metered multipath preference which should be one of
+ * ConnectivityManager#MULTIPATH_PREFERENCE_* value or null if the value
+ * specified by config_networkMeteredMultipathPreference is used.
+ */
+ public static void setNetworkMeteredMultipathPreference(@NonNull Context context,
+ @NonNull @MultipathPreference String preference) {
+ if (!(Integer.valueOf(preference) == MULTIPATH_PREFERENCE_HANDOVER
+ || Integer.valueOf(preference) == MULTIPATH_PREFERENCE_RELIABILITY
+ || Integer.valueOf(preference) == MULTIPATH_PREFERENCE_PERFORMANCE)) {
+ throw new IllegalArgumentException("Invalid private dns mode");
+ }
+ Settings.Global.putString(
+ context.getContentResolver(), NETWORK_METERED_MULTIPATH_PREFERENCE, preference);
+ }
+
+ /**
+ * Get the list of apps(from {@link Settings}) that should go on cellular networks in preference
+ * even when higher-priority networks are connected.
+ *
+ * @param context The {@link Context} to query the setting.
+ * @return A list of apps that should go on cellular networks in preference even when
+ * higher-priority networks are connected or null if no setting value.
+ */
+ @Nullable
+ public static String getMobileDataPreferredApps(@NonNull Context context) {
+ return Settings.Secure.getString(context.getContentResolver(), MOBILE_DATA_PREFERRED_APPS);
+ }
+
+ /**
+ * Set the list of apps(to {@link Settings}) that should go on cellular networks in preference
+ * even when higher-priority networks are connected.
+ *
+ * @param context The {@link Context} to set the setting.
+ * @param list A list of apps that should go on cellular networks in preference even when
+ * higher-priority networks are connected.
+ */
+ public static void setMobileDataPreferredApps(@NonNull Context context, @Nullable String list) {
+ Settings.Secure.putString(context.getContentResolver(), MOBILE_DATA_PREFERRED_APPS, list);
+ }
}
diff --git a/packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl b/packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl
index 3300fa8fd12a..0826922e2165 100644
--- a/packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl
+++ b/packages/Connectivity/framework/src/android/net/IConnectivityManager.aidl
@@ -142,7 +142,7 @@ interface IConnectivityManager
in NetworkCapabilities nc, in NetworkScore score, in NetworkAgentConfig config,
in int factorySerialNumber);
- NetworkRequest requestNetwork(in NetworkCapabilities networkCapabilities, int reqType,
+ NetworkRequest requestNetwork(int uid, in NetworkCapabilities networkCapabilities, int reqType,
in Messenger messenger, int timeoutSec, in IBinder binder, int legacy,
int callbackFlags, String callingPackageName, String callingAttributionTag);
diff --git a/packages/Connectivity/framework/src/android/net/INetworkAgent.aidl b/packages/Connectivity/framework/src/android/net/INetworkAgent.aidl
index 1f66e18717d8..d941d4b95b56 100644
--- a/packages/Connectivity/framework/src/android/net/INetworkAgent.aidl
+++ b/packages/Connectivity/framework/src/android/net/INetworkAgent.aidl
@@ -46,4 +46,6 @@ oneway interface INetworkAgent {
void onRemoveKeepalivePacketFilter(int slot);
void onQosFilterCallbackRegistered(int qosCallbackId, in QosFilterParcelable filterParcel);
void onQosCallbackUnregistered(int qosCallbackId);
+ void onNetworkCreated();
+ void onNetworkDestroyed();
}
diff --git a/packages/Connectivity/framework/src/android/net/INetworkAgentRegistry.aidl b/packages/Connectivity/framework/src/android/net/INetworkAgentRegistry.aidl
index c5464d32412b..26cb1ed6b4b4 100644
--- a/packages/Connectivity/framework/src/android/net/INetworkAgentRegistry.aidl
+++ b/packages/Connectivity/framework/src/android/net/INetworkAgentRegistry.aidl
@@ -22,6 +22,7 @@ import android.net.NetworkInfo;
import android.net.NetworkScore;
import android.net.QosSession;
import android.telephony.data.EpsBearerQosSessionAttributes;
+import android.telephony.data.NrQosSessionAttributes;
/**
* Interface for NetworkAgents to send network properties.
@@ -37,6 +38,8 @@ oneway interface INetworkAgentRegistry {
void sendSocketKeepaliveEvent(int slot, int reason);
void sendUnderlyingNetworks(in @nullable List<Network> networks);
void sendEpsQosSessionAvailable(int callbackId, in QosSession session, in EpsBearerQosSessionAttributes attributes);
+ void sendNrQosSessionAvailable(int callbackId, in QosSession session, in NrQosSessionAttributes attributes);
void sendQosSessionLost(int qosCallbackId, in QosSession session);
void sendQosCallbackError(int qosCallbackId, int exceptionType);
+ void sendTeardownDelayMs(int teardownDelayMs);
}
diff --git a/packages/Connectivity/framework/src/android/net/IQosCallback.aidl b/packages/Connectivity/framework/src/android/net/IQosCallback.aidl
index 91c75759f85c..c9735419f7dd 100644
--- a/packages/Connectivity/framework/src/android/net/IQosCallback.aidl
+++ b/packages/Connectivity/framework/src/android/net/IQosCallback.aidl
@@ -19,6 +19,7 @@ package android.net;
import android.os.Bundle;
import android.net.QosSession;
import android.telephony.data.EpsBearerQosSessionAttributes;
+import android.telephony.data.NrQosSessionAttributes;
/**
* AIDL interface for QosCallback
@@ -29,6 +30,8 @@ oneway interface IQosCallback
{
void onQosEpsBearerSessionAvailable(in QosSession session,
in EpsBearerQosSessionAttributes attributes);
+ void onNrQosSessionAvailable(in QosSession session,
+ in NrQosSessionAttributes attributes);
void onQosSessionLost(in QosSession session);
void onError(in int type);
}
diff --git a/packages/Connectivity/framework/src/android/net/NetworkAgent.java b/packages/Connectivity/framework/src/android/net/NetworkAgent.java
index 3863ed1113f3..c57da53f289d 100644
--- a/packages/Connectivity/framework/src/android/net/NetworkAgent.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkAgent.java
@@ -32,6 +32,7 @@ import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
import android.telephony.data.EpsBearerQosSessionAttributes;
+import android.telephony.data.NrQosSessionAttributes;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
@@ -184,6 +185,20 @@ public abstract class NetworkAgent {
public static final int EVENT_UNDERLYING_NETWORKS_CHANGED = BASE + 5;
/**
+ * Sent by the NetworkAgent to ConnectivityService to pass the current value of the teardown
+ * delay.
+ * arg1 = teardown delay in milliseconds
+ * @hide
+ */
+ public static final int EVENT_TEARDOWN_DELAY_CHANGED = BASE + 6;
+
+ /**
+ * The maximum value for the teardown delay, in milliseconds.
+ * @hide
+ */
+ public static final int MAX_TEARDOWN_DELAY_MS = 5000;
+
+ /**
* Sent by ConnectivityService to the NetworkAgent to inform the agent of the
* networks status - whether we could use the network or could not, due to
* either a bad network configuration (no internet link) or captive portal.
@@ -196,7 +211,6 @@ public abstract class NetworkAgent {
*/
public static final int CMD_REPORT_NETWORK_STATUS = BASE + 7;
-
/**
* Network validation suceeded.
* Corresponds to {@link NetworkCapabilities.NET_CAPABILITY_VALIDATED}.
@@ -361,10 +375,25 @@ public abstract class NetworkAgent {
*/
public static final int CMD_UNREGISTER_QOS_CALLBACK = BASE + 21;
+ /**
+ * Sent by ConnectivityService to {@link NetworkAgent} to inform the agent that its native
+ * network was created and the Network object is now valid.
+ *
+ * @hide
+ */
+ public static final int CMD_NETWORK_CREATED = BASE + 22;
+
+ /**
+ * Sent by ConnectivityService to {@link NetworkAgent} to inform the agent that its native
+ * network was destroyed.
+ *
+ * @hide
+ */
+ public static final int CMD_NETWORK_DESTROYED = BASE + 23;
+
private static NetworkInfo getLegacyNetworkInfo(final NetworkAgentConfig config) {
- // The subtype can be changed with (TODO) setLegacySubtype, but it starts
- // with 0 (TelephonyManager.NETWORK_TYPE_UNKNOWN) and an empty description.
- final NetworkInfo ni = new NetworkInfo(config.legacyType, 0, config.legacyTypeName, "");
+ final NetworkInfo ni = new NetworkInfo(config.legacyType, config.legacySubType,
+ config.legacyTypeName, config.legacySubTypeName);
ni.setIsAvailable(true);
ni.setDetailedState(NetworkInfo.DetailedState.CONNECTING, null /* reason */,
config.getLegacyExtraInfo());
@@ -390,7 +419,6 @@ public abstract class NetworkAgent {
* @param score the initial score of this network. Update with sendNetworkScore.
* @param config an immutable {@link NetworkAgentConfig} for this agent.
* @param provider the {@link NetworkProvider} managing this agent.
- * @hide TODO : unhide when impl is complete
*/
public NetworkAgent(@NonNull Context context, @NonNull Looper looper, @NonNull String logTag,
@NonNull NetworkCapabilities nc, @NonNull LinkProperties lp,
@@ -562,6 +590,14 @@ public abstract class NetworkAgent {
msg.arg1 /* QoS callback id */);
break;
}
+ case CMD_NETWORK_CREATED: {
+ onNetworkCreated();
+ break;
+ }
+ case CMD_NETWORK_DESTROYED: {
+ onNetworkDestroyed();
+ break;
+ }
}
}
}
@@ -702,6 +738,16 @@ public abstract class NetworkAgent {
mHandler.sendMessage(mHandler.obtainMessage(
CMD_UNREGISTER_QOS_CALLBACK, qosCallbackId, 0, null));
}
+
+ @Override
+ public void onNetworkCreated() {
+ mHandler.sendMessage(mHandler.obtainMessage(CMD_NETWORK_CREATED));
+ }
+
+ @Override
+ public void onNetworkDestroyed() {
+ mHandler.sendMessage(mHandler.obtainMessage(CMD_NETWORK_DESTROYED));
+ }
}
/**
@@ -818,6 +864,29 @@ public abstract class NetworkAgent {
}
/**
+ * Sets the value of the teardown delay.
+ *
+ * The teardown delay is the time between when the network disconnects and when the native
+ * network corresponding to this {@code NetworkAgent} is destroyed. By default, the native
+ * network is destroyed immediately. If {@code teardownDelayMs} is non-zero, then when this
+ * network disconnects, the system will instead immediately mark the network as restricted
+ * and unavailable to unprivileged apps, but will defer destroying the native network until the
+ * teardown delay timer expires.
+ *
+ * The interfaces in use by this network will remain in use until the native network is
+ * destroyed and cannot be reused until {@link #onNetworkDestroyed()} is called.
+ *
+ * This method may be called at any time while the network is connected. It has no effect if
+ * the network is already disconnected and the teardown delay timer is running.
+ *
+ * @param teardownDelayMs the teardown delay to set, or 0 to disable teardown delay.
+ */
+ public void setTeardownDelayMs(
+ @IntRange(from = 0, to = MAX_TEARDOWN_DELAY_MS) int teardownDelayMs) {
+ queueOrSendMessage(reg -> reg.sendTeardownDelayMs(teardownDelayMs));
+ }
+
+ /**
* Change the legacy subtype of this network agent.
*
* This is only for backward compatibility and should not be used by non-legacy network agents,
@@ -829,6 +898,7 @@ public abstract class NetworkAgent {
* @hide
*/
@Deprecated
+ @SystemApi
public void setLegacySubtype(final int legacySubtype, @NonNull final String legacySubtypeName) {
mNetworkInfo.setSubtype(legacySubtype, legacySubtypeName);
queueOrSendNetworkInfo(mNetworkInfo);
@@ -962,6 +1032,7 @@ public abstract class NetworkAgent {
* shall try to overwrite this method and produce a bandwidth update if capable.
* @hide
*/
+ @SystemApi
public void onBandwidthUpdateRequested() {
pollLceData();
}
@@ -1010,6 +1081,17 @@ public abstract class NetworkAgent {
}
/**
+ * Called when ConnectivityService has successfully created this NetworkAgent's native network.
+ */
+ public void onNetworkCreated() {}
+
+
+ /**
+ * Called when ConnectivityService has successfully destroy this NetworkAgent's native network.
+ */
+ public void onNetworkDestroyed() {}
+
+ /**
* Requests that the network hardware send the specified packet at the specified interval.
*
* @param slot the hardware slot on which to start the keepalive.
@@ -1160,29 +1242,37 @@ public abstract class NetworkAgent {
/**
- * Sends the attributes of Eps Bearer Qos Session back to the Application
+ * Sends the attributes of Qos Session back to the Application
*
* @param qosCallbackId the callback id that the session belongs to
- * @param sessionId the unique session id across all Eps Bearer Qos Sessions
- * @param attributes the attributes of the Eps Qos Session
+ * @param sessionId the unique session id across all Qos Sessions
+ * @param attributes the attributes of the Qos Session
*/
public final void sendQosSessionAvailable(final int qosCallbackId, final int sessionId,
- @NonNull final EpsBearerQosSessionAttributes attributes) {
+ @NonNull final QosSessionAttributes attributes) {
Objects.requireNonNull(attributes, "The attributes must be non-null");
- queueOrSendMessage(ra -> ra.sendEpsQosSessionAvailable(qosCallbackId,
- new QosSession(sessionId, QosSession.TYPE_EPS_BEARER),
- attributes));
+ if (attributes instanceof EpsBearerQosSessionAttributes) {
+ queueOrSendMessage(ra -> ra.sendEpsQosSessionAvailable(qosCallbackId,
+ new QosSession(sessionId, QosSession.TYPE_EPS_BEARER),
+ (EpsBearerQosSessionAttributes)attributes));
+ } else if (attributes instanceof NrQosSessionAttributes) {
+ queueOrSendMessage(ra -> ra.sendNrQosSessionAvailable(qosCallbackId,
+ new QosSession(sessionId, QosSession.TYPE_NR_BEARER),
+ (NrQosSessionAttributes)attributes));
+ }
}
/**
- * Sends event that the Eps Qos Session was lost.
+ * Sends event that the Qos Session was lost.
*
* @param qosCallbackId the callback id that the session belongs to
- * @param sessionId the unique session id across all Eps Bearer Qos Sessions
+ * @param sessionId the unique session id across all Qos Sessions
+ * @param qosSessionType the session type {@code QosSesson#QosSessionType}
*/
- public final void sendQosSessionLost(final int qosCallbackId, final int sessionId) {
+ public final void sendQosSessionLost(final int qosCallbackId,
+ final int sessionId, final int qosSessionType) {
queueOrSendMessage(ra -> ra.sendQosSessionLost(qosCallbackId,
- new QosSession(sessionId, QosSession.TYPE_EPS_BEARER)));
+ new QosSession(sessionId, qosSessionType)));
}
/**
diff --git a/packages/Connectivity/framework/src/android/net/NetworkAgentConfig.java b/packages/Connectivity/framework/src/android/net/NetworkAgentConfig.java
index 5e50a6404acb..3f058d8cbf12 100644
--- a/packages/Connectivity/framework/src/android/net/NetworkAgentConfig.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkAgentConfig.java
@@ -64,6 +64,16 @@ public final class NetworkAgentConfig implements Parcelable {
}
/**
+ * @return whether this VPN connection can be bypassed by the apps.
+ *
+ * @hide
+ */
+ @SystemApi(client = MODULE_LIBRARIES)
+ public boolean isBypassableVpn() {
+ return allowBypass;
+ }
+
+ /**
* Set if the user desires to use this network even if it is unvalidated. This field has meaning
* only if {@link explicitlySelected} is true. If it is, this field must also be set to the
* appropriate value based on previous user choice.
@@ -165,6 +175,12 @@ public final class NetworkAgentConfig implements Parcelable {
}
/**
+ * The legacy Sub type of this network agent, or TYPE_NONE if unset.
+ * @hide
+ */
+ public int legacySubType = ConnectivityManager.TYPE_NONE;
+
+ /**
* Set to true if the PRIVATE_DNS_BROKEN notification has shown for this network.
* Reset this bit when private DNS mode is changed from strict mode to opportunistic/off mode.
*
@@ -190,6 +206,13 @@ public final class NetworkAgentConfig implements Parcelable {
}
/**
+ * The name of the legacy Sub network type. It's a free-form string.
+ * @hide
+ */
+ @NonNull
+ public String legacySubTypeName = "";
+
+ /**
* The legacy extra info of the agent. The extra info should only be :
* <ul>
* <li>For cellular agents, the APN name.</li>
@@ -225,6 +248,8 @@ public final class NetworkAgentConfig implements Parcelable {
skip464xlat = nac.skip464xlat;
legacyType = nac.legacyType;
legacyTypeName = nac.legacyTypeName;
+ legacySubType = nac.legacySubType;
+ legacySubTypeName = nac.legacySubTypeName;
mLegacyExtraInfo = nac.mLegacyExtraInfo;
}
}
@@ -290,7 +315,6 @@ public final class NetworkAgentConfig implements Parcelable {
* and reduce idle traffic on networks that are known to be IPv6-only without a NAT64.
*
* @return this builder, to facilitate chaining.
- * @hide
*/
@NonNull
public Builder disableNat64Detection() {
@@ -303,7 +327,6 @@ public final class NetworkAgentConfig implements Parcelable {
* perform its own carrier-specific provisioning procedure.
*
* @return this builder, to facilitate chaining.
- * @hide
*/
@NonNull
public Builder disableProvisioningNotification() {
@@ -324,6 +347,18 @@ public final class NetworkAgentConfig implements Parcelable {
}
/**
+ * Sets the legacy sub-type for this network.
+ *
+ * @param legacySubType the type
+ * @return this builder, to facilitate chaining.
+ */
+ @NonNull
+ public Builder setLegacySubType(final int legacySubType) {
+ mConfig.legacySubType = legacySubType;
+ return this;
+ }
+
+ /**
* Sets the name of the legacy type of the agent. It's a free-form string used in logging.
* @param legacyTypeName the name
* @return this builder, to facilitate chaining.
@@ -335,10 +370,20 @@ public final class NetworkAgentConfig implements Parcelable {
}
/**
+ * Sets the name of the legacy Sub-type of the agent. It's a free-form string.
+ * @param legacySubTypeName the name
+ * @return this builder, to facilitate chaining.
+ */
+ @NonNull
+ public Builder setLegacySubTypeName(@NonNull String legacySubTypeName) {
+ mConfig.legacySubTypeName = legacySubTypeName;
+ return this;
+ }
+
+ /**
* Sets the legacy extra info of the agent.
* @param legacyExtraInfo the legacy extra info.
* @return this builder, to facilitate chaining.
- * @hide
*/
@NonNull
public Builder setLegacyExtraInfo(@NonNull String legacyExtraInfo) {
@@ -347,6 +392,19 @@ public final class NetworkAgentConfig implements Parcelable {
}
/**
+ * Sets whether the apps can bypass the VPN connection.
+ *
+ * @return this builder, to facilitate chaining.
+ * @hide
+ */
+ @NonNull
+ @SystemApi(client = MODULE_LIBRARIES)
+ public Builder setBypassableVpn(boolean allowBypass) {
+ mConfig.allowBypass = allowBypass;
+ return this;
+ }
+
+ /**
* Returns the constructed {@link NetworkAgentConfig} object.
*/
@NonNull
@@ -412,6 +470,8 @@ public final class NetworkAgentConfig implements Parcelable {
out.writeInt(skip464xlat ? 1 : 0);
out.writeInt(legacyType);
out.writeString(legacyTypeName);
+ out.writeInt(legacySubType);
+ out.writeString(legacySubTypeName);
out.writeString(mLegacyExtraInfo);
}
@@ -429,6 +489,8 @@ public final class NetworkAgentConfig implements Parcelable {
networkAgentConfig.skip464xlat = in.readInt() != 0;
networkAgentConfig.legacyType = in.readInt();
networkAgentConfig.legacyTypeName = in.readString();
+ networkAgentConfig.legacySubType = in.readInt();
+ networkAgentConfig.legacySubTypeName = in.readString();
networkAgentConfig.mLegacyExtraInfo = in.readString();
return networkAgentConfig;
}
diff --git a/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java b/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java
index c9c0940dfdf5..881fa8c2702c 100644
--- a/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java
@@ -639,19 +639,31 @@ public final class NetworkCapabilities implements Parcelable {
}
/**
- * Removes (if found) the given capability from this {@code NetworkCapability} instance.
+ * Removes (if found) the given capability from this {@code NetworkCapability}
+ * instance that were added via addCapability(int) or setCapabilities(int[], int[]).
*
* @param capability the capability to be removed.
* @return This NetworkCapabilities instance, to facilitate chaining.
* @hide
*/
public @NonNull NetworkCapabilities removeCapability(@NetCapability int capability) {
- // Note that this method removes capabilities that were added via addCapability(int),
- // addUnwantedCapability(int) or setCapabilities(int[], int[]).
checkValidCapability(capability);
final long mask = ~(1 << capability);
mNetworkCapabilities &= mask;
- mUnwantedNetworkCapabilities &= mask;
+ return this;
+ }
+
+ /**
+ * Removes (if found) the given unwanted capability from this {@code NetworkCapability}
+ * instance that were added via addUnwantedCapability(int) or setCapabilities(int[], int[]).
+ *
+ * @param capability the capability to be removed.
+ * @return This NetworkCapabilities instance, to facilitate chaining.
+ * @hide
+ */
+ public @NonNull NetworkCapabilities removeUnwantedCapability(@NetCapability int capability) {
+ checkValidCapability(capability);
+ mUnwantedNetworkCapabilities &= ~(1 << capability);
return this;
}
@@ -723,6 +735,7 @@ public final class NetworkCapabilities implements Parcelable {
}
/** @hide */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public boolean hasUnwantedCapability(@NetCapability int capability) {
return isValidCapability(capability)
&& ((mUnwantedNetworkCapabilities & (1 << capability)) != 0);
@@ -736,10 +749,16 @@ public final class NetworkCapabilities implements Parcelable {
return ((mNetworkCapabilities & CONNECTIVITY_MANAGED_CAPABILITIES) != 0);
}
- /** Note this method may result in having the same capability in wanted and unwanted lists. */
private void combineNetCapabilities(@NonNull NetworkCapabilities nc) {
- this.mNetworkCapabilities |= nc.mNetworkCapabilities;
- this.mUnwantedNetworkCapabilities |= nc.mUnwantedNetworkCapabilities;
+ final long wantedCaps = this.mNetworkCapabilities | nc.mNetworkCapabilities;
+ final long unwantedCaps =
+ this.mUnwantedNetworkCapabilities | nc.mUnwantedNetworkCapabilities;
+ if ((wantedCaps & unwantedCaps) != 0) {
+ throw new IllegalArgumentException(
+ "Cannot have the same capability in wanted and unwanted lists.");
+ }
+ this.mNetworkCapabilities = wantedCaps;
+ this.mUnwantedNetworkCapabilities = unwantedCaps;
}
/**
diff --git a/packages/Connectivity/framework/src/android/net/NetworkRequest.java b/packages/Connectivity/framework/src/android/net/NetworkRequest.java
index cf131f0df607..38691ef5cb39 100644
--- a/packages/Connectivity/framework/src/android/net/NetworkRequest.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkRequest.java
@@ -216,6 +216,14 @@ public class NetworkRequest implements Parcelable {
}
/**
+ * Creates a new Builder of NetworkRequest from an existing instance.
+ */
+ public Builder(@NonNull final NetworkRequest request) {
+ Objects.requireNonNull(request);
+ mNetworkCapabilities = request.networkCapabilities;
+ }
+
+ /**
* Build {@link NetworkRequest} give the current set of capabilities.
*/
public NetworkRequest build() {
@@ -305,12 +313,31 @@ public class NetworkRequest implements Parcelable {
*
* @hide
*/
+ @NonNull
+ @SuppressLint("MissingGetterMatchingBuilder")
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public Builder addUnwantedCapability(@NetworkCapabilities.NetCapability int capability) {
mNetworkCapabilities.addUnwantedCapability(capability);
return this;
}
/**
+ * Removes (if found) the given unwanted capability from this builder instance.
+ *
+ * @param capability The unwanted capability to remove.
+ * @return The builder to facilitate chaining.
+ *
+ * @hide
+ */
+ @NonNull
+ @SuppressLint("BuilderSetStyle")
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public Builder removeUnwantedCapability(@NetworkCapabilities.NetCapability int capability) {
+ mNetworkCapabilities.removeUnwantedCapability(capability);
+ return this;
+ }
+
+ /**
* Completely clears all the {@code NetworkCapabilities} from this builder instance,
* removing even the capabilities that are set by default when the object is constructed.
*
@@ -567,6 +594,7 @@ public class NetworkRequest implements Parcelable {
*
* @hide
*/
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public boolean hasUnwantedCapability(@NetCapability int capability) {
return networkCapabilities.hasUnwantedCapability(capability);
}
@@ -671,4 +699,43 @@ public class NetworkRequest implements Parcelable {
public int hashCode() {
return Objects.hash(requestId, legacyType, networkCapabilities, type);
}
+
+ /**
+ * Gets all the capabilities set on this {@code NetworkRequest} instance.
+ *
+ * @return an array of capability values for this instance.
+ */
+ @NonNull
+ public @NetCapability int[] getCapabilities() {
+ // No need to make a defensive copy here as NC#getCapabilities() already returns
+ // a new array.
+ return networkCapabilities.getCapabilities();
+ }
+
+ /**
+ * Gets all the unwanted capabilities set on this {@code NetworkRequest} instance.
+ *
+ * @return an array of unwanted capability values for this instance.
+ *
+ * @hide
+ */
+ @NonNull
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public @NetCapability int[] getUnwantedCapabilities() {
+ // No need to make a defensive copy here as NC#getUnwantedCapabilities() already returns
+ // a new array.
+ return networkCapabilities.getUnwantedCapabilities();
+ }
+
+ /**
+ * Gets all the transports set on this {@code NetworkRequest} instance.
+ *
+ * @return an array of transport type values for this instance.
+ */
+ @NonNull
+ public @Transport int[] getTransportTypes() {
+ // No need to make a defensive copy here as NC#getTransportTypes() already returns
+ // a new array.
+ return networkCapabilities.getTransportTypes();
+ }
}
diff --git a/packages/Connectivity/framework/src/android/net/NetworkScore.java b/packages/Connectivity/framework/src/android/net/NetworkScore.java
index eadcb2d0a7f4..65849930fa4a 100644
--- a/packages/Connectivity/framework/src/android/net/NetworkScore.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkScore.java
@@ -17,6 +17,7 @@
package android.net;
import android.annotation.NonNull;
+import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
@@ -29,7 +30,7 @@ import com.android.internal.annotations.VisibleForTesting;
* network is considered for a particular use.
* @hide
*/
-// TODO : @SystemApi when the implementation is complete
+@SystemApi
public final class NetworkScore implements Parcelable {
// This will be removed soon. Do *NOT* depend on it for any new code that is not part of
// a migration.
@@ -62,6 +63,8 @@ public final class NetworkScore implements Parcelable {
/**
* @return whether this score has a particular policy.
+ *
+ * @hide
*/
@VisibleForTesting
public boolean hasPolicy(final int policy) {
diff --git a/packages/Connectivity/framework/src/android/net/NetworkUtils.java b/packages/Connectivity/framework/src/android/net/NetworkUtils.java
index c4bebc0a982e..a92fda1cde46 100644
--- a/packages/Connectivity/framework/src/android/net/NetworkUtils.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkUtils.java
@@ -92,7 +92,10 @@ public class NetworkUtils {
* Determine if {@code uid} can access network designated by {@code netId}.
* @return {@code true} if {@code uid} can access network, {@code false} otherwise.
*/
- public native static boolean queryUserAccess(int uid, int netId);
+ public static boolean queryUserAccess(int uid, int netId) {
+ // TODO (b/183485986): remove this method
+ return false;
+ }
/**
* DNS resolver series jni method.
diff --git a/packages/Connectivity/framework/src/android/net/QosCallbackConnection.java b/packages/Connectivity/framework/src/android/net/QosCallbackConnection.java
index bdb4ad68cd7b..de0fc243b43b 100644
--- a/packages/Connectivity/framework/src/android/net/QosCallbackConnection.java
+++ b/packages/Connectivity/framework/src/android/net/QosCallbackConnection.java
@@ -19,6 +19,7 @@ package android.net;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.telephony.data.EpsBearerQosSessionAttributes;
+import android.telephony.data.NrQosSessionAttributes;
import com.android.internal.annotations.VisibleForTesting;
@@ -84,6 +85,25 @@ class QosCallbackConnection extends android.net.IQosCallback.Stub {
}
/**
+ * Called when either the {@link NrQosSessionAttributes} has changed or on the first time
+ * the attributes have become available.
+ *
+ * @param session the session that is now available
+ * @param attributes the corresponding attributes of session
+ */
+ @Override
+ public void onNrQosSessionAvailable(@NonNull final QosSession session,
+ @NonNull final NrQosSessionAttributes attributes) {
+
+ mExecutor.execute(() -> {
+ final QosCallback callback = mCallback;
+ if (callback != null) {
+ callback.onQosSessionAvailable(session, attributes);
+ }
+ });
+ }
+
+ /**
* Called when the session is lost.
*
* @param session the session that was lost
diff --git a/packages/Connectivity/framework/src/android/net/QosSession.java b/packages/Connectivity/framework/src/android/net/QosSession.java
index 4f3bb77c5877..93f2ff2bf724 100644
--- a/packages/Connectivity/framework/src/android/net/QosSession.java
+++ b/packages/Connectivity/framework/src/android/net/QosSession.java
@@ -36,6 +36,11 @@ public final class QosSession implements Parcelable {
*/
public static final int TYPE_EPS_BEARER = 1;
+ /**
+ * The {@link QosSession} is a NR Session.
+ */
+ public static final int TYPE_NR_BEARER = 2;
+
private final int mSessionId;
private final int mSessionType;
@@ -100,6 +105,7 @@ public final class QosSession implements Parcelable {
*/
@IntDef(value = {
TYPE_EPS_BEARER,
+ TYPE_NR_BEARER,
})
@interface QosSessionType {}
diff --git a/packages/Connectivity/framework/src/android/net/SocketKeepalive.java b/packages/Connectivity/framework/src/android/net/SocketKeepalive.java
index d007a9520cb5..f6cae7251609 100644
--- a/packages/Connectivity/framework/src/android/net/SocketKeepalive.java
+++ b/packages/Connectivity/framework/src/android/net/SocketKeepalive.java
@@ -55,36 +55,68 @@ public abstract class SocketKeepalive implements AutoCloseable {
static final String TAG = "SocketKeepalive";
/**
- * No errors.
+ * Success. It indicates there is no error.
* @hide
*/
@SystemApi
public static final int SUCCESS = 0;
- /** @hide */
+ /**
+ * No keepalive. This should only be internally as it indicates There is no keepalive.
+ * It should not propagate to applications.
+ * @hide
+ */
public static final int NO_KEEPALIVE = -1;
- /** @hide */
+ /**
+ * Data received.
+ * @hide
+ */
public static final int DATA_RECEIVED = -2;
- /** @hide */
+ /**
+ * The binder died.
+ * @hide
+ */
public static final int BINDER_DIED = -10;
- /** The specified {@code Network} is not connected. */
+ /**
+ * The invalid network. It indicates the specified {@code Network} is not connected.
+ */
public static final int ERROR_INVALID_NETWORK = -20;
- /** The specified IP addresses are invalid. For example, the specified source IP address is
- * not configured on the specified {@code Network}. */
+
+ /**
+ * The invalid IP addresses. Indicates the specified IP addresses are invalid.
+ * For example, the specified source IP address is not configured on the
+ * specified {@code Network}.
+ */
public static final int ERROR_INVALID_IP_ADDRESS = -21;
- /** The requested port is invalid. */
+
+ /**
+ * The port is invalid.
+ */
public static final int ERROR_INVALID_PORT = -22;
- /** The packet length is invalid (e.g., too long). */
+
+ /**
+ * The length is invalid (e.g. too long).
+ */
public static final int ERROR_INVALID_LENGTH = -23;
- /** The packet transmission interval is invalid (e.g., too short). */
+
+ /**
+ * The interval is invalid (e.g. too short).
+ */
public static final int ERROR_INVALID_INTERVAL = -24;
- /** The target socket is invalid. */
+
+ /**
+ * The socket is invalid.
+ */
public static final int ERROR_INVALID_SOCKET = -25;
- /** The target socket is not idle. */
+
+ /**
+ * The socket is not idle.
+ */
public static final int ERROR_SOCKET_NOT_IDLE = -26;
+
/**
* The stop reason is uninitialized. This should only be internally used as initial state
* of stop reason, instead of propagating to application.
@@ -92,15 +124,29 @@ public abstract class SocketKeepalive implements AutoCloseable {
*/
public static final int ERROR_STOP_REASON_UNINITIALIZED = -27;
- /** The device does not support this request. */
+ /**
+ * The request is unsupported.
+ */
public static final int ERROR_UNSUPPORTED = -30;
- /** @hide TODO: delete when telephony code has been updated. */
- public static final int ERROR_HARDWARE_UNSUPPORTED = ERROR_UNSUPPORTED;
- /** The hardware returned an error. */
+
+ /**
+ * There was a hardware error.
+ */
public static final int ERROR_HARDWARE_ERROR = -31;
- /** The limitation of resource is reached. */
+
+ /**
+ * Resources are insufficient (e.g. all hardware slots are in use).
+ */
public static final int ERROR_INSUFFICIENT_RESOURCES = -32;
+ /**
+ * There was no such slot. This should only be internally as it indicates
+ * a programming error in the system server. It should not propagate to
+ * applications.
+ * @hide
+ */
+ @SystemApi
+ public static final int ERROR_NO_SUCH_SLOT = -33;
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@@ -111,7 +157,8 @@ public abstract class SocketKeepalive implements AutoCloseable {
ERROR_INVALID_LENGTH,
ERROR_INVALID_INTERVAL,
ERROR_INVALID_SOCKET,
- ERROR_SOCKET_NOT_IDLE
+ ERROR_SOCKET_NOT_IDLE,
+ ERROR_NO_SUCH_SLOT
})
public @interface ErrorCode {}
@@ -122,7 +169,6 @@ public abstract class SocketKeepalive implements AutoCloseable {
ERROR_INVALID_LENGTH,
ERROR_UNSUPPORTED,
ERROR_INSUFFICIENT_RESOURCES,
- ERROR_HARDWARE_UNSUPPORTED
})
public @interface KeepaliveEvent {}
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index b7ce2a30931b..413e8e3a0727 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -122,7 +122,8 @@
<uses-permission android:name="android.permission.CREATE_USERS" />
<uses-permission android:name="android.permission.MANAGE_DEVICE_ADMINS" />
<uses-permission android:name="android.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS" />
- <uses-permission android:name="android.permission.QUERY_USERS" />
+ <uses-permission android:name="android.permission.FORCE_DEVICE_POLICY_MANAGER_LOGS" />
+ <uses-permission android:name="android.permission.CLEAR_FREEZE_PERIOD" />
<uses-permission android:name="android.permission.MODIFY_QUIET_MODE" />
<uses-permission android:name="android.permission.ACCESS_LOWPAN_STATE"/>
<uses-permission android:name="android.permission.CHANGE_LOWPAN_STATE"/>
@@ -182,6 +183,7 @@
<uses-permission android:name="android.permission.SET_HARMFUL_APP_WARNINGS" />
<uses-permission android:name="android.permission.MANAGE_SENSORS" />
<uses-permission android:name="android.permission.MANAGE_AUDIO_POLICY" />
+ <uses-permission android:name="android.permission.QUERY_AUDIO_STATE" />
<uses-permission android:name="android.permission.MANAGE_CAMERA" />
<!-- Permissions needed to test system only camera devices -->
<uses-permission android:name="android.permission.CAMERA" />
@@ -230,6 +232,9 @@
<!-- Permission needed to run keyguard manager tests in CTS -->
<uses-permission android:name="android.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS" />
+ <!-- Permission needed to set/clear/verify lockscreen credentials in CTS tests -->
+ <uses-permission android:name="android.permission.SET_AND_VERIFY_LOCKSCREEN_CREDENTIALS" />
+
<!-- Permission needed to test wallpaper component -->
<uses-permission android:name="android.permission.SET_WALLPAPER" />
<uses-permission android:name="android.permission.SET_WALLPAPER_COMPONENT" />
diff --git a/packages/SystemUI/OWNERS b/packages/SystemUI/OWNERS
index f884270eaba8..835471d5cb94 100644
--- a/packages/SystemUI/OWNERS
+++ b/packages/SystemUI/OWNERS
@@ -9,6 +9,7 @@ asc@google.com
awickham@google.com
beverlyt@google.com
brockman@google.com
+ccassidy@google.com
cinek@google.com
cwren@google.com
dupin@google.com
@@ -19,10 +20,10 @@ hwwang@google.com
hyunyoungs@google.com
jaggies@google.com
jamesoleary@google.com
+jdemeulenaere@google.com
jeffdq@google.com
jjaggi@google.com
jonmiranda@google.com
-joshmcgrath@google.com
joshtrask@google.com
juliacr@google.com
juliatuttle@google.com
@@ -37,7 +38,6 @@ mkephart@google.com
mpietal@google.com
mrcasey@google.com
mrenouf@google.com
-nbenbernou@google.com
nesciosquid@google.com
ogunwale@google.com
peanutbutter@google.com
@@ -45,6 +45,7 @@ pinyaoting@google.com
pixel@google.com
roosa@google.com
santie@google.com
+shanh@google.com
snoeberger@google.com
sreyasr@google.com
steell@google.com
@@ -59,6 +60,7 @@ twickham@google.com
vadimt@google.com
victortulias@google.com
winsonc@google.com
+yurilin@google.com
xuqiu@google.com
zakcohen@google.com
diff --git a/packages/VpnDialogs/res/values/strings.xml b/packages/VpnDialogs/res/values/strings.xml
index 443a9bc33b90..f971a0916837 100644
--- a/packages/VpnDialogs/res/values/strings.xml
+++ b/packages/VpnDialogs/res/values/strings.xml
@@ -28,6 +28,17 @@
]]> appears at the top of your screen when VPN is active.
</string>
+ <!-- TV specific dialog message to warn about the risk of using a VPN application. [CHAR LIMIT=NONE] -->
+ <string name="warning" product="tv">
+ <xliff:g id="app">%s</xliff:g> wants to set up a VPN connection
+ that allows it to monitor network traffic. Only accept if you trust the source.
+ <![CDATA[
+ <br />
+ <br />
+ <img src="vpn_icon" />
+ ]]> appears on your screen when VPN is active.
+ </string>
+
<!-- Dialog title for built-in VPN. [CHAR LIMIT=40] -->
<string name="legacy_title">VPN is connected</string>
<!-- Label for the name of the current VPN session. [CHAR LIMIT=20] -->
diff --git a/services/api/current.txt b/services/api/current.txt
index 17ca369c62ab..7c5c01ef6868 100644
--- a/services/api/current.txt
+++ b/services/api/current.txt
@@ -80,6 +80,14 @@ package com.android.server {
}
+package com.android.server.stats {
+
+ public final class StatsHelper {
+ method public static void sendStatsdReadyBroadcast(@NonNull android.content.Context);
+ }
+
+}
+
package com.android.server.wifi {
public class SupplicantManager {
diff --git a/services/api/non-updatable-current.txt b/services/api/non-updatable-current.txt
index 647739f34cf2..6419b7088fdb 100644
--- a/services/api/non-updatable-current.txt
+++ b/services/api/non-updatable-current.txt
@@ -35,6 +35,14 @@ package com.android.server {
}
+package com.android.server.stats {
+
+ public final class StatsHelper {
+ method public static void sendStatsdReadyBroadcast(@NonNull android.content.Context);
+ }
+
+}
+
package com.android.server.wifi {
public class SupplicantManager {
diff --git a/services/core/Android.bp b/services/core/Android.bp
index c40afbfe4f97..0ac8f74ff831 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -210,6 +210,7 @@ filegroup {
"java/com/android/server/connectivity/AutodestructReference.java",
"java/com/android/server/connectivity/ConnectivityConstants.java",
"java/com/android/server/connectivity/DnsManager.java",
+ "java/com/android/server/connectivity/FullScore.java",
"java/com/android/server/connectivity/KeepaliveTracker.java",
"java/com/android/server/connectivity/LingerMonitor.java",
"java/com/android/server/connectivity/MockableSystemProperties.java",
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 6fcb3f74c757..e3ce7a31b97e 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -30,6 +30,9 @@ import static android.net.ConnectivityDiagnosticsManager.DataStallReport.DETECTI
import static android.net.ConnectivityDiagnosticsManager.DataStallReport.KEY_DNS_CONSECUTIVE_TIMEOUTS;
import static android.net.ConnectivityDiagnosticsManager.DataStallReport.KEY_TCP_METRICS_COLLECTION_PERIOD_MILLIS;
import static android.net.ConnectivityDiagnosticsManager.DataStallReport.KEY_TCP_PACKET_FAIL_RATE;
+import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_MASK;
+import static android.net.ConnectivityManager.BLOCKED_REASON_LOCKDOWN_VPN;
+import static android.net.ConnectivityManager.BLOCKED_REASON_NONE;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC;
import static android.net.ConnectivityManager.TYPE_BLUETOOTH;
@@ -75,7 +78,6 @@ import static android.net.NetworkCapabilities.REDACT_FOR_NETWORK_SETTINGS;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_TEST;
import static android.net.NetworkCapabilities.TRANSPORT_VPN;
-import static android.net.NetworkPolicyManager.BLOCKED_REASON_NONE;
import static android.net.NetworkPolicyManager.blockedReasonsToString;
import static android.net.NetworkRequest.Type.LISTEN_FOR_BEST;
import static android.net.shared.NetworkMonitorUtils.isPrivateDnsValidationRequired;
@@ -108,6 +110,7 @@ import android.net.ConnectionInfo;
import android.net.ConnectivityDiagnosticsManager.ConnectivityReport;
import android.net.ConnectivityDiagnosticsManager.DataStallReport;
import android.net.ConnectivityManager;
+import android.net.ConnectivityManager.BlockedReason;
import android.net.ConnectivityManager.NetworkCallback;
import android.net.ConnectivityManager.RestrictBackgroundStatus;
import android.net.ConnectivityResources;
@@ -315,6 +318,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
// The maximum number of network request allowed per uid before an exception is thrown.
private static final int MAX_NETWORK_REQUESTS_PER_UID = 100;
+ // The maximum number of network request allowed for system UIDs before an exception is thrown.
+ private static final int MAX_NETWORK_REQUESTS_PER_SYSTEM_UID = 250;
+
@VisibleForTesting
protected int mLingerDelayMs; // Can't be final, or test subclass constructors can't change it.
@VisibleForTesting
@@ -330,6 +336,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
protected final PermissionMonitor mPermissionMonitor;
private final PerUidCounter mNetworkRequestCounter;
+ private final PerUidCounter mSystemNetworkRequestCounter;
private volatile boolean mLockdownEnabled;
@@ -1146,8 +1153,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
/**
* @see NetworkUtils#queryUserAccess(int, int)
*/
- public boolean queryUserAccess(int uid, int netId) {
- return NetworkUtils.queryUserAccess(uid, netId);
+ public boolean queryUserAccess(int uid, Network network, ConnectivityService cs) {
+ return cs.queryUserAccess(uid, network);
}
/**
@@ -1198,12 +1205,13 @@ public class ConnectivityService extends IConnectivityManager.Stub
mContext = Objects.requireNonNull(context, "missing Context");
mResources = deps.getResources(mContext);
mNetworkRequestCounter = new PerUidCounter(MAX_NETWORK_REQUESTS_PER_UID);
+ mSystemNetworkRequestCounter = new PerUidCounter(MAX_NETWORK_REQUESTS_PER_SYSTEM_UID);
mMetricsLog = logger;
mNetworkRanker = new NetworkRanker();
final NetworkRequest defaultInternetRequest = createDefaultRequest();
mDefaultRequest = new NetworkRequestInfo(
- defaultInternetRequest, null,
+ Process.myUid(), defaultInternetRequest, null,
new Binder(), NetworkCallback.FLAG_INCLUDE_LOCATION_INFO,
null /* attributionTags */);
mNetworkRequests.put(defaultInternetRequest, mDefaultRequest);
@@ -1410,8 +1418,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (enable) {
handleRegisterNetworkRequest(new NetworkRequestInfo(
- networkRequest, null,
- new Binder(),
+ Process.myUid(), networkRequest, null, new Binder(),
NetworkCallback.FLAG_INCLUDE_LOCATION_INFO,
null /* attributionTags */));
} else {
@@ -1549,16 +1556,16 @@ public class ConnectivityService extends IConnectivityManager.Stub
mNetworkInfoBlockingLogs.log(action + " " + uid);
}
- private void maybeLogBlockedStatusChanged(NetworkRequestInfo nri, Network net,
- boolean blocked) {
+ private void maybeLogBlockedStatusChanged(NetworkRequestInfo nri, Network net, int blocked) {
if (nri == null || net == null || !LOGD_BLOCKED_NETWORKINFO) {
return;
}
- final String action = blocked ? "BLOCKED" : "UNBLOCKED";
+ final String action = (blocked != 0) ? "BLOCKED" : "UNBLOCKED";
final int requestId = nri.getActiveRequest() != null
? nri.getActiveRequest().requestId : nri.mRequests.get(0).requestId;
mNetworkInfoBlockingLogs.log(String.format(
- "%s %d(%d) on netId %d", action, nri.mUid, requestId, net.getNetId()));
+ "%s %d(%d) on netId %d: %s", action, nri.mAsUid, requestId, net.getNetId(),
+ blockedReasonsToString(blocked)));
}
/**
@@ -2073,6 +2080,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
private void restrictRequestUidsForCallerAndSetRequestorInfo(NetworkCapabilities nc,
int callerUid, String callerPackageName) {
if (!checkSettingsPermission()) {
+ // There is no need to track the effective UID of the request here. If the caller lacks
+ // the settings permission, the effective UID is the same as the calling ID.
nc.setSingleUid(callerUid);
}
nc.setRequestorUidAndPackageName(callerUid, callerPackageName);
@@ -2337,15 +2346,15 @@ public class ConnectivityService extends IConnectivityManager.Stub
private final NetworkPolicyCallback mPolicyCallback = new NetworkPolicyCallback() {
@Override
- public void onUidBlockedReasonChanged(int uid, int blockedReasons) {
+ public void onUidBlockedReasonChanged(int uid, @BlockedReason int blockedReasons) {
mHandler.sendMessage(mHandler.obtainMessage(EVENT_UID_BLOCKED_REASON_CHANGED,
uid, blockedReasons));
}
};
- void handleUidBlockedReasonChanged(int uid, int blockedReasons) {
+ private void handleUidBlockedReasonChanged(int uid, @BlockedReason int blockedReasons) {
maybeNotifyNetworkBlockedForNewState(uid, blockedReasons);
- mUidBlockedReasons.put(uid, blockedReasons);
+ setUidBlockedReasons(uid, blockedReasons);
}
private boolean checkAnyPermissionOf(String... permissions) {
@@ -3118,6 +3127,13 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
break;
}
+ case NetworkAgent.EVENT_TEARDOWN_DELAY_CHANGED: {
+ if (msg.arg1 >= 0 && msg.arg1 <= NetworkAgent.MAX_TEARDOWN_DELAY_MS) {
+ nai.teardownDelayMs = msg.arg1;
+ } else {
+ logwtf(nai.toShortString() + " set invalid teardown delay " + msg.arg1);
+ }
+ }
}
}
@@ -3688,6 +3704,23 @@ public class ConnectivityService extends IConnectivityManager.Stub
mLegacyTypeTracker.remove(nai, wasDefault);
rematchAllNetworksAndRequests();
mLingerMonitor.noteDisconnect(nai);
+
+ // Immediate teardown.
+ if (nai.teardownDelayMs == 0) {
+ destroyNetwork(nai);
+ return;
+ }
+
+ // Delayed teardown.
+ try {
+ mNetd.networkSetPermissionForNetwork(nai.network.netId, INetd.PERMISSION_SYSTEM);
+ } catch (RemoteException e) {
+ Log.d(TAG, "Error marking network restricted during teardown: " + e);
+ }
+ mHandler.postDelayed(() -> destroyNetwork(nai), nai.teardownDelayMs);
+ }
+
+ private void destroyNetwork(NetworkAgentInfo nai) {
if (nai.created) {
// Tell netd to clean up the configuration for this network
// (routing rules, DNS, etc).
@@ -3700,6 +3733,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
mDnsManager.removeNetwork(nai.network);
}
mNetIdManager.releaseNetId(nai.network.getNetId());
+ nai.onNetworkDestroyed();
}
private boolean createNativeNetwork(@NonNull NetworkAgentInfo networkAgent) {
@@ -4000,7 +4034,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
}
}
- mNetworkRequestCounter.decrementCount(nri.mUid);
+ decrementRequestCount(nri);
mNetworkRequestInfoLogs.log("RELEASE " + nri);
if (null != nri.getActiveRequest()) {
@@ -4111,6 +4145,20 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
}
+ private PerUidCounter getRequestCounter(NetworkRequestInfo nri) {
+ return checkAnyPermissionOf(
+ nri.mPid, nri.mUid, NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK)
+ ? mSystemNetworkRequestCounter : mNetworkRequestCounter;
+ }
+
+ private void incrementRequestCountOrThrow(NetworkRequestInfo nri) {
+ getRequestCounter(nri).incrementCountOrThrow(nri.mUid);
+ }
+
+ private void decrementRequestCount(NetworkRequestInfo nri) {
+ getRequestCounter(nri).decrementCount(nri.mUid);
+ }
+
@Override
public void setAcceptUnvalidated(Network network, boolean accept, boolean always) {
enforceNetworkStackSettingsOrSetup();
@@ -4838,6 +4886,42 @@ public class ConnectivityService extends IConnectivityManager.Stub
nai.networkMonitor().forceReevaluation(uid);
}
+ // TODO: call into netd.
+ private boolean queryUserAccess(int uid, Network network) {
+ final NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);
+ if (nai == null) return false;
+
+ // Any UID can use its default network.
+ if (nai == getDefaultNetworkForUid(uid)) return true;
+
+ // Privileged apps can use any network.
+ if (mPermissionMonitor.hasRestrictedNetworksPermission(uid)) {
+ return true;
+ }
+
+ // An unprivileged UID can use a VPN iff the VPN applies to it.
+ if (nai.isVPN()) {
+ return nai.networkCapabilities.appliesToUid(uid);
+ }
+
+ // An unprivileged UID can bypass the VPN that applies to it only if it can protect its
+ // sockets, i.e., if it is the owner.
+ final NetworkAgentInfo vpn = getVpnForUid(uid);
+ if (vpn != null && !vpn.networkAgentConfig.allowBypass
+ && uid != vpn.networkCapabilities.getOwnerUid()) {
+ return false;
+ }
+
+ // The UID's permission must be at least sufficient for the network. Since the restricted
+ // permission was already checked above, that just leaves background networks.
+ if (!nai.networkCapabilities.hasCapability(NET_CAPABILITY_FOREGROUND)) {
+ return mPermissionMonitor.hasUseBackgroundNetworksPermission(uid);
+ }
+
+ // Unrestricted network. Anyone gets to use it.
+ return true;
+ }
+
/**
* Returns information about the proxy a certain network is using. If given a null network, it
* it will return the proxy for the bound network for the caller app or the default proxy if
@@ -4858,7 +4942,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
return null;
}
return getLinkPropertiesProxyInfo(activeNetwork);
- } else if (mDeps.queryUserAccess(mDeps.getCallingUid(), network.getNetId())) {
+ } else if (mDeps.queryUserAccess(mDeps.getCallingUid(), network, this)) {
// Don't call getLinkProperties() as it requires ACCESS_NETWORK_STATE permission, which
// caller may not have.
return getLinkPropertiesProxyInfo(network);
@@ -5085,7 +5169,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
@Override
public void setRequireVpnForUids(boolean requireVpn, UidRange[] ranges) {
- PermissionUtils.enforceNetworkStackPermission(mContext);
+ enforceNetworkStackOrSettingsPermission();
mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_REQUIRE_VPN_FOR_UIDS,
encodeBool(requireVpn), 0 /* arg2 */, ranges));
}
@@ -5123,7 +5207,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
@Override
public void setLegacyLockdownVpnEnabled(boolean enabled) {
- enforceSettingsPermission();
+ enforceNetworkStackOrSettingsPermission();
mHandler.post(() -> mLockdownEnabled = enabled);
}
@@ -5363,6 +5447,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
boolean mPendingIntentSent;
@Nullable
final Messenger mMessenger;
+
+ // Information about the caller that caused this object to be created.
@Nullable
private final IBinder mBinder;
final int mPid;
@@ -5370,6 +5456,13 @@ public class ConnectivityService extends IConnectivityManager.Stub
final @NetworkCallback.Flag int mCallbackFlags;
@Nullable
final String mCallingAttributionTag;
+
+ // Effective UID of this request. This is different from mUid when a privileged process
+ // files a request on behalf of another UID. This UID is used to determine blocked status,
+ // UID matching, and so on. mUid above is used for permission checks and to enforce the
+ // maximum limit of registered callbacks per UID.
+ final int mAsUid;
+
// In order to preserve the mapping of NetworkRequest-to-callback when apps register
// callbacks using a returned NetworkRequest, the original NetworkRequest needs to be
// maintained for keying off of. This is only a concern when the original nri
@@ -5397,12 +5490,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
return (null == uids) ? new ArraySet<>() : uids;
}
- NetworkRequestInfo(@NonNull final NetworkRequest r, @Nullable final PendingIntent pi,
- @Nullable String callingAttributionTag) {
- this(Collections.singletonList(r), r, pi, callingAttributionTag);
+ NetworkRequestInfo(int asUid, @NonNull final NetworkRequest r,
+ @Nullable final PendingIntent pi, @Nullable String callingAttributionTag) {
+ this(asUid, Collections.singletonList(r), r, pi, callingAttributionTag);
}
- NetworkRequestInfo(@NonNull final List<NetworkRequest> r,
+ NetworkRequestInfo(int asUid, @NonNull final List<NetworkRequest> r,
@NonNull final NetworkRequest requestForCallback, @Nullable final PendingIntent pi,
@Nullable String callingAttributionTag) {
ensureAllNetworkRequestsHaveType(r);
@@ -5413,7 +5506,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
mBinder = null;
mPid = getCallingPid();
mUid = mDeps.getCallingUid();
- mNetworkRequestCounter.incrementCountOrThrow(mUid);
+ mAsUid = asUid;
+ incrementRequestCountOrThrow(this);
/**
* Location sensitive data not included in pending intent. Only included in
* {@link NetworkCallback}.
@@ -5422,14 +5516,15 @@ public class ConnectivityService extends IConnectivityManager.Stub
mCallingAttributionTag = callingAttributionTag;
}
- NetworkRequestInfo(@NonNull final NetworkRequest r, @Nullable final Messenger m,
+ NetworkRequestInfo(int asUid, @NonNull final NetworkRequest r, @Nullable final Messenger m,
@Nullable final IBinder binder,
@NetworkCallback.Flag int callbackFlags,
@Nullable String callingAttributionTag) {
- this(Collections.singletonList(r), r, m, binder, callbackFlags, callingAttributionTag);
+ this(asUid, Collections.singletonList(r), r, m, binder, callbackFlags,
+ callingAttributionTag);
}
- NetworkRequestInfo(@NonNull final List<NetworkRequest> r,
+ NetworkRequestInfo(int asUid, @NonNull final List<NetworkRequest> r,
@NonNull final NetworkRequest requestForCallback, @Nullable final Messenger m,
@Nullable final IBinder binder,
@NetworkCallback.Flag int callbackFlags,
@@ -5442,8 +5537,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
mBinder = binder;
mPid = getCallingPid();
mUid = mDeps.getCallingUid();
+ mAsUid = asUid;
mPendingIntent = null;
- mNetworkRequestCounter.incrementCountOrThrow(mUid);
+ incrementRequestCountOrThrow(this);
mCallbackFlags = callbackFlags;
mCallingAttributionTag = callingAttributionTag;
@@ -5484,18 +5580,19 @@ public class ConnectivityService extends IConnectivityManager.Stub
mBinder = nri.mBinder;
mPid = nri.mPid;
mUid = nri.mUid;
+ mAsUid = nri.mAsUid;
mPendingIntent = nri.mPendingIntent;
- mNetworkRequestCounter.incrementCountOrThrow(mUid);
+ incrementRequestCountOrThrow(this);
mCallbackFlags = nri.mCallbackFlags;
mCallingAttributionTag = nri.mCallingAttributionTag;
}
- NetworkRequestInfo(@NonNull final NetworkRequest r) {
- this(Collections.singletonList(r));
+ NetworkRequestInfo(int asUid, @NonNull final NetworkRequest r) {
+ this(asUid, Collections.singletonList(r));
}
- NetworkRequestInfo(@NonNull final List<NetworkRequest> r) {
- this(r, r.get(0), null /* pi */, null /* callingAttributionTag */);
+ NetworkRequestInfo(int asUid, @NonNull final List<NetworkRequest> r) {
+ this(asUid, r, r.get(0), null /* pi */, null /* callingAttributionTag */);
}
// True if this NRI is being satisfied. It also accounts for if the nri has its satisifer
@@ -5531,9 +5628,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
@Override
public String toString() {
- return "uid/pid:" + mUid + "/" + mPid + " active request Id: "
+ final String asUidString = (mAsUid == mUid) ? "" : " asUid: " + mAsUid;
+ return "uid/pid:" + mUid + "/" + mPid + asUidString + " activeRequest: "
+ (mActiveRequest == null ? null : mActiveRequest.requestId)
- + " callback request Id: "
+ + " callbackRequest: "
+ mNetworkRequestForCallback.requestId
+ " " + mRequests
+ (mPendingIntent == null ? "" : " to trigger " + mPendingIntent)
@@ -5634,7 +5732,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
@Override
- public NetworkRequest requestNetwork(NetworkCapabilities networkCapabilities,
+ public NetworkRequest requestNetwork(int asUid, NetworkCapabilities networkCapabilities,
int reqTypeInt, Messenger messenger, int timeoutMs, IBinder binder,
int legacyType, int callbackFlags, @NonNull String callingPackageName,
@Nullable String callingAttributionTag) {
@@ -5646,6 +5744,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
final NetworkCapabilities defaultNc = mDefaultRequest.mRequests.get(0).networkCapabilities;
final int callingUid = mDeps.getCallingUid();
+ // Privileged callers can track the default network of another UID by passing in a UID.
+ if (asUid != Process.INVALID_UID) {
+ enforceSettingsPermission();
+ } else {
+ asUid = callingUid;
+ }
final NetworkRequest.Type reqType;
try {
reqType = NetworkRequest.Type.values()[reqTypeInt];
@@ -5655,10 +5759,10 @@ 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 ones appropriate for the caller.
- // This allows callers to keep track of the default network for their app.
+ // is unused and will be replaced by ones appropriate for the UID (usually, the
+ // calling app). This allows callers to keep track of the default network.
networkCapabilities = copyDefaultNetworkCapabilitiesForUid(
- defaultNc, callingUid, callingPackageName);
+ defaultNc, asUid, callingUid, callingPackageName);
enforceAccessPermission();
break;
case TRACK_SYSTEM_DEFAULT:
@@ -5710,7 +5814,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
final NetworkRequest networkRequest = new NetworkRequest(networkCapabilities, legacyType,
nextNetworkRequestId(), reqType);
final NetworkRequestInfo nri = getNriToRegister(
- networkRequest, messenger, binder, callbackFlags, callingAttributionTag);
+ asUid, networkRequest, messenger, binder, callbackFlags,
+ callingAttributionTag);
if (DBG) log("requestNetwork for " + nri);
// For TRACK_SYSTEM_DEFAULT callbacks, the capabilities have been modified since they were
@@ -5737,25 +5842,27 @@ public class ConnectivityService extends IConnectivityManager.Stub
* requests registered to track the default request. If there is currently a per-app default
* tracking the app requestor, then we need to create a version of this nri that mirrors that of
* the tracking per-app default so that callbacks are sent to the app requestor appropriately.
+ * @param asUid the uid on behalf of which to file the request. Different from requestorUid
+ * when a privileged caller is tracking the default network for another uid.
* @param nr the network request for the nri.
* @param msgr the messenger for the nri.
* @param binder the binder for the nri.
* @param callingAttributionTag the calling attribution tag for the nri.
* @return the nri to register.
*/
- private NetworkRequestInfo getNriToRegister(@NonNull final NetworkRequest nr,
+ private NetworkRequestInfo getNriToRegister(final int asUid, @NonNull final NetworkRequest nr,
@Nullable final Messenger msgr, @Nullable final IBinder binder,
@NetworkCallback.Flag int callbackFlags,
@Nullable String callingAttributionTag) {
final List<NetworkRequest> requests;
if (NetworkRequest.Type.TRACK_DEFAULT == nr.type) {
requests = copyDefaultNetworkRequestsForUid(
- nr.getRequestorUid(), nr.getRequestorPackageName());
+ asUid, nr.getRequestorUid(), nr.getRequestorPackageName());
} else {
requests = Collections.singletonList(nr);
}
return new NetworkRequestInfo(
- requests, nr, msgr, binder, callbackFlags, callingAttributionTag);
+ asUid, requests, nr, msgr, binder, callbackFlags, callingAttributionTag);
}
private void enforceNetworkRequestPermissions(NetworkCapabilities networkCapabilities,
@@ -5836,8 +5943,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
NetworkRequest networkRequest = new NetworkRequest(networkCapabilities, TYPE_NONE,
nextNetworkRequestId(), NetworkRequest.Type.REQUEST);
- NetworkRequestInfo nri =
- new NetworkRequestInfo(networkRequest, operation, callingAttributionTag);
+ NetworkRequestInfo nri = new NetworkRequestInfo(callingUid, networkRequest, operation,
+ callingAttributionTag);
if (DBG) log("pendingRequest for " + nri);
mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_REQUEST_WITH_INTENT,
nri));
@@ -5904,7 +6011,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
NetworkRequest networkRequest = new NetworkRequest(nc, TYPE_NONE, nextNetworkRequestId(),
NetworkRequest.Type.LISTEN);
NetworkRequestInfo nri =
- new NetworkRequestInfo(networkRequest, messenger, binder, callbackFlags,
+ new NetworkRequestInfo(callingUid, networkRequest, messenger, binder, callbackFlags,
callingAttributionTag);
if (VDBG) log("listenForNetwork for " + nri);
@@ -5929,8 +6036,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
NetworkRequest networkRequest = new NetworkRequest(nc, TYPE_NONE, nextNetworkRequestId(),
NetworkRequest.Type.LISTEN);
- NetworkRequestInfo nri =
- new NetworkRequestInfo(networkRequest, operation, callingAttributionTag);
+ NetworkRequestInfo nri = new NetworkRequestInfo(callingUid, networkRequest, operation,
+ callingAttributionTag);
if (VDBG) log("pendingListenForNetwork for " + nri);
mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_LISTENER, nri));
@@ -6080,33 +6187,37 @@ public class ConnectivityService extends IConnectivityManager.Stub
/**
* Get a copy of the network requests of the default request that is currently tracking the
* given uid.
+ * @param asUid the uid on behalf of which to file the request. Different from requestorUid
+ * when a privileged caller is tracking the default network for another uid.
* @param requestorUid the uid to check the default for.
* @param requestorPackageName the requestor's package name.
* @return a copy of the default's NetworkRequest that is tracking the given uid.
*/
@NonNull
private List<NetworkRequest> copyDefaultNetworkRequestsForUid(
- @NonNull final int requestorUid, @NonNull final String requestorPackageName) {
+ final int asUid, final int requestorUid, @NonNull final String requestorPackageName) {
return copyNetworkRequestsForUid(
- getDefaultRequestTrackingUid(requestorUid).mRequests,
- requestorUid, requestorPackageName);
+ getDefaultRequestTrackingUid(asUid).mRequests,
+ asUid, requestorUid, requestorPackageName);
}
/**
* Copy the given nri's NetworkRequest collection.
* @param requestsToCopy the NetworkRequest collection to be copied.
+ * @param asUid the uid on behalf of which to file the request. Different from requestorUid
+ * when a privileged caller is tracking the default network for another uid.
* @param requestorUid the uid to set on the copied collection.
* @param requestorPackageName the package name to set on the copied collection.
* @return the copied NetworkRequest collection.
*/
@NonNull
private List<NetworkRequest> copyNetworkRequestsForUid(
- @NonNull final List<NetworkRequest> requestsToCopy, @NonNull final int requestorUid,
- @NonNull final String requestorPackageName) {
+ @NonNull final List<NetworkRequest> requestsToCopy, final int asUid,
+ final int requestorUid, @NonNull final String requestorPackageName) {
final List<NetworkRequest> requests = new ArrayList<>();
for (final NetworkRequest nr : requestsToCopy) {
requests.add(new NetworkRequest(copyDefaultNetworkCapabilitiesForUid(
- nr.networkCapabilities, requestorUid, requestorPackageName),
+ nr.networkCapabilities, asUid, requestorUid, requestorPackageName),
nr.legacyType, nextNetworkRequestId(), nr.type));
}
return requests;
@@ -6114,17 +6225,17 @@ public class ConnectivityService extends IConnectivityManager.Stub
@NonNull
private NetworkCapabilities copyDefaultNetworkCapabilitiesForUid(
- @NonNull final NetworkCapabilities netCapToCopy, @NonNull final int requestorUid,
- @NonNull final String requestorPackageName) {
+ @NonNull final NetworkCapabilities netCapToCopy, final int asUid,
+ final int requestorUid, @NonNull final String requestorPackageName) {
// These capabilities are for a TRACK_DEFAULT callback, so:
// 1. Remove NET_CAPABILITY_VPN, because it's (currently!) the only difference between
// mDefaultRequest and a per-UID default request.
// TODO: stop depending on the fact that these two unrelated things happen to be the same
- // 2. Always set the UIDs to mAsUid. restrictRequestUidsForCallerAndSetRequestorInfo will
+ // 2. Always set the UIDs to asUid. restrictRequestUidsForCallerAndSetRequestorInfo will
// not do this in the case of a privileged application.
final NetworkCapabilities netCap = new NetworkCapabilities(netCapToCopy);
netCap.removeCapability(NET_CAPABILITY_NOT_VPN);
- netCap.setSingleUid(requestorUid);
+ netCap.setSingleUid(asUid);
restrictRequestUidsForCallerAndSetRequestorInfo(
netCap, requestorUid, requestorPackageName);
return netCap;
@@ -6185,8 +6296,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
// Request used to optionally keep vehicle internal network always active
private final NetworkRequest mDefaultVehicleRequest;
- // TODO replace with INetd.DUMMY_NET_ID when available.
- private static final int NO_SERVICE_NET_ID = 51;
+ // TODO replace with INetd.UNREACHABLE_NET_ID when available.
+ private static final int NO_SERVICE_NET_ID = 52;
// Sentinel NAI used to direct apps with default networks that should have no connectivity to a
// network with no service. This NAI should never be matched against, nor should any public API
// ever return the associated network. For this reason, this NAI is not in the list of available
@@ -7280,7 +7391,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
break;
}
case ConnectivityManager.CALLBACK_BLK_CHANGED: {
- maybeLogBlockedStatusChanged(nri, networkAgent.network, arg1 != 0);
+ maybeLogBlockedStatusChanged(nri, networkAgent.network, arg1);
msg.arg1 = arg1;
break;
}
@@ -7936,6 +8047,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
updateCapabilitiesForNetwork(networkAgent);
}
networkAgent.created = true;
+ networkAgent.onNetworkCreated();
}
if (!networkAgent.everConnected && state == NetworkInfo.State.CONNECTED) {
@@ -8023,12 +8135,11 @@ public class ConnectivityService extends IConnectivityManager.Stub
return;
}
+ final int blockedReasons = mUidBlockedReasons.get(nri.mAsUid, BLOCKED_REASON_NONE);
final boolean metered = nai.networkCapabilities.isMetered();
- boolean blocked;
- blocked = isUidBlockedByVpn(nri.mUid, mVpnBlockedUidRanges);
- blocked |= NetworkPolicyManager.isUidBlocked(
- mUidBlockedReasons.get(nri.mUid, BLOCKED_REASON_NONE), metered);
- callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_AVAILABLE, blocked ? 1 : 0);
+ final boolean vpnBlocked = isUidBlockedByVpn(nri.mAsUid, mVpnBlockedUidRanges);
+ callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_AVAILABLE,
+ getBlockedState(blockedReasons, metered, vpnBlocked));
}
// Notify the requests on this NAI that the network is now lingered.
@@ -8037,6 +8148,21 @@ public class ConnectivityService extends IConnectivityManager.Stub
notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_LOSING, lingerTime);
}
+ private static int getBlockedState(int reasons, boolean metered, boolean vpnBlocked) {
+ if (!metered) reasons &= ~BLOCKED_METERED_REASON_MASK;
+ return vpnBlocked
+ ? reasons | BLOCKED_REASON_LOCKDOWN_VPN
+ : reasons & ~BLOCKED_REASON_LOCKDOWN_VPN;
+ }
+
+ private void setUidBlockedReasons(int uid, @BlockedReason int blockedReasons) {
+ if (blockedReasons == BLOCKED_REASON_NONE) {
+ mUidBlockedReasons.delete(uid);
+ } else {
+ mUidBlockedReasons.put(uid, blockedReasons);
+ }
+ }
+
/**
* Notify of the blocked state apps with a registered callback matching a given NAI.
*
@@ -8044,7 +8170,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
* any given nai, all requests need to be considered according to the uid who filed it.
*
* @param nai The target NetworkAgentInfo.
- * @param oldMetered True if the previous network capabilities is metered.
+ * @param oldMetered True if the previous network capabilities were metered.
+ * @param newMetered True if the current network capabilities are metered.
+ * @param oldBlockedUidRanges list of UID ranges previously blocked by lockdown VPN.
+ * @param newBlockedUidRanges list of UID ranges blocked by lockdown VPN.
*/
private void maybeNotifyNetworkBlocked(NetworkAgentInfo nai, boolean oldMetered,
boolean newMetered, List<UidRange> oldBlockedUidRanges,
@@ -8053,22 +8182,18 @@ public class ConnectivityService extends IConnectivityManager.Stub
for (int i = 0; i < nai.numNetworkRequests(); i++) {
NetworkRequest nr = nai.requestAt(i);
NetworkRequestInfo nri = mNetworkRequests.get(nr);
- final boolean oldBlocked, newBlocked, oldVpnBlocked, newVpnBlocked;
- oldVpnBlocked = isUidBlockedByVpn(nri.mUid, oldBlockedUidRanges);
- newVpnBlocked = (oldBlockedUidRanges != newBlockedUidRanges)
- ? isUidBlockedByVpn(nri.mUid, newBlockedUidRanges)
+ final int blockedReasons = mUidBlockedReasons.get(nri.mAsUid, BLOCKED_REASON_NONE);
+ final boolean oldVpnBlocked = isUidBlockedByVpn(nri.mAsUid, oldBlockedUidRanges);
+ final boolean newVpnBlocked = (oldBlockedUidRanges != newBlockedUidRanges)
+ ? isUidBlockedByVpn(nri.mAsUid, newBlockedUidRanges)
: oldVpnBlocked;
- final int blockedReasons = mUidBlockedReasons.get(nri.mUid, BLOCKED_REASON_NONE);
- oldBlocked = oldVpnBlocked || NetworkPolicyManager.isUidBlocked(
- blockedReasons, oldMetered);
- newBlocked = newVpnBlocked || NetworkPolicyManager.isUidBlocked(
- blockedReasons, newMetered);
-
- if (oldBlocked != newBlocked) {
+ final int oldBlockedState = getBlockedState(blockedReasons, oldMetered, oldVpnBlocked);
+ final int newBlockedState = getBlockedState(blockedReasons, newMetered, newVpnBlocked);
+ if (oldBlockedState != newBlockedState) {
callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_BLK_CHANGED,
- encodeBool(newBlocked));
+ newBlockedState);
}
}
}
@@ -8078,25 +8203,23 @@ public class ConnectivityService extends IConnectivityManager.Stub
* @param uid The uid for which the rules changed.
* @param blockedReasons The reasons for why an uid is blocked.
*/
- private void maybeNotifyNetworkBlockedForNewState(int uid, int blockedReasons) {
+ private void maybeNotifyNetworkBlockedForNewState(int uid, @BlockedReason int blockedReasons) {
for (final NetworkAgentInfo nai : mNetworkAgentInfos) {
final boolean metered = nai.networkCapabilities.isMetered();
final boolean vpnBlocked = isUidBlockedByVpn(uid, mVpnBlockedUidRanges);
- final boolean oldBlocked, newBlocked;
- oldBlocked = vpnBlocked || NetworkPolicyManager.isUidBlocked(
- mUidBlockedReasons.get(uid, BLOCKED_REASON_NONE), metered);
- newBlocked = vpnBlocked || NetworkPolicyManager.isUidBlocked(
- blockedReasons, metered);
- if (oldBlocked == newBlocked) {
+ final int oldBlockedState = getBlockedState(
+ mUidBlockedReasons.get(uid, BLOCKED_REASON_NONE), metered, vpnBlocked);
+ final int newBlockedState = getBlockedState(blockedReasons, metered, vpnBlocked);
+ if (oldBlockedState == newBlockedState) {
continue;
}
- final int arg = encodeBool(newBlocked);
for (int i = 0; i < nai.numNetworkRequests(); i++) {
NetworkRequest nr = nai.requestAt(i);
NetworkRequestInfo nri = mNetworkRequests.get(nr);
- if (nri != null && nri.mUid == uid) {
- callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_BLK_CHANGED, arg);
+ if (nri != null && nri.mAsUid == uid) {
+ callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_BLK_CHANGED,
+ newBlockedState);
}
}
}
@@ -8644,7 +8767,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
// Decrement the reference count for this NetworkRequestInfo. The reference count is
// incremented when the NetworkRequestInfo is created as part of
// enforceRequestCountLimit().
- mNetworkRequestCounter.decrementCount(nri.mUid);
+ decrementRequestCount(nri);
return;
}
@@ -8710,7 +8833,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
// Decrement the reference count for this NetworkRequestInfo. The reference count is
// incremented when the NetworkRequestInfo is created as part of
// enforceRequestCountLimit().
- mNetworkRequestCounter.decrementCount(nri.mUid);
+ decrementRequestCount(nri);
iCb.unlinkToDeath(cbInfo, 0);
}
@@ -8860,7 +8983,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
// nri is not bound to the death of callback. Instead, callback.bindToDeath() is set in
// handleRegisterConnectivityDiagnosticsCallback(). nri will be cleaned up as part of the
// callback's binder death.
- final NetworkRequestInfo nri = new NetworkRequestInfo(requestWithId);
+ final NetworkRequestInfo nri = new NetworkRequestInfo(callingUid, requestWithId);
final ConnectivityDiagnosticsCallbackInfo cbInfo =
new ConnectivityDiagnosticsCallbackInfo(callback, nri, callingPackageName);
@@ -9344,7 +9467,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
nrs.add(createNetworkRequest(NetworkRequest.Type.REQUEST, pref.capabilities));
nrs.add(createDefaultRequest());
setNetworkRequestUids(nrs, UidRange.fromIntRanges(pref.capabilities.getUids()));
- final NetworkRequestInfo nri = new NetworkRequestInfo(nrs);
+ final NetworkRequestInfo nri = new NetworkRequestInfo(Process.myUid(), nrs);
result.add(nri);
}
return result;
@@ -9515,7 +9638,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
// Include this nri if it will be tracked by the new per-app default requests.
final boolean isNriGoingToBeTracked =
- getDefaultRequestTrackingUid(nri.mUid) != mDefaultRequest;
+ getDefaultRequestTrackingUid(nri.mAsUid) != mDefaultRequest;
if (isNriGoingToBeTracked) {
defaultCallbackRequests.add(nri);
}
@@ -9537,7 +9660,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
final ArraySet<NetworkRequestInfo> callbackRequestsToRegister = new ArraySet<>();
for (final NetworkRequestInfo callbackRequest : perAppCallbackRequestsForUpdate) {
final NetworkRequestInfo trackingNri =
- getDefaultRequestTrackingUid(callbackRequest.mUid);
+ getDefaultRequestTrackingUid(callbackRequest.mAsUid);
// If this nri is not being tracked, the change it back to an untracked nri.
if (trackingNri == mDefaultRequest) {
@@ -9547,12 +9670,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
continue;
}
- final String requestorPackageName =
- callbackRequest.mRequests.get(0).getRequestorPackageName();
+ final NetworkRequest request = callbackRequest.mRequests.get(0);
callbackRequestsToRegister.add(new NetworkRequestInfo(
callbackRequest,
copyNetworkRequestsForUid(
- trackingNri.mRequests, callbackRequest.mUid, requestorPackageName)));
+ trackingNri.mRequests, callbackRequest.mAsUid,
+ callbackRequest.mUid, request.getRequestorPackageName())));
}
return callbackRequestsToRegister;
}
@@ -9656,7 +9779,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
ranges.add(new UidRange(uid, uid));
}
setNetworkRequestUids(requests, ranges);
- return new NetworkRequestInfo(requests);
+ return new NetworkRequestInfo(Process.myUid(), requests);
}
private NetworkRequest createUnmeteredNetworkRequest() {
diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java
index 4c3c6ef21fc5..794cb9301d69 100644
--- a/services/core/java/com/android/server/IpSecService.java
+++ b/services/core/java/com/android/server/IpSecService.java
@@ -1651,7 +1651,7 @@ public class IpSecService extends IIpSecService.Stub {
c.getMode(),
c.getSourceAddress(),
c.getDestinationAddress(),
- (c.getNetwork() != null) ? c.getNetwork().netId : 0,
+ (c.getNetwork() != null) ? c.getNetwork().getNetId() : 0,
spiRecord.getSpi(),
c.getMarkValue(),
c.getMarkMask(),
diff --git a/services/core/java/com/android/server/PinnerService.java b/services/core/java/com/android/server/PinnerService.java
index 3148a6205871..1241b77798ff 100644
--- a/services/core/java/com/android/server/PinnerService.java
+++ b/services/core/java/com/android/server/PinnerService.java
@@ -270,18 +270,9 @@ public final class PinnerService extends SystemService {
* Handler for on start pinning message
*/
private void handlePinOnStart() {
- final String bootImage = SystemProperties.get("dalvik.vm.boot-image", "");
- String[] filesToPin = null;
- if (bootImage.endsWith("boot-image.prof")) {
- // Use the files listed for that specific boot image.
- // TODO: find a better way to know we're using the JIT zygote configuration.
- filesToPin = mContext.getResources().getStringArray(
- com.android.internal.R.array.config_jitzygoteBootImagePinnerServiceFiles);
- } else {
- // Files to pin come from the overlay and can be specified per-device config
- filesToPin = mContext.getResources().getStringArray(
- com.android.internal.R.array.config_defaultPinnerServiceFiles);
- }
+ // Files to pin come from the overlay and can be specified per-device config
+ String[] filesToPin = mContext.getResources().getStringArray(
+ com.android.internal.R.array.config_defaultPinnerServiceFiles);
// Continue trying to pin each file even if we fail to pin some of them
for (String fileToPin : filesToPin) {
PinnedFile pf = pinFile(fileToPin,
@@ -291,10 +282,32 @@ public final class PinnerService extends SystemService {
Slog.e(TAG, "Failed to pin file = " + fileToPin);
continue;
}
-
synchronized (this) {
mPinnedFiles.add(pf);
}
+ if (fileToPin.endsWith(".jar") | fileToPin.endsWith(".apk")) {
+ // Check whether the runtime has compilation artifacts to pin.
+ String arch = VMRuntime.getInstructionSet(Build.SUPPORTED_ABIS[0]);
+ String[] files = null;
+ try {
+ files = DexFile.getDexFileOutputPaths(fileToPin, arch);
+ } catch (IOException ioe) { }
+ if (files == null) {
+ continue;
+ }
+ for (String file : files) {
+ PinnedFile df = pinFile(file,
+ Integer.MAX_VALUE,
+ /*attemptPinIntrospection=*/false);
+ if (df == null) {
+ Slog.i(TAG, "Failed to pin ART file = " + file);
+ continue;
+ }
+ synchronized (this) {
+ mPinnedFiles.add(df);
+ }
+ }
+ }
}
}
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 78ffcbdaff4d..0affda4fd561 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -402,10 +402,15 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
switch (msg.what) {
case MSG_USER_SWITCHED: {
if (VDBG) log("MSG_USER_SWITCHED userId=" + msg.arg1);
- int numPhones = getTelephonyManager().getPhoneCount();
- for (int sub = 0; sub < numPhones; sub++) {
- TelephonyRegistry.this.notifyCellLocationForSubscriber(sub,
- mCellIdentity[sub]);
+ int numPhones = getTelephonyManager().getActiveModemCount();
+ for (int phoneId = 0; phoneId < numPhones; phoneId++) {
+ int[] subIds = SubscriptionManager.getSubId(phoneId);
+ int subId =
+ (subIds != null) && (subIds.length > 0)
+ ? subIds[0]
+ : SubscriptionManager.DEFAULT_SUBSCRIPTION_ID;
+ TelephonyRegistry.this.notifyCellLocationForSubscriber(
+ subId, mCellIdentity[phoneId], true /* hasUserSwitched */);
}
break;
}
@@ -1170,7 +1175,9 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
TelephonyCallback.EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED)) {
try {
r.callback.onPhysicalChannelConfigChanged(
- mPhysicalChannelConfigs);
+ shouldSanitizeLocationForPhysicalChannelConfig(r)
+ ? getLocationSanitizedConfigs(mPhysicalChannelConfigs)
+ : mPhysicalChannelConfigs);
} catch (RemoteException ex) {
remove(r.binder);
}
@@ -1877,20 +1884,20 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
@Override
- public void notifyCellLocation(CellIdentity cellLocation) {
- notifyCellLocationForSubscriber(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, cellLocation);
+ public void notifyCellLocationForSubscriber(int subId, CellIdentity cellIdentity) {
+ notifyCellLocationForSubscriber(subId, cellIdentity, false /* hasUserSwitched */);
}
- @Override
- public void notifyCellLocationForSubscriber(int subId, CellIdentity cellIdentity) {
- log("notifyCellLocationForSubscriber: subId=" + subId
- + " cellIdentity=" + cellIdentity);
+ private void notifyCellLocationForSubscriber(int subId, CellIdentity cellIdentity,
+ boolean hasUserSwitched) {
+ log("notifyCellLocationForSubscriber: subId=" + subId + " cellIdentity=" + cellIdentity);
if (!checkNotifyPermission("notifyCellLocation()")) {
return;
}
int phoneId = getPhoneIdFromSubId(subId);
synchronized (mRecords) {
- if (validatePhoneId(phoneId) && !Objects.equals(cellIdentity, mCellIdentity[phoneId])) {
+ if (validatePhoneId(phoneId)
+ && (hasUserSwitched || !Objects.equals(cellIdentity, mCellIdentity[phoneId]))) {
mCellIdentity[phoneId] = cellIdentity;
for (Record r : mRecords) {
if (validateEventAndUserLocked(
@@ -2371,8 +2378,10 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
return;
}
+ List<PhysicalChannelConfig> sanitizedConfigs = getLocationSanitizedConfigs(configs);
if (VDBG) {
- log("notifyPhysicalChannelConfig: subId=" + subId + " configs=" + configs);
+ log("notifyPhysicalChannelConfig: subId=" + subId + " configs=" + configs
+ + " sanitizedConfigs=" + sanitizedConfigs);
}
synchronized (mRecords) {
@@ -2385,11 +2394,14 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
&& idMatch(r.subId, subId, phoneId)) {
try {
if (DBG_LOC) {
- log("notifyPhysicalChannelConfig: "
- + "mPhysicalChannelConfigs="
- + configs + " r=" + r);
+ log("notifyPhysicalChannelConfig: mPhysicalChannelConfigs="
+ + (shouldSanitizeLocationForPhysicalChannelConfig(r)
+ ? sanitizedConfigs : configs)
+ + " r=" + r);
}
- r.callback.onPhysicalChannelConfigChanged(configs);
+ r.callback.onPhysicalChannelConfigChanged(
+ shouldSanitizeLocationForPhysicalChannelConfig(r)
+ ? sanitizedConfigs : configs);
} catch (RemoteException ex) {
mRemoveList.add(r.binder);
}
@@ -2400,6 +2412,25 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
}
}
+ private static boolean shouldSanitizeLocationForPhysicalChannelConfig(Record record) {
+ // Always redact location info from PhysicalChannelConfig if the registrant is from neither
+ // PHONE nor SYSTEM process. There is no user case that the registrant needs the location
+ // info (e.g. physicalCellId). This also remove the need for the location permissions check.
+ return record.callerUid != Process.PHONE_UID && record.callerUid != Process.SYSTEM_UID;
+ }
+
+ /**
+ * Return a copy of the PhysicalChannelConfig list but with location info removed.
+ */
+ private static List<PhysicalChannelConfig> getLocationSanitizedConfigs(
+ List<PhysicalChannelConfig> configs) {
+ List<PhysicalChannelConfig> sanitizedConfigs = new ArrayList<>(configs.size());
+ for (PhysicalChannelConfig config : configs) {
+ sanitizedConfigs.add(config.createLocationInfoSanitizedCopy());
+ }
+ return sanitizedConfigs;
+ }
+
/**
* Notify that the data enabled has changed.
*
@@ -2527,7 +2558,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub {
final int recordCount = mRecords.size();
pw.println("last known state:");
pw.increaseIndent();
- for (int i = 0; i < getTelephonyManager().getPhoneCount(); i++) {
+ for (int i = 0; i < getTelephonyManager().getActiveModemCount(); i++) {
pw.println("Phone Id=" + i);
pw.increaseIndent();
pw.println("mCallState=" + mCallState[i]);
diff --git a/services/core/java/com/android/server/VcnManagementService.java b/services/core/java/com/android/server/VcnManagementService.java
index 6c18cdea51fa..4622e98bbbb2 100644
--- a/services/core/java/com/android/server/VcnManagementService.java
+++ b/services/core/java/com/android/server/VcnManagementService.java
@@ -29,7 +29,10 @@ import static java.util.Objects.requireNonNull;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.AppOpsManager;
+import android.content.BroadcastReceiver;
import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.LinkProperties;
import android.net.NetworkCapabilities;
@@ -158,6 +161,7 @@ public class VcnManagementService extends IVcnManagementService.Stub {
@NonNull private final TelephonySubscriptionTrackerCallback mTelephonySubscriptionTrackerCb;
@NonNull private final TelephonySubscriptionTracker mTelephonySubscriptionTracker;
@NonNull private final VcnContext mVcnContext;
+ @NonNull private final BroadcastReceiver mPkgChangeReceiver;
/** Can only be assigned when {@link #systemReady()} is called, since it uses AppOpsManager. */
@Nullable private LocationPermissionChecker mLocationPermissionChecker;
@@ -203,6 +207,29 @@ public class VcnManagementService extends IVcnManagementService.Stub {
mConfigDiskRwHelper = mDeps.newPersistableBundleLockingReadWriteHelper(VCN_CONFIG_FILE);
mVcnContext = mDeps.newVcnContext(mContext, mLooper, mNetworkProvider);
+ mPkgChangeReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final String action = intent.getAction();
+
+ if (Intent.ACTION_PACKAGE_ADDED.equals(action)
+ || Intent.ACTION_PACKAGE_REPLACED.equals(action)
+ || Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
+ mTelephonySubscriptionTracker.handleSubscriptionsChanged();
+ } else {
+ Log.wtf(TAG, "received unexpected intent: " + action);
+ }
+ }
+ };
+
+ final IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
+ intentFilter.addAction(Intent.ACTION_PACKAGE_REPLACED);
+ intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+ intentFilter.addDataScheme("package");
+ mContext.registerReceiver(
+ mPkgChangeReceiver, intentFilter, null /* broadcastPermission */, mHandler);
+
// Run on handler to ensure I/O does not block system server startup
mHandler.post(() -> {
PersistableBundle configBundle = null;
@@ -349,7 +376,8 @@ public class VcnManagementService extends IVcnManagementService.Stub {
}
}
- private void enforceCallingUserAndCarrierPrivilege(ParcelUuid subscriptionGroup) {
+ private void enforceCallingUserAndCarrierPrivilege(
+ ParcelUuid subscriptionGroup, String pkgName) {
// Only apps running in the primary (system) user are allowed to configure the VCN. This is
// in line with Telephony's behavior with regards to binding to a Carrier App provided
// CarrierConfigService.
@@ -363,12 +391,15 @@ public class VcnManagementService extends IVcnManagementService.Stub {
subscriptionInfos.addAll(subMgr.getSubscriptionsInGroup(subscriptionGroup));
});
- final TelephonyManager telMgr = mContext.getSystemService(TelephonyManager.class);
for (SubscriptionInfo info : subscriptionInfos) {
+ final TelephonyManager telMgr = mContext.getSystemService(TelephonyManager.class)
+ .createForSubscriptionId(info.getSubscriptionId());
+
// Check subscription is active first; much cheaper/faster check, and an app (currently)
// cannot be carrier privileged for inactive subscriptions.
if (subMgr.isValidSlotIndex(info.getSimSlotIndex())
- && telMgr.hasCarrierPrivileges(info.getSubscriptionId())) {
+ && telMgr.checkCarrierPrivilegesForPackage(pkgName)
+ == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
// TODO (b/173717728): Allow configuration for inactive, but manageable
// subscriptions.
// TODO (b/173718661): Check for whole subscription groups at a time.
@@ -536,7 +567,7 @@ public class VcnManagementService extends IVcnManagementService.Stub {
mContext.getSystemService(AppOpsManager.class)
.checkPackage(mDeps.getBinderCallingUid(), config.getProvisioningPackageName());
- enforceCallingUserAndCarrierPrivilege(subscriptionGroup);
+ enforceCallingUserAndCarrierPrivilege(subscriptionGroup, opPkgName);
Binder.withCleanCallingIdentity(() -> {
synchronized (mLock) {
@@ -554,11 +585,14 @@ public class VcnManagementService extends IVcnManagementService.Stub {
* <p>Implements the IVcnManagementService Binder interface.
*/
@Override
- public void clearVcnConfig(@NonNull ParcelUuid subscriptionGroup) {
+ public void clearVcnConfig(@NonNull ParcelUuid subscriptionGroup, @NonNull String opPkgName) {
requireNonNull(subscriptionGroup, "subscriptionGroup was null");
+ requireNonNull(opPkgName, "opPkgName was null");
Slog.v(TAG, "VCN config cleared for subGrp: " + subscriptionGroup);
- enforceCallingUserAndCarrierPrivilege(subscriptionGroup);
+ mContext.getSystemService(AppOpsManager.class)
+ .checkPackage(mDeps.getBinderCallingUid(), opPkgName);
+ enforceCallingUserAndCarrierPrivilege(subscriptionGroup, opPkgName);
Binder.withCleanCallingIdentity(() -> {
synchronized (mLock) {
@@ -821,8 +855,7 @@ public class VcnManagementService extends IVcnManagementService.Stub {
final IBinder cbBinder = callback.asBinder();
final VcnStatusCallbackInfo cbInfo =
- new VcnStatusCallbackInfo(
- subGroup, callback, opPkgName, mDeps.getBinderCallingUid());
+ new VcnStatusCallbackInfo(subGroup, callback, opPkgName, callingUid);
try {
cbBinder.linkToDeath(cbInfo, 0 /* flags */);
diff --git a/services/core/java/com/android/server/apphibernation/AppHibernationService.java b/services/core/java/com/android/server/apphibernation/AppHibernationService.java
index b3373d0bb536..351231f34c4b 100644
--- a/services/core/java/com/android/server/apphibernation/AppHibernationService.java
+++ b/services/core/java/com/android/server/apphibernation/AppHibernationService.java
@@ -69,6 +69,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
@@ -101,6 +102,7 @@ public final class AppHibernationService extends SystemService {
private final Map<String, GlobalLevelState> mGlobalHibernationStates = new ArrayMap<>();
private final HibernationStateDiskStore<GlobalLevelState> mGlobalLevelHibernationDiskStore;
private final Injector mInjector;
+ private final Executor mBackgroundExecutor;
@VisibleForTesting
boolean mIsServiceEnabled;
@@ -126,6 +128,7 @@ public final class AppHibernationService extends SystemService {
mIActivityManager = injector.getActivityManager();
mUserManager = injector.getUserManager();
mGlobalLevelHibernationDiskStore = injector.getGlobalLevelDiskStore();
+ mBackgroundExecutor = injector.getBackgroundExecutor();
mInjector = injector;
final Context userAllContext = mContext.createContextAsUser(UserHandle.ALL, 0 /* flags */);
@@ -147,11 +150,13 @@ public final class AppHibernationService extends SystemService {
@Override
public void onBootPhase(int phase) {
if (phase == PHASE_BOOT_COMPLETED) {
- List<GlobalLevelState> states =
- mGlobalLevelHibernationDiskStore.readHibernationStates();
- synchronized (mLock) {
- initializeGlobalHibernationStates(states);
- }
+ mBackgroundExecutor.execute(() -> {
+ List<GlobalLevelState> states =
+ mGlobalLevelHibernationDiskStore.readHibernationStates();
+ synchronized (mLock) {
+ initializeGlobalHibernationStates(states);
+ }
+ });
}
if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
mIsServiceEnabled = isAppHibernationEnabled();
@@ -170,16 +175,15 @@ public final class AppHibernationService extends SystemService {
* @return true if package is hibernating for the user
*/
boolean isHibernatingForUser(String packageName, int userId) {
- if (!checkHibernationEnabled("isHibernatingForUser")) {
+ String methodName = "isHibernatingForUser";
+ if (!checkHibernationEnabled(methodName)) {
return false;
}
getContext().enforceCallingOrSelfPermission(
android.Manifest.permission.MANAGE_APP_HIBERNATION,
"Caller does not have MANAGE_APP_HIBERNATION permission.");
- userId = handleIncomingUser(userId, "isHibernating");
- if (!mUserManager.isUserUnlockingOrUnlocked(userId)) {
- Slog.e(TAG, "Attempt to get hibernation state of stopped or nonexistent user "
- + userId);
+ userId = handleIncomingUser(userId, methodName);
+ if (!checkUserStatesExist(userId, methodName)) {
return false;
}
synchronized (mLock) {
@@ -225,16 +229,15 @@ public final class AppHibernationService extends SystemService {
* @param isHibernating new hibernation state
*/
void setHibernatingForUser(String packageName, int userId, boolean isHibernating) {
- if (!checkHibernationEnabled("setHibernatingForUser")) {
+ String methodName = "setHibernatingForUser";
+ if (!checkHibernationEnabled(methodName)) {
return;
}
getContext().enforceCallingOrSelfPermission(
android.Manifest.permission.MANAGE_APP_HIBERNATION,
"Caller does not have MANAGE_APP_HIBERNATION permission.");
- userId = handleIncomingUser(userId, "setHibernating");
- if (!mUserManager.isUserUnlockingOrUnlocked(userId)) {
- Slog.w(TAG, "Attempt to set hibernation state for a stopped or nonexistent user "
- + userId);
+ userId = handleIncomingUser(userId, methodName);
+ if (!checkUserStatesExist(userId, methodName)) {
return;
}
synchronized (mLock) {
@@ -298,16 +301,15 @@ public final class AppHibernationService extends SystemService {
*/
@NonNull List<String> getHibernatingPackagesForUser(int userId) {
ArrayList<String> hibernatingPackages = new ArrayList<>();
- if (!checkHibernationEnabled("getHibernatingPackagesForUser")) {
+ String methodName = "getHibernatingPackagesForUser";
+ if (!checkHibernationEnabled(methodName)) {
return hibernatingPackages;
}
getContext().enforceCallingOrSelfPermission(
android.Manifest.permission.MANAGE_APP_HIBERNATION,
"Caller does not have MANAGE_APP_HIBERNATION permission.");
- userId = handleIncomingUser(userId, "getHibernatingPackagesForUser");
- if (!mUserManager.isUserUnlockingOrUnlocked(userId)) {
- Slog.w(TAG, "Attempt to get hibernating packages for a stopped or nonexistent user "
- + userId);
+ userId = handleIncomingUser(userId, methodName);
+ if (!checkUserStatesExist(userId, methodName)) {
return hibernatingPackages;
}
synchronized (mLock) {
@@ -477,10 +479,15 @@ public final class AppHibernationService extends SystemService {
HibernationStateDiskStore<UserLevelState> diskStore =
mInjector.getUserLevelDiskStore(userId);
mUserDiskStores.put(userId, diskStore);
- List<UserLevelState> storedStates = diskStore.readHibernationStates();
- synchronized (mLock) {
- initializeUserHibernationStates(userId, storedStates);
- }
+ mBackgroundExecutor.execute(() -> {
+ List<UserLevelState> storedStates = diskStore.readHibernationStates();
+ synchronized (mLock) {
+ // Ensure user hasn't stopped in the time to execute.
+ if (mUserManager.isUserUnlockingOrUnlocked(userId)) {
+ initializeUserHibernationStates(userId, storedStates);
+ }
+ }
+ });
}
@Override
@@ -550,6 +557,20 @@ public final class AppHibernationService extends SystemService {
}
}
+ private boolean checkUserStatesExist(int userId, String methodName) {
+ if (!mUserManager.isUserUnlockingOrUnlocked(userId)) {
+ Slog.e(TAG, String.format(
+ "Attempt to call %s on stopped or nonexistent user %d", methodName, userId));
+ return false;
+ }
+ if (!mUserStates.contains(userId)) {
+ Slog.w(TAG, String.format(
+ "Attempt to call %s before states have been read from disk", methodName));
+ return false;
+ }
+ return true;
+ }
+
private boolean checkHibernationEnabled(String methodName) {
if (!mIsServiceEnabled) {
Slog.w(TAG, String.format("Attempted to call %s on unsupported device.", methodName));
@@ -720,6 +741,8 @@ public final class AppHibernationService extends SystemService {
UserManager getUserManager();
+ Executor getBackgroundExecutor();
+
HibernationStateDiskStore<GlobalLevelState> getGlobalLevelDiskStore();
HibernationStateDiskStore<UserLevelState> getUserLevelDiskStore(int userId);
@@ -758,6 +781,11 @@ public final class AppHibernationService extends SystemService {
}
@Override
+ public Executor getBackgroundExecutor() {
+ return mScheduledExecutorService;
+ }
+
+ @Override
public HibernationStateDiskStore<GlobalLevelState> getGlobalLevelDiskStore() {
File dir = new File(Environment.getDataSystemDirectory(), HIBERNATION_DIR_NAME);
return new HibernationStateDiskStore<>(
diff --git a/services/core/java/com/android/server/apphibernation/HibernationStateDiskStore.java b/services/core/java/com/android/server/apphibernation/HibernationStateDiskStore.java
index c83659d2ff56..24cf43339847 100644
--- a/services/core/java/com/android/server/apphibernation/HibernationStateDiskStore.java
+++ b/services/core/java/com/android/server/apphibernation/HibernationStateDiskStore.java
@@ -109,6 +109,7 @@ class HibernationStateDiskStore<T> {
* @return the parsed list of hibernation states, null if file does not exist
*/
@Nullable
+ @WorkerThread
List<T> readHibernationStates() {
synchronized (this) {
if (!mHibernationFile.exists()) {
diff --git a/services/core/java/com/android/server/clipboard/ClipboardService.java b/services/core/java/com/android/server/clipboard/ClipboardService.java
index 6776f49b7d8f..6aec9fcf9a24 100644
--- a/services/core/java/com/android/server/clipboard/ClipboardService.java
+++ b/services/core/java/com/android/server/clipboard/ClipboardService.java
@@ -106,6 +106,29 @@ class HostClipboardMonitor implements Runnable {
return false;
}
+ private void closePipe() {
+ try {
+ final RandomAccessFile pipe = mPipe;
+ mPipe = null;
+ if (pipe != null) {
+ pipe.close();
+ }
+ } catch (IOException ignore) {
+ }
+ }
+
+ private byte[] receiveMessage() throws IOException {
+ final int size = Integer.reverseBytes(mPipe.readInt());
+ final byte[] receivedData = new byte[size];
+ mPipe.readFully(receivedData);
+ return receivedData;
+ }
+
+ private void sendMessage(byte[] message) throws IOException {
+ mPipe.writeInt(Integer.reverseBytes(message.length));
+ mPipe.write(message);
+ }
+
public HostClipboardMonitor(HostClipboardCallback cb) {
mHostClipboardCallback = cb;
}
@@ -120,17 +143,12 @@ class HostClipboardMonitor implements Runnable {
while ((mPipe == null) && !openPipe()) {
Thread.sleep(100);
}
- int size = mPipe.readInt();
- size = Integer.reverseBytes(size);
- byte[] receivedData = new byte[size];
- mPipe.readFully(receivedData);
+
+ final byte[] receivedData = receiveMessage();
mHostClipboardCallback.onHostClipboardUpdated(
new String(receivedData));
} catch (IOException e) {
- try {
- mPipe.close();
- } catch (IOException ee) {}
- mPipe = null;
+ closePipe();
} catch (InterruptedException e) {}
}
}
@@ -138,8 +156,7 @@ class HostClipboardMonitor implements Runnable {
public void setHostClipboard(String content) {
try {
if (mPipe != null) {
- mPipe.writeInt(Integer.reverseBytes(content.getBytes().length));
- mPipe.write(content.getBytes());
+ sendMessage(content.getBytes());
}
} catch(IOException e) {
Slog.e("HostClipboardMonitor",
diff --git a/services/core/java/com/android/server/compat/CompatChange.java b/services/core/java/com/android/server/compat/CompatChange.java
index ae9b0015de43..d29a0c715e95 100644
--- a/services/core/java/com/android/server/compat/CompatChange.java
+++ b/services/core/java/com/android/server/compat/CompatChange.java
@@ -23,7 +23,9 @@ 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.Disabled;
import android.compat.annotation.EnabledSince;
+import android.compat.annotation.Overridable;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
@@ -60,6 +62,15 @@ public final class CompatChange extends CompatibilityChangeInfo {
static final long CTS_SYSTEM_API_CHANGEID = 149391281; // This is a bug id.
/**
+ * An overridable change ID to be used only in the CTS test for this SystemApi
+ */
+ @ChangeId
+ @Disabled
+ @Overridable
+ static final long CTS_SYSTEM_API_OVERRIDABLE_CHANGEID = 174043039; // This is a bug id.
+
+
+ /**
* Callback listener for when compat changes are updated for a package.
* See {@link #registerListener(ChangeListener)} for more details.
*/
@@ -211,6 +222,7 @@ public final class CompatChange extends CompatibilityChangeInfo {
boolean hasPackageOverride(String pname) {
return mRawOverrides.containsKey(pname);
}
+
/**
* Remove any package override for the given package name, restoring the default behaviour.
*
@@ -355,7 +367,7 @@ public final class CompatChange extends CompatibilityChangeInfo {
override.setPackageName(entry.getKey());
override.setMinVersionCode(entry.getValue().getMinVersionCode());
override.setMaxVersionCode(entry.getValue().getMaxVersionCode());
- override.setEnabled(entry.getValue().getEnabled());
+ override.setEnabled(entry.getValue().isEnabled());
rawList.add(override);
}
changeOverrides.setRaw(rawOverrides);
diff --git a/services/core/java/com/android/server/compat/CompatConfig.java b/services/core/java/com/android/server/compat/CompatConfig.java
index ef86f42d6c3c..55e269630093 100644
--- a/services/core/java/com/android/server/compat/CompatConfig.java
+++ b/services/core/java/com/android/server/compat/CompatConfig.java
@@ -304,6 +304,16 @@ final class CompatConfig {
}
/**
+ * Returns whether the change is overridable.
+ */
+ boolean isOverridable(long changeId) {
+ synchronized (mChanges) {
+ CompatChange c = mChanges.get(changeId);
+ return c != null && c.getOverridable();
+ }
+ }
+
+ /**
* Removes an override previously added via {@link #addOverride(long, String, boolean)}.
*
* <p>This restores the default behaviour for the given change and app, once any app processes
@@ -343,7 +353,7 @@ final class CompatConfig {
/**
* Removes all overrides previously added via {@link #addOverride(long, String, boolean)} or
- * {@link #addOverrides(CompatibilityChangeConfig, String)} for a certain package.
+ * {@link #addOverrides(CompatibilityOverrideConfig, String)} for a certain package.
*
* <p>This restores the default behaviour for the given app.
*
@@ -632,8 +642,11 @@ final class CompatConfig {
}
boolean shouldInvalidateCache = false;
for (CompatChange c: changes) {
+ if (!c.hasPackageOverride(packageName)) {
+ continue;
+ }
OverrideAllowedState allowedState =
- mOverrideValidator.getOverrideAllowedState(c.getId(), packageName);
+ mOverrideValidator.getOverrideAllowedStateForRecheck(c.getId(), packageName);
shouldInvalidateCache |= c.recheckOverride(packageName, allowedState, mContext);
}
if (shouldInvalidateCache) {
diff --git a/services/core/java/com/android/server/compat/OverrideValidatorImpl.java b/services/core/java/com/android/server/compat/OverrideValidatorImpl.java
index aa66a1a8b01f..b5006913af35 100644
--- a/services/core/java/com/android/server/compat/OverrideValidatorImpl.java
+++ b/services/core/java/com/android/server/compat/OverrideValidatorImpl.java
@@ -16,6 +16,9 @@
package com.android.server.compat;
+import static android.Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+
import static com.android.internal.compat.OverrideAllowedState.ALLOWED;
import static com.android.internal.compat.OverrideAllowedState.DEFERRED_VERIFICATION;
import static com.android.internal.compat.OverrideAllowedState.DISABLED_NON_TARGET_SDK;
@@ -24,6 +27,7 @@ import static com.android.internal.compat.OverrideAllowedState.DISABLED_TARGET_S
import static com.android.internal.compat.OverrideAllowedState.LOGGING_ONLY_CHANGE;
import static com.android.internal.compat.OverrideAllowedState.PLATFORM_TOO_OLD;
+import android.annotation.NonNull;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
@@ -69,8 +73,25 @@ public class OverrideValidatorImpl extends IOverrideValidator.Stub {
mForceNonDebuggableFinalBuild = false;
}
+ /**
+ * Check the allowed state for the given changeId and packageName on a recheck.
+ *
+ * <p>Recheck happens when the given app is getting updated. In this case we cannot do a
+ * permission check on the caller, so we're using the fact that the override was present as
+ * proof that the original caller was allowed to set this override.
+ */
+ OverrideAllowedState getOverrideAllowedStateForRecheck(long changeId,
+ @NonNull String packageName) {
+ return getOverrideAllowedStateInternal(changeId, packageName, true);
+ }
+
@Override
public OverrideAllowedState getOverrideAllowedState(long changeId, String packageName) {
+ return getOverrideAllowedStateInternal(changeId, packageName, false);
+ }
+
+ private OverrideAllowedState getOverrideAllowedStateInternal(long changeId, String packageName,
+ boolean isRecheck) {
if (mCompatConfig.isLoggingOnly(changeId)) {
return new OverrideAllowedState(LOGGING_ONLY_CHANGE, -1, -1);
}
@@ -99,6 +120,16 @@ public class OverrideValidatorImpl extends IOverrideValidator.Stub {
} catch (NameNotFoundException e) {
return new OverrideAllowedState(DEFERRED_VERIFICATION, -1, -1);
}
+ // If the change is annotated as @Overridable, apps with the specific permission can
+ // set the override even on production builds. When rechecking the override, e.g. during an
+ // app update we can bypass this check, as it wouldn't have been here in the first place.
+ if (mCompatConfig.isOverridable(changeId)
+ && (isRecheck
+ || mContext.checkCallingOrSelfPermission(
+ OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD)
+ == PERMISSION_GRANTED)) {
+ return new OverrideAllowedState(ALLOWED, -1, -1);
+ }
int appTargetSdk = applicationInfo.targetSdkVersion;
// Only allow overriding debuggable apps.
if ((applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
@@ -130,5 +161,4 @@ public class OverrideValidatorImpl extends IOverrideValidator.Stub {
void forceNonDebuggableFinalForTest(boolean value) {
mForceNonDebuggableFinalBuild = value;
}
-
}
diff --git a/services/core/java/com/android/server/compat/PlatformCompat.java b/services/core/java/com/android/server/compat/PlatformCompat.java
index 40e386359a40..20469a21db0c 100644
--- a/services/core/java/com/android/server/compat/PlatformCompat.java
+++ b/services/core/java/com/android/server/compat/PlatformCompat.java
@@ -18,6 +18,7 @@ package com.android.server.compat;
import static android.Manifest.permission.LOG_COMPAT_CHANGE;
import static android.Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG;
+import static android.Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD;
import static android.Manifest.permission.READ_COMPAT_CHANGE_CONFIG;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.Process.SYSTEM_UID;
@@ -182,11 +183,12 @@ public class PlatformCompat extends IPlatformCompat.Stub {
}
@Override
- public void setOverridesFromInstaller(CompatibilityOverrideConfig overrides,
+ public void setOverridesOnReleaseBuilds(CompatibilityOverrideConfig overrides,
String packageName) {
- checkCompatChangeOverridePermission();
+ // TODO(b/183630314): Unify the permission enforcement with the other setOverrides* methods.
+ checkCompatChangeOverrideOverridablePermission();
+ checkAllCompatOverridesAreOverridable(overrides);
mCompatConfig.addOverrides(overrides, packageName);
- killPackage(packageName);
}
@Override
@@ -383,6 +385,26 @@ public class PlatformCompat extends IPlatformCompat.Stub {
}
}
+ private void checkCompatChangeOverrideOverridablePermission() {
+ // Don't check for permissions within the system process
+ if (Binder.getCallingUid() == SYSTEM_UID) {
+ return;
+ }
+ if (mContext.checkCallingOrSelfPermission(OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD)
+ != PERMISSION_GRANTED) {
+ throw new SecurityException("Cannot override compat change");
+ }
+ }
+
+ private void checkAllCompatOverridesAreOverridable(CompatibilityOverrideConfig overrides) {
+ for (Long changeId : overrides.overrides.keySet()) {
+ if (!mCompatConfig.isOverridable(changeId)) {
+ throw new SecurityException("Only change ids marked as Overridable can be "
+ + "overridden.");
+ }
+ }
+ }
+
private void checkCompatChangeReadAndLogPermission() {
checkCompatChangeReadPermission();
checkCompatChangeLogPermission();
diff --git a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
index 7b20ded19205..058dac882225 100644
--- a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
+++ b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
@@ -26,6 +26,7 @@ import static android.net.SocketKeepalive.ERROR_INVALID_INTERVAL;
import static android.net.SocketKeepalive.ERROR_INVALID_IP_ADDRESS;
import static android.net.SocketKeepalive.ERROR_INVALID_NETWORK;
import static android.net.SocketKeepalive.ERROR_INVALID_SOCKET;
+import static android.net.SocketKeepalive.ERROR_NO_SUCH_SLOT;
import static android.net.SocketKeepalive.ERROR_STOP_REASON_UNINITIALIZED;
import static android.net.SocketKeepalive.ERROR_UNSUPPORTED;
import static android.net.SocketKeepalive.MAX_INTERVAL_SEC;
@@ -518,6 +519,8 @@ public class KeepaliveTracker {
}
} else if (reason == ERROR_STOP_REASON_UNINITIALIZED) {
throw new IllegalStateException("Unexpected stop reason: " + reason);
+ } else if (reason == ERROR_NO_SUCH_SLOT) {
+ throw new IllegalStateException("No such slot: " + reason);
} else {
notifyErrorCallback(ki.mCallback, reason);
}
diff --git a/services/core/java/com/android/server/connectivity/NetdEventListenerService.java b/services/core/java/com/android/server/connectivity/NetdEventListenerService.java
index f3d201289f0e..6ea84ce35002 100644
--- a/services/core/java/com/android/server/connectivity/NetdEventListenerService.java
+++ b/services/core/java/com/android/server/connectivity/NetdEventListenerService.java
@@ -18,12 +18,14 @@ package com.android.server.connectivity;
import static android.util.TimeUtils.NANOS_PER_MS;
+import android.annotation.Nullable;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.INetdEventCallback;
import android.net.MacAddress;
import android.net.Network;
import android.net.NetworkCapabilities;
+import android.net.NetworkRequest;
import android.net.metrics.ConnectStats;
import android.net.metrics.DnsEvent;
import android.net.metrics.INetdEventListener;
@@ -98,6 +100,7 @@ public class NetdEventListenerService extends INetdEventListener.Stub {
private final TokenBucket mConnectTb =
new TokenBucket(CONNECT_LATENCY_FILL_RATE, CONNECT_LATENCY_BURST_LIMIT);
+ final TransportForNetIdNetworkCallback mCallback = new TransportForNetIdNetworkCallback();
/**
* There are only 3 possible callbacks.
@@ -158,6 +161,9 @@ public class NetdEventListenerService extends INetdEventListener.Stub {
public NetdEventListenerService(ConnectivityManager cm) {
// We are started when boot is complete, so ConnectivityService should already be running.
mCm = cm;
+ // Clear all capabilities to listen all networks.
+ mCm.registerNetworkCallback(new NetworkRequest.Builder().clearCapabilities().build(),
+ mCallback);
}
private static long projectSnapshotTime(long timeMs) {
@@ -389,18 +395,13 @@ public class NetdEventListenerService extends INetdEventListener.Stub {
}
private long getTransports(int netId) {
- // TODO: directly query ConnectivityService instead of going through Binder interface.
- NetworkCapabilities nc = mCm.getNetworkCapabilities(new Network(netId));
+ final NetworkCapabilities nc = mCallback.getNetworkCapabilities(netId);
if (nc == null) {
return 0;
}
return BitUtils.packBits(nc.getTransportTypes());
}
- private static void maybeLog(String s, Object... args) {
- if (DBG) Log.d(TAG, String.format(s, args));
- }
-
/** Helper class for buffering summaries of NetworkMetrics at regular time intervals */
static class NetworkMetricsSnapshot {
@@ -428,4 +429,29 @@ public class NetdEventListenerService extends INetdEventListener.Stub {
return String.format("%tT.%tL: %s", timeMs, timeMs, j.toString());
}
}
+
+ private class TransportForNetIdNetworkCallback extends ConnectivityManager.NetworkCallback {
+ private final SparseArray<NetworkCapabilities> mCapabilities = new SparseArray<>();
+
+ @Override
+ public void onCapabilitiesChanged(Network network, NetworkCapabilities nc) {
+ synchronized (mCapabilities) {
+ mCapabilities.put(network.getNetId(), nc);
+ }
+ }
+
+ @Override
+ public void onLost(Network network) {
+ synchronized (mCapabilities) {
+ mCapabilities.remove(network.getNetId());
+ }
+ }
+
+ @Nullable
+ public NetworkCapabilities getNetworkCapabilities(int netId) {
+ synchronized (mCapabilities) {
+ return mCapabilities.get(netId);
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index 103ab957f312..ee32fbf00dfe 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -49,6 +49,7 @@ import android.os.IBinder;
import android.os.RemoteException;
import android.os.SystemClock;
import android.telephony.data.EpsBearerQosSessionAttributes;
+import android.telephony.data.NrQosSessionAttributes;
import android.util.Log;
import android.util.Pair;
import android.util.SparseArray;
@@ -200,6 +201,9 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
// Set to true when partial connectivity was detected.
public boolean partialConnectivity;
+ // Delay between when the network is disconnected and when the native network is destroyed.
+ public int teardownDelayMs;
+
// Captive portal info of the network from RFC8908, if any.
// Obtained by ConnectivityService and merged into NetworkAgent-provided information.
public CaptivePortalData capportApiData;
@@ -576,6 +580,28 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
}
}
+ /**
+ * Notify the NetworkAgent that the network is successfully connected.
+ */
+ public void onNetworkCreated() {
+ try {
+ networkAgent.onNetworkCreated();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error sending network created event", e);
+ }
+ }
+
+ /**
+ * Notify the NetworkAgent that the native network has been destroyed.
+ */
+ public void onNetworkDestroyed() {
+ try {
+ networkAgent.onNetworkDestroyed();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error sending network destroyed event", e);
+ }
+ }
+
// TODO: consider moving out of NetworkAgentInfo into its own class
private class NetworkAgentMessageHandler extends INetworkAgentRegistry.Stub {
private final Handler mHandler;
@@ -633,7 +659,13 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
@Override
public void sendEpsQosSessionAvailable(final int qosCallbackId, final QosSession session,
final EpsBearerQosSessionAttributes attributes) {
- mQosCallbackTracker.sendEventQosSessionAvailable(qosCallbackId, session, attributes);
+ mQosCallbackTracker.sendEventEpsQosSessionAvailable(qosCallbackId, session, attributes);
+ }
+
+ @Override
+ public void sendNrQosSessionAvailable(final int qosCallbackId, final QosSession session,
+ final NrQosSessionAttributes attributes) {
+ mQosCallbackTracker.sendEventNrQosSessionAvailable(qosCallbackId, session, attributes);
}
@Override
@@ -646,6 +678,12 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
@QosCallbackException.ExceptionType final int exceptionType) {
mQosCallbackTracker.sendEventQosCallbackError(qosCallbackId, exceptionType);
}
+
+ @Override
+ public void sendTeardownDelayMs(int teardownDelayMs) {
+ mHandler.obtainMessage(NetworkAgent.EVENT_TEARDOWN_DELAY_CHANGED,
+ teardownDelayMs, 0, new Pair<>(NetworkAgentInfo.this, null)).sendToTarget();
+ }
}
/**
diff --git a/services/core/java/com/android/server/connectivity/PermissionMonitor.java b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
index 488677ac1b59..37116797d8d7 100644
--- a/services/core/java/com/android/server/connectivity/PermissionMonitor.java
+++ b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
@@ -271,6 +271,13 @@ public class PermissionMonitor {
return mApps.containsKey(uid);
}
+ /**
+ * Returns whether the given uid has permission to use restricted networks.
+ */
+ public synchronized boolean hasRestrictedNetworksPermission(int uid) {
+ return Boolean.TRUE.equals(mApps.get(uid));
+ }
+
private void update(Set<UserHandle> users, Map<Integer, Boolean> apps, boolean add) {
List<Integer> network = new ArrayList<>();
List<Integer> system = new ArrayList<>();
diff --git a/services/core/java/com/android/server/connectivity/QosCallbackAgentConnection.java b/services/core/java/com/android/server/connectivity/QosCallbackAgentConnection.java
index 0f5400d0f8e6..534dbe7699a7 100644
--- a/services/core/java/com/android/server/connectivity/QosCallbackAgentConnection.java
+++ b/services/core/java/com/android/server/connectivity/QosCallbackAgentConnection.java
@@ -27,6 +27,7 @@ import android.net.QosSession;
import android.os.IBinder;
import android.os.RemoteException;
import android.telephony.data.EpsBearerQosSessionAttributes;
+import android.telephony.data.NrQosSessionAttributes;
import android.util.Log;
import java.util.Objects;
@@ -146,13 +147,23 @@ class QosCallbackAgentConnection implements IBinder.DeathRecipient {
mNetworkAgentInfo.onQosCallbackUnregistered(mAgentCallbackId);
}
- void sendEventQosSessionAvailable(final QosSession session,
+ void sendEventEpsQosSessionAvailable(final QosSession session,
final EpsBearerQosSessionAttributes attributes) {
try {
- if (DBG) log("sendEventQosSessionAvailable: sending...");
+ if (DBG) log("sendEventEpsQosSessionAvailable: sending...");
mCallback.onQosEpsBearerSessionAvailable(session, attributes);
} catch (final RemoteException e) {
- loge("sendEventQosSessionAvailable: remote exception", e);
+ loge("sendEventEpsQosSessionAvailable: remote exception", e);
+ }
+ }
+
+ void sendEventNrQosSessionAvailable(final QosSession session,
+ final NrQosSessionAttributes attributes) {
+ try {
+ if (DBG) log("sendEventNrQosSessionAvailable: sending...");
+ mCallback.onNrQosSessionAvailable(session, attributes);
+ } catch (final RemoteException e) {
+ loge("sendEventNrQosSessionAvailable: remote exception", e);
}
}
diff --git a/services/core/java/com/android/server/connectivity/QosCallbackTracker.java b/services/core/java/com/android/server/connectivity/QosCallbackTracker.java
index 8bda5323e4f8..b6ab47b276e3 100644
--- a/services/core/java/com/android/server/connectivity/QosCallbackTracker.java
+++ b/services/core/java/com/android/server/connectivity/QosCallbackTracker.java
@@ -27,6 +27,7 @@ import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.telephony.data.EpsBearerQosSessionAttributes;
+import android.telephony.data.NrQosSessionAttributes;
import android.util.Log;
import com.android.net.module.util.CollectionUtils;
@@ -179,17 +180,31 @@ public class QosCallbackTracker {
}
/**
- * Called when the NetworkAgent sends the qos session available event
+ * Called when the NetworkAgent sends the qos session available event for EPS
*
* @param qosCallbackId the callback id that the qos session is now available to
* @param session the qos session that is now available
* @param attributes the qos attributes that are now available on the qos session
*/
- public void sendEventQosSessionAvailable(final int qosCallbackId,
+ public void sendEventEpsQosSessionAvailable(final int qosCallbackId,
final QosSession session,
final EpsBearerQosSessionAttributes attributes) {
- runOnAgentConnection(qosCallbackId, "sendEventQosSessionAvailable: ",
- ac -> ac.sendEventQosSessionAvailable(session, attributes));
+ runOnAgentConnection(qosCallbackId, "sendEventEpsQosSessionAvailable: ",
+ ac -> ac.sendEventEpsQosSessionAvailable(session, attributes));
+ }
+
+ /**
+ * Called when the NetworkAgent sends the qos session available event for NR
+ *
+ * @param qosCallbackId the callback id that the qos session is now available to
+ * @param session the qos session that is now available
+ * @param attributes the qos attributes that are now available on the qos session
+ */
+ public void sendEventNrQosSessionAvailable(final int qosCallbackId,
+ final QosSession session,
+ final NrQosSessionAttributes attributes) {
+ runOnAgentConnection(qosCallbackId, "sendEventNrQosSessionAvailable: ",
+ ac -> ac.sendEventNrQosSessionAvailable(session, attributes));
}
/**
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 30e0c7e9b9aa..e5ce4f062973 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -17,12 +17,11 @@
package com.android.server.connectivity;
import static android.Manifest.permission.BIND_VPN_SERVICE;
-import static android.net.ConnectivityManager.NETID_UNSET;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
-import static android.os.UserHandle.PER_USER_RANGE;
import static android.net.RouteInfo.RTN_THROW;
import static android.net.RouteInfo.RTN_UNREACHABLE;
import static android.net.VpnManager.NOTIFICATION_CHANNEL_VPN;
+import static android.os.UserHandle.PER_USER_RANGE;
import static com.android.internal.util.Preconditions.checkArgument;
import static com.android.internal.util.Preconditions.checkNotNull;
@@ -223,7 +222,7 @@ public class Vpn {
protected NetworkAgent mNetworkAgent;
private final Looper mLooper;
@VisibleForTesting
- protected final NetworkCapabilities mNetworkCapabilities;
+ protected NetworkCapabilities mNetworkCapabilities;
private final SystemServices mSystemServices;
private final Ikev2SessionCreator mIkev2SessionCreator;
private final UserManager mUserManager;
@@ -460,11 +459,12 @@ public class Vpn {
mLegacyState = LegacyVpnInfo.STATE_DISCONNECTED;
mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_VPN, 0 /* subtype */, NETWORKTYPE,
"" /* subtypeName */);
- mNetworkCapabilities = new NetworkCapabilities();
- 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));
+ mNetworkCapabilities = new NetworkCapabilities.Builder()
+ .addTransportType(NetworkCapabilities.TRANSPORT_VPN)
+ .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED)
+ .setTransportInfo(new VpnTransportInfo(VpnManager.TYPE_VPN_NONE))
+ .build();
loadAlwaysOnPackage();
}
@@ -525,8 +525,10 @@ public class Vpn {
}
private void resetNetworkCapabilities() {
- mNetworkCapabilities.setUids(null);
- mNetworkCapabilities.setTransportInfo(new VpnTransportInfo(VpnManager.TYPE_VPN_NONE));
+ mNetworkCapabilities = new NetworkCapabilities.Builder(mNetworkCapabilities)
+ .setUids(null)
+ .setTransportInfo(new VpnTransportInfo(VpnManager.TYPE_VPN_NONE))
+ .build();
}
/**
@@ -1124,17 +1126,19 @@ public class Vpn {
}
/**
- * Return netId of current running VPN network.
+ * Return Network of current running VPN network.
*
- * @return a netId if there is a running VPN network or NETID_UNSET if there is no running VPN
+ * @return a Network if there is a running VPN network or null if there is no running VPN
* network or network is null.
*/
- public synchronized int getNetId() {
+ @VisibleForTesting
+ @Nullable
+ public synchronized Network getNetwork() {
final NetworkAgent agent = mNetworkAgent;
- if (null == agent) return NETID_UNSET;
+ if (null == agent) return null;
final Network network = agent.getNetwork();
- if (null == network) return NETID_UNSET;
- return network.getNetId();
+ if (null == network) return null;
+ return network;
}
private LinkProperties makeLinkProperties() {
@@ -1237,29 +1241,33 @@ public class Vpn {
// registered with registerDefaultNetworkCallback. This in turn protects the invariant
// that an app calling ConnectivityManager#bindProcessToNetwork(getDefaultNetwork())
// behaves the same as when it uses the default network.
- mNetworkCapabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
+ final NetworkCapabilities.Builder capsBuilder =
+ new NetworkCapabilities.Builder(mNetworkCapabilities);
+ capsBuilder.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
mLegacyState = LegacyVpnInfo.STATE_CONNECTING;
updateState(DetailedState.CONNECTING, "agentConnect");
- NetworkAgentConfig networkAgentConfig = new NetworkAgentConfig.Builder().build();
- networkAgentConfig.allowBypass = mConfig.allowBypass && !mLockdown;
+ final NetworkAgentConfig networkAgentConfig = new NetworkAgentConfig.Builder()
+ .setBypassableVpn(mConfig.allowBypass && !mLockdown)
+ .build();
- mNetworkCapabilities.setOwnerUid(mOwnerUID);
- mNetworkCapabilities.setAdministratorUids(new int[] {mOwnerUID});
- mNetworkCapabilities.setUids(createUserAndRestrictedProfilesRanges(mUserId,
+ capsBuilder.setOwnerUid(mOwnerUID);
+ capsBuilder.setAdministratorUids(new int[] {mOwnerUID});
+ capsBuilder.setUids(createUserAndRestrictedProfilesRanges(mUserId,
mConfig.allowedApplications, mConfig.disallowedApplications));
- mNetworkCapabilities.setTransportInfo(new VpnTransportInfo(getActiveVpnType()));
+ capsBuilder.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) {
- mNetworkCapabilities.removeCapability(NET_CAPABILITY_NOT_METERED);
+ capsBuilder.removeCapability(NET_CAPABILITY_NOT_METERED);
} else {
- mNetworkCapabilities.addCapability(NET_CAPABILITY_NOT_METERED);
+ capsBuilder.addCapability(NET_CAPABILITY_NOT_METERED);
}
+ mNetworkCapabilities = capsBuilder.build();
mNetworkAgent = new NetworkAgent(mContext, mLooper, NETWORKTYPE /* logtag */,
mNetworkCapabilities, lp,
new NetworkScore.Builder().setLegacyInt(VPN_DEFAULT_SCORE).build(),
@@ -1280,7 +1288,6 @@ public class Vpn {
});
mNetworkAgent.setUnderlyingNetworks((mConfig.underlyingNetworks != null)
? Arrays.asList(mConfig.underlyingNetworks) : null);
- mNetworkInfo.setIsAvailable(true);
updateState(DetailedState.CONNECTED, "agentConnect");
}
@@ -1426,7 +1433,8 @@ public class Vpn {
// restore old state
mConfig = oldConfig;
mConnection = oldConnection;
- mNetworkCapabilities.setUids(oldUsers);
+ mNetworkCapabilities =
+ new NetworkCapabilities.Builder(mNetworkCapabilities).setUids(oldUsers).build();
mNetworkAgent = oldNetworkAgent;
mInterface = oldInterface;
throw e;
@@ -1576,7 +1584,8 @@ public class Vpn {
try {
addUserToRanges(existingRanges, userId, mConfig.allowedApplications,
mConfig.disallowedApplications);
- mNetworkCapabilities.setUids(existingRanges);
+ mNetworkCapabilities = new NetworkCapabilities.Builder(mNetworkCapabilities)
+ .setUids(existingRanges).build();
} catch (Exception e) {
Log.wtf(TAG, "Failed to add restricted user to owner", e);
}
@@ -1605,7 +1614,8 @@ public class Vpn {
final List<Range<Integer>> removedRanges =
uidRangesForUser(userId, existingRanges);
existingRanges.removeAll(removedRanges);
- mNetworkCapabilities.setUids(existingRanges);
+ mNetworkCapabilities = new NetworkCapabilities.Builder(mNetworkCapabilities)
+ .setUids(existingRanges).build();
} catch (Exception e) {
Log.wtf(TAG, "Failed to remove restricted user to owner", e);
}
@@ -1849,22 +1859,13 @@ public class Vpn {
/**
* Updates underlying network set.
*/
- public synchronized boolean setUnderlyingNetworks(Network[] networks) {
+ public synchronized boolean setUnderlyingNetworks(@Nullable Network[] networks) {
if (!isCallerEstablishedOwnerLocked()) {
return false;
}
- if (networks == null) {
- mConfig.underlyingNetworks = null;
- } else {
- mConfig.underlyingNetworks = new Network[networks.length];
- for (int i = 0; i < networks.length; ++i) {
- if (networks[i] == null) {
- mConfig.underlyingNetworks[i] = null;
- } else {
- mConfig.underlyingNetworks[i] = new Network(networks[i].getNetId());
- }
- }
- }
+ // Make defensive copy since the content of array might be altered by the caller.
+ mConfig.underlyingNetworks =
+ (networks != null) ? Arrays.copyOf(networks, networks.length) : null;
mNetworkAgent.setUnderlyingNetworks((mConfig.underlyingNetworks != null)
? Arrays.asList(mConfig.underlyingNetworks) : null);
return true;
@@ -1886,7 +1887,12 @@ public class Vpn {
if (!isRunningLocked()) {
return false;
}
- return mNetworkCapabilities.appliesToUid(uid);
+ final Set<Range<Integer>> uids = mNetworkCapabilities.getUids();
+ if (uids == null) return true;
+ for (final Range<Integer> range : uids) {
+ if (range.contains(uid)) return true;
+ }
+ return false;
}
/**
diff --git a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
index 6f12155c5ec6..6a407e99f1e4 100644
--- a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
+++ b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
@@ -440,9 +440,8 @@ public abstract class BrightnessMappingStrategy {
}
private float permissibleRatio(float currLux, float prevLux) {
- return MathUtils.exp(MAX_GRAD
- * (MathUtils.log(currLux + LUX_GRAD_SMOOTHING)
- - MathUtils.log(prevLux + LUX_GRAD_SMOOTHING)));
+ return MathUtils.pow((currLux + LUX_GRAD_SMOOTHING)
+ / (prevLux + LUX_GRAD_SMOOTHING), MAX_GRAD);
}
protected float inferAutoBrightnessAdjustment(float maxGamma, float desiredBrightness,
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index f658e33e0530..58a702527e5f 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -619,8 +619,10 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
}
}
- addAndStartAction(new NewDeviceAction(this, activeSource.logicalAddress,
- activeSource.physicalAddress, deviceType));
+ if (!mService.isPowerStandbyOrTransient()) {
+ addAndStartAction(new NewDeviceAction(this, activeSource.logicalAddress,
+ activeSource.physicalAddress, deviceType));
+ }
}
private boolean handleNewDeviceAtTheTailOfActivePath(int path) {
@@ -796,10 +798,12 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
@ServiceThreadOnly
void onNewAvrAdded(HdmiDeviceInfo avr) {
assertRunOnServiceThread();
- addAndStartAction(new SystemAudioAutoInitiationAction(this, avr.getLogicalAddress()));
- if (isConnected(avr.getPortId()) && isArcFeatureEnabled(avr.getPortId())
- && !hasAction(SetArcTransmissionStateAction.class)) {
- startArcAction(true);
+ if (!mService.isPowerStandbyOrTransient()) {
+ addAndStartAction(new SystemAudioAutoInitiationAction(this, avr.getLogicalAddress()));
+ if (isConnected(avr.getPortId()) && isArcFeatureEnabled(avr.getPortId())
+ && !hasAction(SetArcTransmissionStateAction.class)) {
+ startArcAction(true);
+ }
}
}
@@ -1656,6 +1660,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
// Remove recording actions.
removeAction(OneTouchRecordAction.class);
removeAction(TimerRecordingAction.class);
+ removeAction(NewDeviceAction.class);
disableSystemAudioIfExist();
disableArcIfExist();
@@ -1696,12 +1701,20 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice {
setArcStatus(false);
// Seq #44.
- removeAction(RequestArcInitiationAction.class);
+ removeAllRunningArcAction();
if (!hasAction(RequestArcTerminationAction.class) && isArcEstablished()) {
addAndStartAction(new RequestArcTerminationAction(this, avr.getLogicalAddress()));
}
}
+ @ServiceThreadOnly
+ private void removeAllRunningArcAction() {
+ // Running or pending actions make TV fail to broadcast <Standby> to connected devices
+ removeAction(RequestArcTerminationAction.class);
+ removeAction(RequestArcInitiationAction.class);
+ removeAction(SetArcTransmissionStateAction.class);
+ }
+
@Override
@ServiceThreadOnly
protected void onStandby(boolean initiatedByCec, int standbyAction) {
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlShellCommand.java b/services/core/java/com/android/server/hdmi/HdmiControlShellCommand.java
index ee3427f0a383..740407c42178 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlShellCommand.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlShellCommand.java
@@ -35,9 +35,23 @@ final class HdmiControlShellCommand extends ShellCommand {
private final IHdmiControlService.Stub mBinderService;
+ final CountDownLatch mLatch;
+ AtomicInteger mCecResult;
+ IHdmiControlCallback.Stub mHdmiControlCallback;
HdmiControlShellCommand(IHdmiControlService.Stub binderService) {
mBinderService = binderService;
+ mLatch = new CountDownLatch(1);
+ mCecResult = new AtomicInteger();
+ mHdmiControlCallback =
+ new IHdmiControlCallback.Stub() {
+ @Override
+ public void onComplete(int result) {
+ getOutPrintWriter().println(" done (" + getResultString(result) + ")");
+ mCecResult.set(result);
+ mLatch.countDown();
+ }
+ };
}
@Override
@@ -70,6 +84,8 @@ final class HdmiControlShellCommand extends ShellCommand {
pw.println(" --args <vendor specific arguments>");
pw.println(" [--id <true if vendor command should be sent with vendor id>]");
pw.println(" Send a Vendor Command to the given target device");
+ pw.println(" setsystemaudiomode, setsam [on|off]");
+ pw.println(" Sets the System Audio Mode feature on or off on TV devices");
}
private int handleShellCommand(String cmd) throws RemoteException {
@@ -81,6 +97,9 @@ final class HdmiControlShellCommand extends ShellCommand {
return oneTouchPlay(pw);
case "vendorcommand":
return vendorCommand(pw);
+ case "setsystemaudiomode":
+ case "setsam":
+ return setSystemAudioMode(pw);
}
getErrPrintWriter().println("Unhandled command: " + cmd);
@@ -88,28 +107,14 @@ final class HdmiControlShellCommand extends ShellCommand {
}
private int oneTouchPlay(PrintWriter pw) throws RemoteException {
- final CountDownLatch latch = new CountDownLatch(1);
- AtomicInteger cecResult = new AtomicInteger();
pw.print("Sending One Touch Play...");
- mBinderService.oneTouchPlay(new IHdmiControlCallback.Stub() {
- @Override
- public void onComplete(int result) {
- pw.println(" done (" + result + ")");
- latch.countDown();
- cecResult.set(result);
- }
- });
+ mBinderService.oneTouchPlay(mHdmiControlCallback);
- try {
- if (!latch.await(HdmiConfig.TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
- getErrPrintWriter().println("One Touch Play timed out.");
- return 1;
- }
- } catch (InterruptedException e) {
- getErrPrintWriter().println("Caught InterruptedException");
- Thread.currentThread().interrupt();
+ if (!receiveCallback("One Touch Play")) {
+ return 1;
}
- return cecResult.get() == HdmiControlManager.RESULT_SUCCESS ? 0 : 1;
+
+ return mCecResult.get() == HdmiControlManager.RESULT_SUCCESS ? 0 : 1;
}
private int vendorCommand(PrintWriter pw) throws RemoteException {
@@ -157,4 +162,62 @@ final class HdmiControlShellCommand extends ShellCommand {
mBinderService.sendVendorCommand(deviceType, destination, params, hasVendorId);
return 0;
}
+
+ private int setSystemAudioMode(PrintWriter pw) throws RemoteException {
+ if (1 > getRemainingArgsCount()) {
+ throw new IllegalArgumentException(
+ "Please indicate if System Audio Mode should be turned \"on\" or \"off\".");
+ }
+
+ String arg = getNextArg();
+ if (arg.equals("on")) {
+ pw.println("Setting System Audio Mode on");
+ mBinderService.setSystemAudioMode(true, mHdmiControlCallback);
+ } else if (arg.equals("off")) {
+ pw.println("Setting System Audio Mode off");
+ mBinderService.setSystemAudioMode(false, mHdmiControlCallback);
+ } else {
+ throw new IllegalArgumentException(
+ "Please indicate if System Audio Mode should be turned \"on\" or \"off\".");
+ }
+
+ if (!receiveCallback("Set System Audio Mode")) {
+ return 1;
+ }
+
+ return mCecResult.get() == HdmiControlManager.RESULT_SUCCESS ? 0 : 1;
+ }
+
+ private boolean receiveCallback(String command) {
+ try {
+ if (!mLatch.await(HdmiConfig.TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
+ getErrPrintWriter().println(command + " timed out.");
+ return false;
+ }
+ } catch (InterruptedException e) {
+ getErrPrintWriter().println("Caught InterruptedException");
+ Thread.currentThread().interrupt();
+ }
+ return true;
+ }
+
+ private String getResultString(int result) {
+ switch (result) {
+ case HdmiControlManager.RESULT_SUCCESS:
+ return "Success";
+ case HdmiControlManager.RESULT_TIMEOUT:
+ return "Timeout";
+ case HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE:
+ return "Source not available";
+ case HdmiControlManager.RESULT_TARGET_NOT_AVAILABLE:
+ return "Target not available";
+ case HdmiControlManager.RESULT_EXCEPTION:
+ return "Exception";
+ case HdmiControlManager.RESULT_INCORRECT_MODE:
+ return "Incorrect mode";
+ case HdmiControlManager.RESULT_COMMUNICATION_FAILED:
+ return "Communication Failed";
+ }
+ return Integer.toString(result);
+ }
}
diff --git a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
index 6e99cba6ea91..76ecc1acc7ac 100644
--- a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
+++ b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
@@ -15,14 +15,17 @@
*/
package com.android.server.locksettings;
+
import static android.os.UserHandle.USER_SYSTEM;
+import android.annotation.IntDef;
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.SystemProperties;
import android.os.UserManager;
import android.provider.DeviceConfig;
import android.provider.Settings;
@@ -35,6 +38,8 @@ import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.widget.RebootEscrowListener;
import java.io.IOException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
@@ -65,6 +70,22 @@ class RebootEscrowManager {
public static final String REBOOT_ESCROW_ARMED_KEY = "reboot_escrow_armed_count";
static final String REBOOT_ESCROW_KEY_ARMED_TIMESTAMP = "reboot_escrow_key_stored_timestamp";
+ static final String REBOOT_ESCROW_KEY_PROVIDER = "reboot_escrow_key_provider";
+
+ /**
+ * The verified boot 2.0 vbmeta digest of the current slot, the property value is always
+ * available after boot.
+ */
+ static final String VBMETA_DIGEST_PROP_NAME = "ro.boot.vbmeta.digest";
+ /**
+ * The system prop contains vbmeta digest of the inactive slot. The build property is set after
+ * an OTA update. RebootEscrowManager will store it in disk before the OTA reboot, so the value
+ * is available for vbmeta digest verification after the device reboots.
+ */
+ static final String OTHER_VBMETA_DIGEST_PROP_NAME = "ota.other.vbmeta_digest";
+ static final String REBOOT_ESCROW_KEY_VBMETA_DIGEST = "reboot_escrow_key_vbmeta_digest";
+ static final String REBOOT_ESCROW_KEY_OTHER_VBMETA_DIGEST =
+ "reboot_escrow_key_other_vbmeta_digest";
/**
* Number of boots until we consider the escrow data to be stale for the purposes of metrics.
@@ -86,6 +107,31 @@ class RebootEscrowManager {
private static final int DEFAULT_LOAD_ESCROW_DATA_RETRY_COUNT = 3;
private static final int DEFAULT_LOAD_ESCROW_DATA_RETRY_INTERVAL_SECONDS = 30;
+ @IntDef(prefix = {"ERROR_"}, value = {
+ ERROR_NONE,
+ ERROR_UNKNOWN,
+ ERROR_NO_PROVIDER,
+ ERROR_LOAD_ESCROW_KEY,
+ ERROR_RETRY_COUNT_EXHAUSTED,
+ ERROR_UNLOCK_ALL_USERS,
+ ERROR_PROVIDER_MISMATCH,
+ ERROR_KEYSTORE_FAILURE,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface RebootEscrowErrorCode {
+ }
+
+ static final int ERROR_NONE = 0;
+ static final int ERROR_UNKNOWN = 1;
+ static final int ERROR_NO_PROVIDER = 2;
+ static final int ERROR_LOAD_ESCROW_KEY = 3;
+ static final int ERROR_RETRY_COUNT_EXHAUSTED = 4;
+ static final int ERROR_UNLOCK_ALL_USERS = 5;
+ static final int ERROR_PROVIDER_MISMATCH = 6;
+ static final int ERROR_KEYSTORE_FAILURE = 7;
+
+ private @RebootEscrowErrorCode int mLoadEscrowDataErrorCode = ERROR_NONE;
+
/**
* Logs events for later debugging in bugreports.
*/
@@ -199,6 +245,10 @@ class RebootEscrowManager {
0);
}
+ public long getCurrentTimeMillis() {
+ return System.currentTimeMillis();
+ }
+
public int getLoadEscrowDataRetryLimit() {
return DeviceConfig.getInt(DeviceConfig.NAMESPACE_OTA,
"load_escrow_data_retry_count", DEFAULT_LOAD_ESCROW_DATA_RETRY_COUNT);
@@ -221,6 +271,11 @@ class RebootEscrowManager {
public RebootEscrowEventLog getEventLog() {
return new RebootEscrowEventLog();
}
+
+ public String getVbmetaDigest(boolean other) {
+ return other ? SystemProperties.get(OTHER_VBMETA_DIGEST_PROP_NAME)
+ : SystemProperties.get(VBMETA_DIGEST_PROP_NAME);
+ }
}
RebootEscrowManager(Context context, Callbacks callbacks, LockSettingsStorage storage) {
@@ -261,6 +316,7 @@ class RebootEscrowManager {
if (rebootEscrowUsers.isEmpty()) {
Slog.i(TAG, "No reboot escrow data found for users,"
+ " skipping loading escrow data");
+ clearMetricsStorage();
return;
}
@@ -284,6 +340,7 @@ class RebootEscrowManager {
}
Slog.w(TAG, "Failed to load reboot escrow data after " + attemptNumber + " attempts");
+ mLoadEscrowDataErrorCode = ERROR_RETRY_COUNT_EXHAUSTED;
onGetRebootEscrowKeyFailed(users, attemptNumber);
}
@@ -307,6 +364,17 @@ class RebootEscrowManager {
}
if (escrowKey == null) {
+ if (mLoadEscrowDataErrorCode == ERROR_NONE) {
+ // Specifically check if the RoR provider has changed after reboot.
+ int providerType = mInjector.serverBasedResumeOnReboot()
+ ? RebootEscrowProviderInterface.TYPE_SERVER_BASED
+ : RebootEscrowProviderInterface.TYPE_HAL;
+ if (providerType != mStorage.getInt(REBOOT_ESCROW_KEY_PROVIDER, -1, USER_SYSTEM)) {
+ mLoadEscrowDataErrorCode = ERROR_PROVIDER_MISMATCH;
+ } else {
+ mLoadEscrowDataErrorCode = ERROR_LOAD_ESCROW_KEY;
+ }
+ }
onGetRebootEscrowKeyFailed(users, attemptNumber + 1);
return;
}
@@ -321,9 +389,49 @@ class RebootEscrowManager {
// Clear the old key in keystore. A new key will be generated by new RoR requests.
mKeyStoreManager.clearKeyStoreEncryptionKey();
+ if (!allUsersUnlocked && mLoadEscrowDataErrorCode == ERROR_NONE) {
+ mLoadEscrowDataErrorCode = ERROR_UNLOCK_ALL_USERS;
+ }
onEscrowRestoreComplete(allUsersUnlocked, attemptNumber + 1);
}
+ private void clearMetricsStorage() {
+ mStorage.removeKey(REBOOT_ESCROW_ARMED_KEY, USER_SYSTEM);
+ mStorage.removeKey(REBOOT_ESCROW_KEY_ARMED_TIMESTAMP, USER_SYSTEM);
+ mStorage.removeKey(REBOOT_ESCROW_KEY_VBMETA_DIGEST, USER_SYSTEM);
+ mStorage.removeKey(REBOOT_ESCROW_KEY_OTHER_VBMETA_DIGEST, USER_SYSTEM);
+ mStorage.removeKey(REBOOT_ESCROW_KEY_PROVIDER, USER_SYSTEM);
+ }
+
+ private int getVbmetaDigestStatusOnRestoreComplete() {
+ String currentVbmetaDigest = mInjector.getVbmetaDigest(false);
+ String vbmetaDigestStored = mStorage.getString(REBOOT_ESCROW_KEY_VBMETA_DIGEST,
+ "", USER_SYSTEM);
+ String vbmetaDigestOtherStored = mStorage.getString(REBOOT_ESCROW_KEY_OTHER_VBMETA_DIGEST,
+ "", USER_SYSTEM);
+
+ // The other vbmeta digest is never set, assume no slot switch is attempted.
+ if (vbmetaDigestOtherStored.isEmpty()) {
+ if (currentVbmetaDigest.equals(vbmetaDigestStored)) {
+ return FrameworkStatsLog
+ .REBOOT_ESCROW_RECOVERY_REPORTED__VBMETA_DIGEST_STATUS__MATCH_EXPECTED_SLOT;
+ }
+ return FrameworkStatsLog
+ .REBOOT_ESCROW_RECOVERY_REPORTED__VBMETA_DIGEST_STATUS__MISMATCH;
+ }
+
+ // The other vbmeta digest is set, we expect to boot into the new slot.
+ if (currentVbmetaDigest.equals(vbmetaDigestOtherStored)) {
+ return FrameworkStatsLog
+ .REBOOT_ESCROW_RECOVERY_REPORTED__VBMETA_DIGEST_STATUS__MATCH_EXPECTED_SLOT;
+ } else if (currentVbmetaDigest.equals(vbmetaDigestStored)) {
+ return FrameworkStatsLog
+ .REBOOT_ESCROW_RECOVERY_REPORTED__VBMETA_DIGEST_STATUS__MATCH_FALLBACK_SLOT;
+ }
+ return FrameworkStatsLog
+ .REBOOT_ESCROW_RECOVERY_REPORTED__VBMETA_DIGEST_STATUS__MISMATCH;
+ }
+
private void reportMetricOnRestoreComplete(boolean success, int attemptCount) {
int serviceType = mInjector.serverBasedResumeOnReboot()
? FrameworkStatsLog.REBOOT_ESCROW_RECOVERY_REPORTED__TYPE__SERVER_BASED
@@ -331,26 +439,32 @@ class RebootEscrowManager {
long armedTimestamp = mStorage.getLong(REBOOT_ESCROW_KEY_ARMED_TIMESTAMP, -1,
USER_SYSTEM);
- mStorage.removeKey(REBOOT_ESCROW_KEY_ARMED_TIMESTAMP, USER_SYSTEM);
- int escrowDurationInSeconds = armedTimestamp != -1
- ? (int) (System.currentTimeMillis() - armedTimestamp) / 1000 : -1;
+ int escrowDurationInSeconds = -1;
+ long currentTimeStamp = mInjector.getCurrentTimeMillis();
+ if (armedTimestamp != -1 && currentTimeStamp > armedTimestamp) {
+ escrowDurationInSeconds = (int) (currentTimeStamp - armedTimestamp) / 1000;
+ }
- // TODO(b/179105110) design error code; and report the true value for other fields.
- int vbmetaDigestStatus = FrameworkStatsLog
- .REBOOT_ESCROW_RECOVERY_REPORTED__VBMETA_DIGEST_STATUS__MATCH_EXPECTED_SLOT;
+ int vbmetaDigestStatus = getVbmetaDigestStatusOnRestoreComplete();
+ if (!success && mLoadEscrowDataErrorCode == ERROR_NONE) {
+ mLoadEscrowDataErrorCode = ERROR_UNKNOWN;
+ }
- mInjector.reportMetric(success, 0 /* error code */, serviceType, attemptCount,
+ // TODO(179105110) report the duration since boot complete.
+ mInjector.reportMetric(success, mLoadEscrowDataErrorCode, serviceType, attemptCount,
escrowDurationInSeconds, vbmetaDigestStatus, -1);
+
+ mLoadEscrowDataErrorCode = ERROR_NONE;
}
private void onEscrowRestoreComplete(boolean success, int attemptCount) {
int previousBootCount = mStorage.getInt(REBOOT_ESCROW_ARMED_KEY, -1, USER_SYSTEM);
- mStorage.removeKey(REBOOT_ESCROW_ARMED_KEY, USER_SYSTEM);
int bootCountDelta = mInjector.getBootCount() - previousBootCount;
if (success || (previousBootCount != -1 && bootCountDelta <= BOOT_COUNT_TOLERANCE)) {
reportMetricOnRestoreComplete(success, attemptCount);
}
+ clearMetricsStorage();
}
private RebootEscrowKey getAndClearRebootEscrowKey(SecretKey kk) throws IOException {
@@ -358,6 +472,14 @@ class RebootEscrowManager {
if (rebootEscrowProvider == null) {
Slog.w(TAG,
"Had reboot escrow data for users, but RebootEscrowProvider is unavailable");
+ mLoadEscrowDataErrorCode = ERROR_NO_PROVIDER;
+ return null;
+ }
+
+ // Server based RoR always need the decryption key from keystore.
+ if (rebootEscrowProvider.getType() == RebootEscrowProviderInterface.TYPE_SERVER_BASED
+ && kk == null) {
+ mLoadEscrowDataErrorCode = ERROR_KEYSTORE_FAILURE;
return null;
}
@@ -463,7 +585,7 @@ class RebootEscrowManager {
return;
}
- mStorage.removeKey(REBOOT_ESCROW_ARMED_KEY, USER_SYSTEM);
+ clearMetricsStorage();
rebootEscrowProvider.clearRebootEscrowKey();
List<UserInfo> users = mUserManager.getUsers();
@@ -486,6 +608,9 @@ class RebootEscrowManager {
return false;
}
+ int actualProviderType = rebootEscrowProvider.getType();
+ // TODO(b/183140900) Fail the reboot if provider type mismatches.
+
RebootEscrowKey escrowKey;
synchronized (mKeyGenerationLock) {
escrowKey = mPendingRebootEscrowKey;
@@ -505,8 +630,14 @@ class RebootEscrowManager {
boolean armedRebootEscrow = rebootEscrowProvider.storeRebootEscrowKey(escrowKey, kk);
if (armedRebootEscrow) {
mStorage.setInt(REBOOT_ESCROW_ARMED_KEY, mInjector.getBootCount(), USER_SYSTEM);
- mStorage.setLong(REBOOT_ESCROW_KEY_ARMED_TIMESTAMP, System.currentTimeMillis(),
+ mStorage.setLong(REBOOT_ESCROW_KEY_ARMED_TIMESTAMP, mInjector.getCurrentTimeMillis(),
+ USER_SYSTEM);
+ // Store the vbmeta digest of both slots.
+ mStorage.setString(REBOOT_ESCROW_KEY_VBMETA_DIGEST, mInjector.getVbmetaDigest(false),
USER_SYSTEM);
+ mStorage.setString(REBOOT_ESCROW_KEY_OTHER_VBMETA_DIGEST,
+ mInjector.getVbmetaDigest(true), USER_SYSTEM);
+ mStorage.setInt(REBOOT_ESCROW_KEY_PROVIDER, actualProviderType, USER_SYSTEM);
mEventLog.addEntry(RebootEscrowEvent.SET_ARMED_STATUS);
}
diff --git a/services/core/java/com/android/server/locksettings/RebootEscrowProviderHalImpl.java b/services/core/java/com/android/server/locksettings/RebootEscrowProviderHalImpl.java
index 4b00772088f2..e8f6f4abd030 100644
--- a/services/core/java/com/android/server/locksettings/RebootEscrowProviderHalImpl.java
+++ b/services/core/java/com/android/server/locksettings/RebootEscrowProviderHalImpl.java
@@ -60,6 +60,11 @@ class RebootEscrowProviderHalImpl implements RebootEscrowProviderInterface {
}
@Override
+ public int getType() {
+ return TYPE_HAL;
+ }
+
+ @Override
public boolean hasRebootEscrowSupport() {
return mInjector.getRebootEscrow() != null;
}
diff --git a/services/core/java/com/android/server/locksettings/RebootEscrowProviderInterface.java b/services/core/java/com/android/server/locksettings/RebootEscrowProviderInterface.java
index af6faad3c76e..e106d817c533 100644
--- a/services/core/java/com/android/server/locksettings/RebootEscrowProviderInterface.java
+++ b/services/core/java/com/android/server/locksettings/RebootEscrowProviderInterface.java
@@ -16,7 +16,11 @@
package com.android.server.locksettings;
+import android.annotation.IntDef;
+
import java.io.IOException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import javax.crypto.SecretKey;
@@ -28,6 +32,21 @@ import javax.crypto.SecretKey;
* @hide
*/
public interface RebootEscrowProviderInterface {
+ @IntDef(prefix = {"TYPE_"}, value = {
+ TYPE_HAL,
+ TYPE_SERVER_BASED,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface RebootEscrowProviderType {
+ }
+ int TYPE_HAL = 0;
+ int TYPE_SERVER_BASED = 1;
+
+ /**
+ * Returns the reboot escrow provider type.
+ */
+ @RebootEscrowProviderType int getType();
+
/**
* Returns true if the secure store/discard of reboot escrow key is supported.
*/
diff --git a/services/core/java/com/android/server/locksettings/RebootEscrowProviderServerBasedImpl.java b/services/core/java/com/android/server/locksettings/RebootEscrowProviderServerBasedImpl.java
index 697bf08a232e..28669875f1cd 100644
--- a/services/core/java/com/android/server/locksettings/RebootEscrowProviderServerBasedImpl.java
+++ b/services/core/java/com/android/server/locksettings/RebootEscrowProviderServerBasedImpl.java
@@ -95,6 +95,11 @@ class RebootEscrowProviderServerBasedImpl implements RebootEscrowProviderInterfa
}
@Override
+ public int getType() {
+ return TYPE_SERVER_BASED;
+ }
+
+ @Override
public boolean hasRebootEscrowSupport() {
return mInjector.getServiceConnection() != null;
}
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java b/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java
index 39ed7e8b1e1a..2e4d41c7d364 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java
@@ -96,9 +96,10 @@ public abstract class NetworkPolicyManagerInternal {
/**
* Notifies that the specified {@link NetworkStatsProvider} has reached its quota
- * which was set through {@link NetworkStatsProvider#onSetLimit(String, long)}.
+ * which was set through {@link NetworkStatsProvider#onSetLimit(String, long)} or
+ * {@link NetworkStatsProvider#onSetWarningAndLimit(String, long, long)}.
*
* @param tag the human readable identifier of the custom network stats provider.
*/
- public abstract void onStatsProviderLimitReached(@NonNull String tag);
+ public abstract void onStatsProviderWarningOrLimitReached(@NonNull String tag);
}
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 46c80e7c44e3..c12785805a2e 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -38,6 +38,15 @@ import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
import static android.content.pm.PackageManager.MATCH_DISABLED_COMPONENTS;
import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_ADMIN_DISABLED;
+import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_DATA_SAVER;
+import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_MASK;
+import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_USER_RESTRICTED;
+import static android.net.ConnectivityManager.BLOCKED_REASON_APP_STANDBY;
+import static android.net.ConnectivityManager.BLOCKED_REASON_BATTERY_SAVER;
+import static android.net.ConnectivityManager.BLOCKED_REASON_DOZE;
+import static android.net.ConnectivityManager.BLOCKED_REASON_NONE;
+import static android.net.ConnectivityManager.BLOCKED_REASON_RESTRICTED_MODE;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLED;
import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED;
@@ -66,15 +75,6 @@ import static android.net.NetworkPolicyManager.ALLOWED_REASON_POWER_SAVE_ALLOWLI
import static android.net.NetworkPolicyManager.ALLOWED_REASON_POWER_SAVE_EXCEPT_IDLE_ALLOWLIST;
import static android.net.NetworkPolicyManager.ALLOWED_REASON_RESTRICTED_MODE_PERMISSIONS;
import static android.net.NetworkPolicyManager.ALLOWED_REASON_SYSTEM;
-import static android.net.NetworkPolicyManager.BLOCKED_METERED_REASON_ADMIN_DISABLED;
-import static android.net.NetworkPolicyManager.BLOCKED_METERED_REASON_DATA_SAVER;
-import static android.net.NetworkPolicyManager.BLOCKED_METERED_REASON_MASK;
-import static android.net.NetworkPolicyManager.BLOCKED_METERED_REASON_USER_RESTRICTED;
-import static android.net.NetworkPolicyManager.BLOCKED_REASON_APP_STANDBY;
-import static android.net.NetworkPolicyManager.BLOCKED_REASON_BATTERY_SAVER;
-import static android.net.NetworkPolicyManager.BLOCKED_REASON_DOZE;
-import static android.net.NetworkPolicyManager.BLOCKED_REASON_NONE;
-import static android.net.NetworkPolicyManager.BLOCKED_REASON_RESTRICTED_MODE;
import static android.net.NetworkPolicyManager.EXTRA_NETWORK_TEMPLATE;
import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT;
import static android.net.NetworkPolicyManager.MASK_ALL_NETWORKS;
@@ -174,12 +174,10 @@ import android.content.res.Resources;
import android.database.ContentObserver;
import android.net.ConnectivityManager;
import android.net.ConnectivityManager.NetworkCallback;
-import android.net.IConnectivityManager;
import android.net.INetworkManagementEventObserver;
import android.net.INetworkPolicyListener;
import android.net.INetworkPolicyManager;
import android.net.INetworkStatsService;
-import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkIdentity;
@@ -425,15 +423,15 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
private static final int MSG_LIMIT_REACHED = 5;
private static final int MSG_RESTRICT_BACKGROUND_CHANGED = 6;
private static final int MSG_ADVISE_PERSIST_THRESHOLD = 7;
- private static final int MSG_UPDATE_INTERFACE_QUOTA = 10;
- private static final int MSG_REMOVE_INTERFACE_QUOTA = 11;
+ private static final int MSG_UPDATE_INTERFACE_QUOTAS = 10;
+ private static final int MSG_REMOVE_INTERFACE_QUOTAS = 11;
private static final int MSG_POLICIES_CHANGED = 13;
private static final int MSG_RESET_FIREWALL_RULES_BY_UID = 15;
private static final int MSG_SUBSCRIPTION_OVERRIDE = 16;
private static final int MSG_METERED_RESTRICTED_PACKAGES_CHANGED = 17;
private static final int MSG_SET_NETWORK_TEMPLATE_ENABLED = 18;
private static final int MSG_SUBSCRIPTION_PLANS_CHANGED = 19;
- private static final int MSG_STATS_PROVIDER_LIMIT_REACHED = 20;
+ private static final int MSG_STATS_PROVIDER_WARNING_OR_LIMIT_REACHED = 20;
// TODO: Add similar docs for other messages.
/**
* Message to indicate that reasons for why an uid is blocked changed.
@@ -1220,10 +1218,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
private static boolean updateCapabilityChange(SparseBooleanArray lastValues, boolean newValue,
Network network) {
- final boolean lastValue = lastValues.get(network.netId, false);
- final boolean changed = (lastValue != newValue) || lastValues.indexOfKey(network.netId) < 0;
+ final boolean lastValue = lastValues.get(network.getNetId(), false);
+ final boolean changed = (lastValue != newValue)
+ || lastValues.indexOfKey(network.getNetId()) < 0;
if (changed) {
- lastValues.put(network.netId, newValue);
+ lastValues.put(network.getNetId(), newValue);
}
return changed;
}
@@ -1246,7 +1245,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
mNetworkRoaming, newRoaming, network);
if (meteredChanged || roamingChanged) {
- mLogger.meterednessChanged(network.netId, newMetered);
+ mLogger.meterednessChanged(network.getNetId(), newMetered);
updateNetworkRulesNL();
}
}
@@ -1922,16 +1921,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
* Collect all ifaces from a {@link NetworkStateSnapshot} into the given set.
*/
private static void collectIfaces(ArraySet<String> ifaces, NetworkStateSnapshot snapshot) {
- final String baseIface = snapshot.linkProperties.getInterfaceName();
- if (baseIface != null) {
- ifaces.add(baseIface);
- }
- for (LinkProperties stackedLink : snapshot.linkProperties.getStackedLinks()) {
- final String stackedIface = stackedLink.getInterfaceName();
- if (stackedIface != null) {
- ifaces.add(stackedIface);
- }
- }
+ ifaces.addAll(snapshot.linkProperties.getAllInterfaceNames());
}
/**
@@ -2012,7 +2002,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
mNetIdToSubId.clear();
final ArrayMap<NetworkStateSnapshot, NetworkIdentity> identified = new ArrayMap<>();
for (final NetworkStateSnapshot snapshot : snapshots) {
- mNetIdToSubId.put(snapshot.network.netId, parseSubId(snapshot));
+ mNetIdToSubId.put(snapshot.network.getNetId(), parseSubId(snapshot));
// Policies matched by NPMS only match by subscriber ID or by ssid. Thus subtype
// in the object created here is never used and its value doesn't matter, so use
@@ -2045,39 +2035,45 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
final boolean hasWarning = policy.warningBytes != LIMIT_DISABLED;
final boolean hasLimit = policy.limitBytes != LIMIT_DISABLED;
- if (hasLimit || policy.metered) {
- final long quotaBytes;
- if (hasLimit && policy.hasCycle()) {
- final Pair<ZonedDateTime, ZonedDateTime> cycle = NetworkPolicyManager
- .cycleIterator(policy).next();
- final long start = cycle.first.toInstant().toEpochMilli();
- final long end = cycle.second.toInstant().toEpochMilli();
- final long totalBytes = getTotalBytes(policy.template, start, end);
-
- if (policy.lastLimitSnooze >= start) {
- // snoozing past quota, but we still need to restrict apps,
- // so push really high quota.
- quotaBytes = Long.MAX_VALUE;
- } else {
- // remaining "quota" bytes are based on total usage in
- // current cycle. kernel doesn't like 0-byte rules, so we
- // set 1-byte quota and disable the radio later.
- quotaBytes = Math.max(1, policy.limitBytes - totalBytes);
- }
- } else {
- // metered network, but no policy limit; we still need to
- // restrict apps, so push really high quota.
- quotaBytes = Long.MAX_VALUE;
+ long limitBytes = Long.MAX_VALUE;
+ long warningBytes = Long.MAX_VALUE;
+ if ((hasLimit || hasWarning) && policy.hasCycle()) {
+ final Pair<ZonedDateTime, ZonedDateTime> cycle = NetworkPolicyManager
+ .cycleIterator(policy).next();
+ final long start = cycle.first.toInstant().toEpochMilli();
+ final long end = cycle.second.toInstant().toEpochMilli();
+ final long totalBytes = getTotalBytes(policy.template, start, end);
+
+ // If the limit notification is not snoozed, the limit quota needs to be calculated.
+ if (hasLimit && policy.lastLimitSnooze < start) {
+ // remaining "quota" bytes are based on total usage in
+ // current cycle. kernel doesn't like 0-byte rules, so we
+ // set 1-byte quota and disable the radio later.
+ limitBytes = Math.max(1, policy.limitBytes - totalBytes);
+ }
+
+ // If the warning notification was snoozed by user, or the service already knows
+ // it is over warning bytes, doesn't need to calculate warning bytes.
+ if (hasWarning && policy.lastWarningSnooze < start
+ && !policy.isOverWarning(totalBytes)) {
+ warningBytes = Math.max(1, policy.warningBytes - totalBytes);
}
+ }
+ if (hasWarning || hasLimit || policy.metered) {
if (matchingIfaces.size() > 1) {
// TODO: switch to shared quota once NMS supports
Slog.w(TAG, "shared quota unsupported; generating rule for each iface");
}
+ // Set the interface warning and limit. For interfaces which has no cycle,
+ // or metered with no policy quotas, or snoozed notification; we still need to put
+ // iptables rule hooks to restrict apps for data saver, so push really high quota.
+ // TODO: Push NetworkStatsProvider.QUOTA_UNLIMITED instead of Long.MAX_VALUE to
+ // providers.
for (int j = matchingIfaces.size() - 1; j >= 0; j--) {
final String iface = matchingIfaces.valueAt(j);
- setInterfaceQuotaAsync(iface, quotaBytes);
+ setInterfaceQuotasAsync(iface, warningBytes, limitBytes);
newMeteredIfaces.add(iface);
}
}
@@ -2100,7 +2096,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
for (int j = matchingIfaces.size() - 1; j >= 0; j--) {
final String iface = matchingIfaces.valueAt(j);
if (!newMeteredIfaces.contains(iface)) {
- setInterfaceQuotaAsync(iface, Long.MAX_VALUE);
+ setInterfaceQuotasAsync(iface, Long.MAX_VALUE, Long.MAX_VALUE);
newMeteredIfaces.add(iface);
}
}
@@ -2112,7 +2108,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
for (int i = mMeteredIfaces.size() - 1; i >= 0; i--) {
final String iface = mMeteredIfaces.valueAt(i);
if (!newMeteredIfaces.contains(iface)) {
- removeInterfaceQuotaAsync(iface);
+ removeInterfaceQuotasAsync(iface);
}
}
mMeteredIfaces = newMeteredIfaces;
@@ -4982,7 +4978,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
mListeners.finishBroadcast();
return true;
}
- case MSG_STATS_PROVIDER_LIMIT_REACHED: {
+ case MSG_STATS_PROVIDER_WARNING_OR_LIMIT_REACHED: {
mNetworkStats.forceUpdate();
synchronized (mNetworkPoliciesSecondLock) {
@@ -5053,19 +5049,20 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
mNetworkStats.advisePersistThreshold(persistThreshold);
return true;
}
- case MSG_UPDATE_INTERFACE_QUOTA: {
- final String iface = (String) msg.obj;
- // int params need to be stitched back into a long
- final long quota = ((long) msg.arg1 << 32) | (msg.arg2 & 0xFFFFFFFFL);
- removeInterfaceQuota(iface);
- setInterfaceQuota(iface, quota);
- mNetworkStats.setStatsProviderLimitAsync(iface, quota);
+ case MSG_UPDATE_INTERFACE_QUOTAS: {
+ final IfaceQuotas val = (IfaceQuotas) msg.obj;
+ // TODO: Consider set a new limit before removing the original one.
+ removeInterfaceLimit(val.iface);
+ setInterfaceLimit(val.iface, val.limit);
+ mNetworkStats.setStatsProviderWarningAndLimitAsync(val.iface, val.warning,
+ val.limit);
return true;
}
- case MSG_REMOVE_INTERFACE_QUOTA: {
+ case MSG_REMOVE_INTERFACE_QUOTAS: {
final String iface = (String) msg.obj;
- removeInterfaceQuota(iface);
- mNetworkStats.setStatsProviderLimitAsync(iface, QUOTA_UNLIMITED);
+ removeInterfaceLimit(iface);
+ mNetworkStats.setStatsProviderWarningAndLimitAsync(iface, QUOTA_UNLIMITED,
+ QUOTA_UNLIMITED);
return true;
}
case MSG_RESET_FIREWALL_RULES_BY_UID: {
@@ -5213,15 +5210,32 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
}
- private void setInterfaceQuotaAsync(String iface, long quotaBytes) {
- // long quotaBytes split up into two ints to fit in message
- mHandler.obtainMessage(MSG_UPDATE_INTERFACE_QUOTA, (int) (quotaBytes >> 32),
- (int) (quotaBytes & 0xFFFFFFFF), iface).sendToTarget();
+ private static final class IfaceQuotas {
+ @NonNull public final String iface;
+ // Warning and limit bytes of interface qutoas, could be QUOTA_UNLIMITED or Long.MAX_VALUE
+ // if not set. 0 is not acceptable since kernel doesn't like 0-byte rules.
+ public final long warning;
+ public final long limit;
+
+ private IfaceQuotas(@NonNull String iface, long warning, long limit) {
+ this.iface = iface;
+ this.warning = warning;
+ this.limit = limit;
+ }
+ }
+
+ private void setInterfaceQuotasAsync(@NonNull String iface,
+ long warningBytes, long limitBytes) {
+ mHandler.obtainMessage(MSG_UPDATE_INTERFACE_QUOTAS,
+ new IfaceQuotas(iface, warningBytes, limitBytes)).sendToTarget();
}
- private void setInterfaceQuota(String iface, long quotaBytes) {
+ private void setInterfaceLimit(String iface, long limitBytes) {
try {
- mNetworkManager.setInterfaceQuota(iface, quotaBytes);
+ // For legacy design the data warning is covered by global alert, where the
+ // kernel will notify upper layer for a small amount of change of traffic
+ // statistics. Thus, passing warning is not needed.
+ mNetworkManager.setInterfaceQuota(iface, limitBytes);
} catch (IllegalStateException e) {
Log.wtf(TAG, "problem setting interface quota", e);
} catch (RemoteException e) {
@@ -5229,11 +5243,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
}
- private void removeInterfaceQuotaAsync(String iface) {
- mHandler.obtainMessage(MSG_REMOVE_INTERFACE_QUOTA, iface).sendToTarget();
+ private void removeInterfaceQuotasAsync(String iface) {
+ mHandler.obtainMessage(MSG_REMOVE_INTERFACE_QUOTAS, iface).sendToTarget();
}
- private void removeInterfaceQuota(String iface) {
+ private void removeInterfaceLimit(String iface) {
try {
mNetworkManager.removeInterfaceQuota(iface);
} catch (IllegalStateException e) {
@@ -5738,9 +5752,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
@Override
- public void onStatsProviderLimitReached(@NonNull String tag) {
- Log.v(TAG, "onStatsProviderLimitReached: " + tag);
- mHandler.obtainMessage(MSG_STATS_PROVIDER_LIMIT_REACHED).sendToTarget();
+ public void onStatsProviderWarningOrLimitReached(@NonNull String tag) {
+ Log.v(TAG, "onStatsProviderWarningOrLimitReached: " + tag);
+ mHandler.obtainMessage(MSG_STATS_PROVIDER_WARNING_OR_LIMIT_REACHED).sendToTarget();
}
}
@@ -5782,7 +5796,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
@GuardedBy("mNetworkPoliciesSecondLock")
private int getSubIdLocked(Network network) {
- return mNetIdToSubId.get(network.netId, INVALID_SUBSCRIPTION_ID);
+ return mNetIdToSubId.get(network.getNetId(), INVALID_SUBSCRIPTION_ID);
}
@GuardedBy("mNetworkPoliciesSecondLock")
diff --git a/services/core/java/com/android/server/net/NetworkStatsManagerInternal.java b/services/core/java/com/android/server/net/NetworkStatsManagerInternal.java
index 0cb0bc2c0896..0e9a9da6804b 100644
--- a/services/core/java/com/android/server/net/NetworkStatsManagerInternal.java
+++ b/services/core/java/com/android/server/net/NetworkStatsManagerInternal.java
@@ -37,8 +37,9 @@ public abstract class NetworkStatsManagerInternal {
public abstract void forceUpdate();
/**
- * Set the quota limit to all registered custom network stats providers.
+ * Set the warning and limit to all registered custom network stats providers.
* Note that invocation of any interface will be sent to all providers.
*/
- public abstract void setStatsProviderLimitAsync(@NonNull String iface, long quota);
+ public abstract void setStatsProviderWarningAndLimitAsync(@NonNull String iface, long warning,
+ long limit);
}
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index 7b376847fd44..19f5e3cd5dfa 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -24,6 +24,7 @@ import static android.content.Intent.ACTION_UID_REMOVED;
import static android.content.Intent.ACTION_USER_REMOVED;
import static android.content.Intent.EXTRA_UID;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkIdentity.SUBTYPE_COMBINED;
import static android.net.NetworkStack.checkNetworkStackPermission;
import static android.net.NetworkStats.DEFAULT_NETWORK_ALL;
@@ -65,6 +66,7 @@ import static android.provider.Settings.Global.NETSTATS_UID_TAG_BUCKET_DURATION;
import static android.provider.Settings.Global.NETSTATS_UID_TAG_DELETE_AGE;
import static android.provider.Settings.Global.NETSTATS_UID_TAG_PERSIST_BYTES;
import static android.provider.Settings.Global.NETSTATS_UID_TAG_ROTATE_AGE;
+import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
import static android.text.format.DateUtils.DAY_IN_MILLIS;
import static android.text.format.DateUtils.HOUR_IN_MILLIS;
import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
@@ -92,7 +94,6 @@ import android.net.DataUsageRequest;
import android.net.INetworkManagementEventObserver;
import android.net.INetworkStatsService;
import android.net.INetworkStatsSession;
-import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkIdentity;
@@ -101,7 +102,9 @@ import android.net.NetworkStateSnapshot;
import android.net.NetworkStats;
import android.net.NetworkStats.NonMonotonicObserver;
import android.net.NetworkStatsHistory;
+import android.net.NetworkSpecifier;
import android.net.NetworkTemplate;
+import android.net.TelephonyNetworkSpecifier;
import android.net.TrafficStats;
import android.net.UnderlyingNetworkInfo;
import android.net.Uri;
@@ -131,6 +134,7 @@ import android.service.NetworkInterfaceProto;
import android.service.NetworkStatsServiceDumpProto;
import android.telephony.PhoneStateListener;
import android.telephony.SubscriptionPlan;
+import android.text.TextUtils;
import android.text.format.DateUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -1320,8 +1324,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
ident.getSubType(), ident.getSubscriberId(), ident.getNetworkId(),
ident.getRoaming(), true /* metered */,
true /* onDefaultNetwork */, ident.getOemManaged());
- findOrCreateNetworkIdentitySet(mActiveIfaces, IFACE_VT).add(vtIdent);
- findOrCreateNetworkIdentitySet(mActiveUidIfaces, IFACE_VT).add(vtIdent);
+ final String ifaceVt = IFACE_VT + getSubIdForMobile(snapshot);
+ findOrCreateNetworkIdentitySet(mActiveIfaces, ifaceVt).add(vtIdent);
+ findOrCreateNetworkIdentitySet(mActiveUidIfaces, ifaceVt).add(vtIdent);
}
if (isMobile) {
@@ -1358,17 +1363,18 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
// (or non eBPF offloaded) TX they would appear on both, however egress interface
// accounting is explicitly bypassed for traffic from the clat uid.
//
- final List<LinkProperties> stackedLinks = snapshot.linkProperties.getStackedLinks();
- for (LinkProperties stackedLink : stackedLinks) {
- final String stackedIface = stackedLink.getInterfaceName();
- if (stackedIface != null) {
- findOrCreateNetworkIdentitySet(mActiveIfaces, stackedIface).add(ident);
- findOrCreateNetworkIdentitySet(mActiveUidIfaces, stackedIface).add(ident);
+ // TODO: This code might be combined to above code.
+ for (String iface : snapshot.linkProperties.getAllInterfaceNames()) {
+ // baseIface has been handled, so ignore it.
+ if (TextUtils.equals(baseIface, iface)) continue;
+ if (iface != null) {
+ findOrCreateNetworkIdentitySet(mActiveIfaces, iface).add(ident);
+ findOrCreateNetworkIdentitySet(mActiveUidIfaces, iface).add(ident);
if (isMobile) {
- mobileIfaces.add(stackedIface);
+ mobileIfaces.add(iface);
}
- mStatsFactory.noteStackedIface(stackedIface, baseIface);
+ mStatsFactory.noteStackedIface(iface, baseIface);
}
}
}
@@ -1376,6 +1382,20 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
mMobileIfaces = mobileIfaces.toArray(new String[mobileIfaces.size()]);
}
+ private static int getSubIdForMobile(@NonNull NetworkStateSnapshot state) {
+ if (!state.networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
+ throw new IllegalArgumentException("Mobile state need capability TRANSPORT_CELLULAR");
+ }
+
+ final NetworkSpecifier spec = state.networkCapabilities.getNetworkSpecifier();
+ if (spec instanceof TelephonyNetworkSpecifier) {
+ return ((TelephonyNetworkSpecifier) spec).getSubscriptionId();
+ } else {
+ Slog.wtf(TAG, "getSubIdForState invalid NetworkSpecifier");
+ return INVALID_SUBSCRIPTION_ID;
+ }
+ }
+
/**
* For networks with {@code TRANSPORT_CELLULAR}, get subType that was obtained through
* {@link PhoneStateListener}. Otherwise, return 0 given that other networks with different
@@ -1673,9 +1693,14 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
}
@Override
- public void setStatsProviderLimitAsync(@NonNull String iface, long quota) {
- if (LOGV) Slog.v(TAG, "setStatsProviderLimitAsync(" + iface + "," + quota + ")");
- invokeForAllStatsProviderCallbacks((cb) -> cb.mProvider.onSetLimit(iface, quota));
+ public void setStatsProviderWarningAndLimitAsync(
+ @NonNull String iface, long warning, long limit) {
+ if (LOGV) {
+ Slog.v(TAG, "setStatsProviderWarningAndLimitAsync("
+ + iface + "," + warning + "," + limit + ")");
+ }
+ invokeForAllStatsProviderCallbacks((cb) -> cb.mProvider.onSetWarningAndLimit(iface,
+ warning, limit));
}
}
@@ -2070,10 +2095,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
}
@Override
- public void notifyLimitReached() {
- Log.d(TAG, mTag + ": onLimitReached");
+ public void notifyWarningOrLimitReached() {
+ Log.d(TAG, mTag + ": notifyWarningOrLimitReached");
LocalServices.getService(NetworkPolicyManagerInternal.class)
- .onStatsProviderLimitReached(mTag);
+ .onStatsProviderWarningOrLimitReached(mTag);
}
@Override
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index 7d1827d1b6e2..0c1ba962323f 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -32,6 +32,7 @@ import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
+import android.app.ActivityManager;
import android.app.AppOpsManager;
import android.app.Notification;
import android.app.NotificationChannel;
@@ -177,6 +178,8 @@ public class PreferencesHelper implements RankingConfig {
private Map<String, List<String>> mOemLockedApps = new HashMap();
+ private int mCurrentUserId = UserHandle.USER_NULL;
+
public PreferencesHelper(Context context, PackageManager pm, RankingHandler rankingHandler,
ZenModeHelper zenHelper, NotificationChannelLogger notificationChannelLogger,
AppOpsManager appOpsManager,
@@ -191,7 +194,8 @@ public class PreferencesHelper implements RankingConfig {
updateBadgingEnabled();
updateBubblesEnabled();
- syncChannelsBypassingDnd(mContext.getUserId());
+ mCurrentUserId = ActivityManager.getCurrentUser();
+ syncChannelsBypassingDnd();
}
public void readXml(XmlPullParser parser, boolean forRestore, int userId)
@@ -790,7 +794,7 @@ public class PreferencesHelper implements RankingConfig {
// but the system can
if (group.isBlocked() != oldGroup.isBlocked()) {
group.lockFields(NotificationChannelGroup.USER_LOCKED_BLOCKED_STATE);
- updateChannelsBypassingDnd(mContext.getUserId());
+ updateChannelsBypassingDnd();
}
}
}
@@ -871,13 +875,13 @@ public class PreferencesHelper implements RankingConfig {
// fields on the channel yet
if (existing.getUserLockedFields() == 0 && hasDndAccess) {
boolean bypassDnd = channel.canBypassDnd();
- if (bypassDnd != existing.canBypassDnd()) {
+ if (bypassDnd != existing.canBypassDnd() || wasUndeleted) {
existing.setBypassDnd(bypassDnd);
needsPolicyFileChange = true;
if (bypassDnd != mAreChannelsBypassingDnd
|| previousExistingImportance != existing.getImportance()) {
- updateChannelsBypassingDnd(mContext.getUserId());
+ updateChannelsBypassingDnd();
}
}
}
@@ -941,7 +945,7 @@ public class PreferencesHelper implements RankingConfig {
r.channels.put(channel.getId(), channel);
if (channel.canBypassDnd() != mAreChannelsBypassingDnd) {
- updateChannelsBypassingDnd(mContext.getUserId());
+ updateChannelsBypassingDnd();
}
MetricsLogger.action(getChannelLog(channel, pkg).setType(
com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_OPEN));
@@ -1013,7 +1017,7 @@ public class PreferencesHelper implements RankingConfig {
if (updatedChannel.canBypassDnd() != mAreChannelsBypassingDnd
|| channel.getImportance() != updatedChannel.getImportance()) {
- updateChannelsBypassingDnd(mContext.getUserId());
+ updateChannelsBypassingDnd();
}
}
updateConfig();
@@ -1110,7 +1114,7 @@ public class PreferencesHelper implements RankingConfig {
mNotificationChannelLogger.logNotificationChannelDeleted(channel, uid, pkg);
if (mAreChannelsBypassingDnd && channel.canBypassDnd()) {
- updateChannelsBypassingDnd(mContext.getUserId());
+ updateChannelsBypassingDnd();
}
}
}
@@ -1454,7 +1458,7 @@ public class PreferencesHelper implements RankingConfig {
}
}
if (!deletedChannelIds.isEmpty() && mAreChannelsBypassingDnd) {
- updateChannelsBypassingDnd(mContext.getUserId());
+ updateChannelsBypassingDnd();
}
return deletedChannelIds;
}
@@ -1600,29 +1604,29 @@ public class PreferencesHelper implements RankingConfig {
}
/**
- * Syncs {@link #mAreChannelsBypassingDnd} with the user's notification policy before
+ * Syncs {@link #mAreChannelsBypassingDnd} with the current user's notification policy before
* updating
- * @param userId
*/
- private void syncChannelsBypassingDnd(int userId) {
+ private void syncChannelsBypassingDnd() {
mAreChannelsBypassingDnd = (mZenModeHelper.getNotificationPolicy().state
& NotificationManager.Policy.STATE_CHANNELS_BYPASSING_DND) == 1;
- updateChannelsBypassingDnd(userId);
+ updateChannelsBypassingDnd();
}
/**
- * Updates the user's NotificationPolicy based on whether the given userId
+ * Updates the user's NotificationPolicy based on whether the current userId
* has channels bypassing DND
* @param userId
*/
- private void updateChannelsBypassingDnd(int userId) {
+ private void updateChannelsBypassingDnd() {
synchronized (mPackagePreferences) {
final int numPackagePreferences = mPackagePreferences.size();
for (int i = 0; i < numPackagePreferences; i++) {
final PackagePreferences r = mPackagePreferences.valueAt(i);
- // Package isn't associated with this userId or notifications from this package are
- // blocked
- if (userId != UserHandle.getUserId(r.uid) || r.importance == IMPORTANCE_NONE) {
+ // Package isn't associated with the current userId or notifications from this
+ // package are blocked
+ if (mCurrentUserId != UserHandle.getUserId(r.uid)
+ || r.importance == IMPORTANCE_NONE) {
continue;
}
@@ -2168,14 +2172,16 @@ public class PreferencesHelper implements RankingConfig {
* Called when user switches
*/
public void onUserSwitched(int userId) {
- syncChannelsBypassingDnd(userId);
+ mCurrentUserId = userId;
+ syncChannelsBypassingDnd();
}
/**
* Called when user is unlocked
*/
public void onUserUnlocked(int userId) {
- syncChannelsBypassingDnd(userId);
+ mCurrentUserId = userId;
+ syncChannelsBypassingDnd();
}
public void onUserRemoved(int userId) {
diff --git a/services/core/java/com/android/server/os/NativeTombstoneManager.java b/services/core/java/com/android/server/os/NativeTombstoneManager.java
index cc6a8243799d..ed1f5f567d95 100644
--- a/services/core/java/com/android/server/os/NativeTombstoneManager.java
+++ b/services/core/java/com/android/server/os/NativeTombstoneManager.java
@@ -392,7 +392,7 @@ public final class NativeTombstoneManager {
int pid = 0;
int uid = 0;
- String processName = "";
+ String processName = null;
String crashReason = "";
String selinuxLabel = "";
@@ -407,8 +407,10 @@ public final class NativeTombstoneManager {
uid = stream.readInt(Tombstone.UID);
break;
- case (int) Tombstone.PROCESS_NAME:
- processName = stream.readString(Tombstone.PROCESS_NAME);
+ case (int) Tombstone.COMMAND_LINE:
+ if (processName == null) {
+ processName = stream.readString(Tombstone.COMMAND_LINE);
+ }
break;
case (int) Tombstone.CAUSES:
@@ -472,7 +474,7 @@ public final class NativeTombstoneManager {
result.mAppId = appId;
result.mPid = pid;
result.mUid = uid;
- result.mProcessName = processName;
+ result.mProcessName = processName == null ? "" : processName;
result.mTimestampMs = timestampMs;
result.mCrashReason = crashReason;
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index 5d8b75d2af4e..37b9d5649d7d 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -51,8 +51,8 @@ import android.os.FileUtils;
import android.os.PowerManager;
import android.os.SystemClock;
import android.os.SystemProperties;
-import android.os.UserHandle;
import android.os.Trace;
+import android.os.UserHandle;
import android.os.WorkSource;
import android.os.storage.StorageManager;
import android.util.Log;
@@ -258,22 +258,22 @@ public class PackageDexOptimizer {
packageStats, options.isDowngrade(), profileName, dexMetadataPath,
options.getCompilationReason());
- // Only report metrics for base apk for now.
- // TODO: add ISA and APK type to metrics.
- if (pkg.getBaseCodePath().equals(path)) {
+ // OTAPreopt doesn't have stats so don't report in that case.
+ if (packageStats != null) {
Trace.traceBegin(Trace.TRACE_TAG_PACKAGE_MANAGER, "dex2oat-metrics");
try {
long sessionId = Math.randomLongInternal();
ArtStatsLogUtils.writeStatsLog(
mArtStatsLogger,
sessionId,
- path,
compilerFilter,
sharedGid,
packageStats.getCompileTime(path),
dexMetadataPath,
options.getCompilationReason(),
- newResult);
+ newResult,
+ ArtStatsLogUtils.getApkType(path),
+ dexCodeIsa);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_PACKAGE_MANAGER);
}
diff --git a/services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java b/services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java
index c8dc1b1ff562..f99a3c330c32 100644
--- a/services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java
+++ b/services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java
@@ -39,6 +39,7 @@ public class ArtStatsLogUtils {
private static final String TAG = ArtStatsLogUtils.class.getSimpleName();
private static final String PROFILE_DEX_METADATA = "primary.prof";
private static final String VDEX_DEX_METADATA = "primary.vdex";
+ private static final String BASE_APK= "base.apk";
private static final int ART_COMPILATION_REASON_INSTALL_BULK_SECONDARY =
@@ -122,16 +123,34 @@ public class ArtStatsLogUtils {
ART_COMPILATION_FILTER_FAKE_RUN_FROM_VDEX_FALLBACK);
}
+ private static final Map<String, Integer> ISA_MAP = new HashMap();
+
+ static {
+ COMPILE_FILTER_MAP.put("arm", ArtStatsLog.
+ ART_DATUM_REPORTED__ISA__ART_ISA_ARM);
+ COMPILE_FILTER_MAP.put("arm64", ArtStatsLog.
+ ART_DATUM_REPORTED__ISA__ART_ISA_ARM64);
+ COMPILE_FILTER_MAP.put("x86", ArtStatsLog.
+ ART_DATUM_REPORTED__ISA__ART_ISA_X86);
+ COMPILE_FILTER_MAP.put("x86_64", ArtStatsLog.
+ ART_DATUM_REPORTED__ISA__ART_ISA_X86_64);
+ COMPILE_FILTER_MAP.put("mips", ArtStatsLog.
+ ART_DATUM_REPORTED__ISA__ART_ISA_MIPS);
+ COMPILE_FILTER_MAP.put("mips64", ArtStatsLog.
+ ART_DATUM_REPORTED__ISA__ART_ISA_MIPS64);
+ }
+
public static void writeStatsLog(
ArtStatsLogger logger,
long sessionId,
- String path,
String compilerFilter,
int uid,
long compileTime,
String dexMetadataPath,
int compilationReason,
- int result) {
+ int result,
+ int apkType,
+ String isa) {
int dexMetadataType = getDexMetadataType(dexMetadataPath);
logger.write(
sessionId,
@@ -140,7 +159,9 @@ public class ArtStatsLogUtils {
compilerFilter,
ArtStatsLog.ART_DATUM_REPORTED__KIND__ART_DATUM_DEX2OAT_RESULT_CODE,
result,
- dexMetadataType);
+ dexMetadataType,
+ apkType,
+ isa);
logger.write(
sessionId,
uid,
@@ -148,7 +169,16 @@ public class ArtStatsLogUtils {
compilerFilter,
ArtStatsLog.ART_DATUM_REPORTED__KIND__ART_DATUM_DEX2OAT_TOTAL_TIME,
compileTime,
- dexMetadataType);
+ dexMetadataType,
+ apkType,
+ isa);
+ }
+
+ public static int getApkType(String path) {
+ if (path.equals(BASE_APK)) {
+ return ArtStatsLog.ART_DATUM_REPORTED__APK_TYPE__ART_APK_TYPE_BASE;
+ }
+ return ArtStatsLog.ART_DATUM_REPORTED__APK_TYPE__ART_APK_TYPE_SPLIT;
}
private static int getDexMetadataType(String dexMetadataPath) {
@@ -207,7 +237,9 @@ public class ArtStatsLogUtils {
String compilerFilter,
int kind,
long value,
- int dexMetadataType) {
+ int dexMetadataType,
+ int apkType,
+ String isa) {
ArtStatsLog.write(
ArtStatsLog.ART_DATUM_REPORTED,
sessionId,
@@ -220,7 +252,10 @@ public class ArtStatsLogUtils {
ArtStatsLog.ART_DATUM_REPORTED__THREAD_TYPE__ART_THREAD_MAIN,
kind,
value,
- dexMetadataType);
+ dexMetadataType,
+ apkType,
+ ISA_MAP.getOrDefault(isa,
+ ArtStatsLog.ART_DATUM_REPORTED__ISA__ART_ISA_UNKNOWN));
}
}
}
diff --git a/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java b/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java
index 0a6772bd8f6a..fe21201f5cb7 100644
--- a/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java
+++ b/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java
@@ -734,7 +734,15 @@ public class RecoverySystemService extends IRecoverySystem.Stub implements Reboo
return REBOOT_ERROR_SLOT_MISMATCH;
}
- if (!mInjector.getLockSettingsService().armRebootEscrow()) {
+ final long origId = Binder.clearCallingIdentity();
+ boolean result;
+ try {
+ result = mInjector.getLockSettingsService().armRebootEscrow();
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+
+ if (!result) {
Slog.w(TAG, "Failure to escrow key for reboot");
return REBOOT_ERROR_ARM_REBOOT_ESCROW_FAILURE;
}
@@ -742,11 +750,20 @@ public class RecoverySystemService extends IRecoverySystem.Stub implements Reboo
return REBOOT_ERROR_NONE;
}
+ private boolean useServerBasedRoR() {
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ return DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_OTA,
+ "server_based_ror_enabled", false);
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
+
private void reportMetricsOnRebootWithLskf(String packageName, boolean slotSwitch,
@ResumeOnRebootRebootErrorCode int errorCode) {
int uid = mInjector.getUidFromPackageName(packageName);
- boolean serverBased = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_OTA,
- "server_based_ror_enabled", false);
+ boolean serverBased = useServerBasedRoR();
int preparedClientCount;
synchronized (this) {
preparedClientCount = mCallerPreparedForReboot.size();
diff --git a/services/core/java/com/android/server/stats/StatsHelper.java b/services/core/java/com/android/server/stats/StatsHelper.java
new file mode 100644
index 000000000000..9b9f6b502f2c
--- /dev/null
+++ b/services/core/java/com/android/server/stats/StatsHelper.java
@@ -0,0 +1,45 @@
+/*
+ * 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.stats;
+
+import static android.app.StatsManager.ACTION_STATSD_STARTED;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.content.Context;
+import android.content.Intent;
+import android.os.UserHandle;
+
+/**
+ * Provides helper methods for the Statsd APEX
+ *
+ * @hide
+ **/
+@SystemApi(client = SystemApi.Client.SYSTEM_SERVER)
+public final class StatsHelper {
+ private StatsHelper() {}
+
+ /**
+ * Send statsd ready broadcast
+ *
+ **/
+ public static void sendStatsdReadyBroadcast(@NonNull final Context context) {
+ context.sendBroadcastAsUser(
+ new Intent(ACTION_STATSD_STARTED).addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND),
+ UserHandle.SYSTEM, android.Manifest.permission.DUMP);
+ }
+}
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java
index 35194658a48f..85d2d39d7a1d 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorCallbackImpl.java
@@ -20,7 +20,7 @@ import android.annotation.Nullable;
import android.app.AlarmManager;
import android.content.ContentResolver;
import android.content.Context;
-import android.net.ConnectivityManager;
+import android.content.pm.PackageManager;
import android.os.SystemProperties;
import android.provider.Settings;
@@ -52,9 +52,7 @@ public final class TimeZoneDetectorCallbackImpl implements TimeZoneDetectorStrat
}
private boolean deviceHasTelephonyNetwork() {
- // TODO b/150583524 Avoid the use of a deprecated API.
- return mContext.getSystemService(ConnectivityManager.class)
- .isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
+ return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY);
}
@Override
diff --git a/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java b/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java
index 8dcc547508ec..6ff8d6f8ba94 100644
--- a/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java
+++ b/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java
@@ -290,25 +290,6 @@ public class UnderlyingNetworkTracker {
maybeNotifyCallback();
}
- private void handleNetworkSuspended(@NonNull Network network, boolean isSuspended) {
- mVcnContext.ensureRunningOnLooperThread();
-
- if (!isSameNetwork(mRecordInProgress, network)) {
- Slog.wtf(TAG, "Invalid update to isSuspended");
- return;
- }
-
- final NetworkCapabilities newCaps =
- new NetworkCapabilities(mRecordInProgress.getNetworkCapabilities());
- if (isSuspended) {
- newCaps.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED);
- } else {
- newCaps.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED);
- }
-
- handleCapabilitiesChanged(network, newCaps);
- }
-
private void handlePropertiesChanged(
@NonNull Network network, @NonNull LinkProperties linkProperties) {
mVcnContext.ensureRunningOnLooperThread();
@@ -366,20 +347,11 @@ public class UnderlyingNetworkTracker {
@Override
public void onCapabilitiesChanged(
@NonNull Network network, @NonNull NetworkCapabilities networkCapabilities) {
+ if (networkCapabilities.equals(mRecordInProgress.getNetworkCapabilities())) return;
handleCapabilitiesChanged(network, networkCapabilities);
}
@Override
- public void onNetworkSuspended(@NonNull Network network) {
- handleNetworkSuspended(network, true /* isSuspended */);
- }
-
- @Override
- public void onNetworkResumed(@NonNull Network network) {
- handleNetworkSuspended(network, false /* isSuspended */);
- }
-
- @Override
public void onLinkPropertiesChanged(
@NonNull Network network, @NonNull LinkProperties linkProperties) {
handlePropertiesChanged(network, linkProperties);
diff --git a/services/core/java/com/android/server/vcn/Vcn.java b/services/core/java/com/android/server/vcn/Vcn.java
index 3f74938005a7..89ed956b3aef 100644
--- a/services/core/java/com/android/server/vcn/Vcn.java
+++ b/services/core/java/com/android/server/vcn/Vcn.java
@@ -41,6 +41,7 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
+import java.util.Map.Entry;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -110,6 +111,24 @@ public class Vcn extends Handler {
@NonNull private final VcnNetworkRequestListener mRequestListener;
@NonNull private final VcnCallback mVcnCallback;
+ /**
+ * Map containing all VcnGatewayConnections and their VcnGatewayConnectionConfigs.
+ *
+ * <p>Due to potential for race conditions, VcnGatewayConnections MUST only be created and added
+ * to this map in {@link #handleNetworkRequested(NetworkRequest, int, int)}, when a VCN receives
+ * a NetworkRequest that matches a VcnGatewayConnectionConfig for this VCN's VcnConfig.
+ *
+ * <p>A VcnGatewayConnection instance MUST NEVER overwrite an existing instance - otherwise
+ * there is potential for a orphaned VcnGatewayConnection instance that does not get properly
+ * shut down.
+ *
+ * <p>Due to potential for race conditions, VcnGatewayConnections MUST only be removed from this
+ * map once they have finished tearing down, which is reported to this VCN via {@link
+ * VcnGatewayStatusCallback#onQuit()}. Once this is done, all NetworkRequests are retrieved from
+ * the NetworkProvider so that another VcnGatewayConnectionConfig can match the
+ * previously-matched request.
+ */
+ // TODO(b/182533200): remove the invariant on VcnGatewayConnection lifecycles
@NonNull
private final Map<VcnGatewayConnectionConfig, VcnGatewayConnection> mVcnGatewayConnections =
new HashMap<>();
@@ -191,6 +210,19 @@ public class Vcn extends Handler {
return Collections.unmodifiableSet(new HashSet<>(mVcnGatewayConnections.values()));
}
+ /** Get current Configs and Gateways for testing purposes */
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ public Map<VcnGatewayConnectionConfig, VcnGatewayConnection>
+ getVcnGatewayConnectionConfigMap() {
+ return Collections.unmodifiableMap(new HashMap<>(mVcnGatewayConnections));
+ }
+
+ /** Set whether this Vcn is active for testing purposes */
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ public void setIsActive(boolean isActive) {
+ mIsActive.set(isActive);
+ }
+
private class VcnNetworkRequestListener implements VcnNetworkProvider.NetworkRequestListener {
@Override
public void onNetworkRequested(@NonNull NetworkRequest request, int score, int providerId) {
@@ -202,11 +234,6 @@ public class Vcn extends Handler {
@Override
public void handleMessage(@NonNull Message msg) {
- // Ignore if this Vcn is not active and we're not receiving new configs
- if (!isActive() && msg.what != MSG_EVENT_CONFIG_UPDATED) {
- return;
- }
-
switch (msg.what) {
case MSG_EVENT_CONFIG_UPDATED:
handleConfigUpdated((VcnConfig) msg.obj);
@@ -237,9 +264,31 @@ public class Vcn extends Handler {
mConfig = config;
- // TODO(b/181815405): Reevaluate active VcnGatewayConnection(s)
+ if (mIsActive.getAndSet(true)) {
+ // VCN is already active - teardown any GatewayConnections whose configs have been
+ // removed and get all current requests
+ for (final Entry<VcnGatewayConnectionConfig, VcnGatewayConnection> entry :
+ mVcnGatewayConnections.entrySet()) {
+ final VcnGatewayConnectionConfig gatewayConnectionConfig = entry.getKey();
+ final VcnGatewayConnection gatewayConnection = entry.getValue();
+
+ // GatewayConnectionConfigs must match exactly (otherwise authentication or
+ // connection details may have changed).
+ if (!mConfig.getGatewayConnectionConfigs().contains(gatewayConnectionConfig)) {
+ if (gatewayConnection == null) {
+ Slog.wtf(
+ getLogTag(),
+ "Found gatewayConnectionConfig without GatewayConnection");
+ } else {
+ gatewayConnection.teardownAsynchronously();
+ }
+ }
+ }
- if (!mIsActive.getAndSet(true)) {
+ // Trigger a re-evaluation of all NetworkRequests (to make sure any that can be
+ // satisfied start a new GatewayConnection)
+ mVcnContext.getVcnNetworkProvider().resendAllRequests(mRequestListener);
+ } else {
// If this VCN was not previously active, it is exiting Safe Mode. Re-register the
// request listener to get NetworkRequests again (and all cached requests).
mVcnContext.getVcnNetworkProvider().registerListener(mRequestListener);
@@ -259,13 +308,16 @@ public class Vcn extends Handler {
private void handleEnterSafeMode() {
handleTeardown();
- mVcnGatewayConnections.clear();
-
mVcnCallback.onEnteredSafeMode();
}
private void handleNetworkRequested(
@NonNull NetworkRequest request, int score, int providerId) {
+ if (!isActive()) {
+ Slog.v(getLogTag(), "Received NetworkRequest while inactive. Ignore for now");
+ return;
+ }
+
if (score > getNetworkScore()) {
if (VDBG) {
Slog.v(
@@ -318,8 +370,10 @@ public class Vcn extends Handler {
mVcnGatewayConnections.remove(config);
// Trigger a re-evaluation of all NetworkRequests (to make sure any that can be satisfied
- // start a new GatewayConnection)
- mVcnContext.getVcnNetworkProvider().resendAllRequests(mRequestListener);
+ // start a new GatewayConnection), but only if the Vcn is still active
+ if (isActive()) {
+ mVcnContext.getVcnNetworkProvider().resendAllRequests(mRequestListener);
+ }
}
private void handleSubscriptionsChanged(@NonNull TelephonySubscriptionSnapshot snapshot) {
diff --git a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
index a262939c0ef9..1208eccc69eb 100644
--- a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
+++ b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
@@ -30,6 +30,8 @@ import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UpdateEngine;
import android.os.UpdateEngineCallback;
+import android.os.UserHandle;
+import android.os.UserManager;
import android.provider.DeviceConfig;
import android.util.Log;
@@ -295,10 +297,56 @@ public final class ProfcollectForwardingService extends SystemService {
return;
}
- try {
- mIProfcollect.report();
- } catch (RemoteException e) {
- Log.e(LOG_TAG, e.getMessage());
+ final boolean uploadReport =
+ DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PROFCOLLECT_NATIVE_BOOT,
+ "upload_report", false);
+
+ new Thread(() -> {
+ try {
+ String reportUuid = mIProfcollect.report();
+
+ if (!uploadReport) {
+ return;
+ }
+
+ final int profileId = getBBProfileId();
+ mIProfcollect.copy_report_to_bb(profileId, reportUuid);
+ String reportPath =
+ "/data/user/" + profileId
+ + "/com.google.android.apps.internal.betterbug/cache/"
+ + reportUuid + ".zip";
+ Intent uploadIntent =
+ new Intent("com.google.android.apps.betterbug.intent.action.UPLOAD_PROFILE")
+ .setPackage("com.google.android.apps.internal.betterbug")
+ .putExtra("EXTRA_DESTINATION", "PROFCOLLECT")
+ .putExtra("EXTRA_PACKAGE_NAME", getContext().getPackageName())
+ .putExtra("EXTRA_PROFILE_PATH", reportPath)
+ .addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+ Context context = getContext();
+ if (context.getPackageManager().queryBroadcastReceivers(uploadIntent, 0) != null) {
+ context.sendBroadcast(uploadIntent);
+ }
+ mIProfcollect.delete_report(reportUuid);
+ } catch (RemoteException e) {
+ Log.e(LOG_TAG, e.getMessage());
+ }
+ }).start();
+ }
+
+ /**
+ * Get BetterBug's profile ID. It is the work profile ID, if it exists. Otherwise the system
+ * user ID.
+ *
+ * @return BetterBug's profile ID.
+ */
+ private int getBBProfileId() {
+ UserManager userManager = UserManager.get(getContext());
+ int[] profiles = userManager.getProfileIds(UserHandle.USER_SYSTEM, false);
+ for (int p : profiles) {
+ if (userManager.getUserInfo(p).isManagedProfile()) {
+ return p;
+ }
}
+ return UserHandle.USER_SYSTEM;
}
}
diff --git a/services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java b/services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java
index 1b8ab2175458..2f0d71a2a579 100644
--- a/services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/apphibernation/AppHibernationServiceTest.java
@@ -58,6 +58,7 @@ import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.Executor;
/**
* Tests for {@link com.android.server.apphibernation.AppHibernationService}
@@ -116,8 +117,8 @@ public final class AppHibernationServiceTest {
mAppHibernationService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
UserInfo userInfo = addUser(USER_ID_1);
- mAppHibernationService.onUserUnlocking(new SystemService.TargetUser(userInfo));
doReturn(true).when(mUserManager).isUserUnlockingOrUnlocked(USER_ID_1);
+ mAppHibernationService.onUserUnlocking(new SystemService.TargetUser(userInfo));
mAppHibernationService.mIsServiceEnabled = true;
}
@@ -150,8 +151,8 @@ public final class AppHibernationServiceTest {
throws RemoteException {
// WHEN a new user is added and a package from the user is hibernated
UserInfo user2 = addUser(USER_ID_2);
- mAppHibernationService.onUserUnlocking(new SystemService.TargetUser(user2));
doReturn(true).when(mUserManager).isUserUnlockingOrUnlocked(USER_ID_2);
+ mAppHibernationService.onUserUnlocking(new SystemService.TargetUser(user2));
mAppHibernationService.setHibernatingForUser(PACKAGE_NAME_1, USER_ID_2, true);
// THEN the new user's package is hibernated
@@ -188,8 +189,8 @@ public final class AppHibernationServiceTest {
// GIVEN an unlocked user with all packages installed
UserInfo userInfo =
addUser(USER_ID_2, new String[]{PACKAGE_NAME_1, PACKAGE_NAME_2, PACKAGE_NAME_3});
- mAppHibernationService.onUserUnlocking(new SystemService.TargetUser(userInfo));
doReturn(true).when(mUserManager).isUserUnlockingOrUnlocked(USER_ID_2);
+ mAppHibernationService.onUserUnlocking(new SystemService.TargetUser(userInfo));
// WHEN packages are hibernated for the user
mAppHibernationService.setHibernatingForUser(PACKAGE_NAME_1, USER_ID_2, true);
@@ -259,6 +260,12 @@ public final class AppHibernationServiceTest {
}
@Override
+ public Executor getBackgroundExecutor() {
+ // Just execute immediately in tests.
+ return r -> r.run();
+ }
+
+ @Override
public HibernationStateDiskStore<GlobalLevelState> getGlobalLevelDiskStore() {
return Mockito.mock(HibernationStateDiskStore.class);
}
diff --git a/services/tests/servicestests/src/com/android/server/compat/CompatConfigBuilder.java b/services/tests/servicestests/src/com/android/server/compat/CompatConfigBuilder.java
index fcd6b842426a..7bdc87ef6bd7 100644
--- a/services/tests/servicestests/src/com/android/server/compat/CompatConfigBuilder.java
+++ b/services/tests/servicestests/src/com/android/server/compat/CompatConfigBuilder.java
@@ -116,7 +116,7 @@ class CompatConfigBuilder {
}
CompatConfigBuilder addOverridableChangeWithId(long id) {
- mChanges.add(new CompatChange(id, "", -1, -1, false, true, "", true));
+ mChanges.add(new CompatChange(id, "", -1, -1, true, false, "", true));
return this;
}
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 bd774056aef8..a866363f46e6 100644
--- a/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/compat/CompatConfigTest.java
@@ -260,6 +260,36 @@ public class CompatConfigTest {
}
@Test
+ public void testInstallerCanSetOverrides() throws Exception {
+ final long changeId = 1234L;
+ final int installerUid = 23;
+ CompatConfig compatConfig = CompatConfigBuilder.create(mBuildClassifier, mContext)
+ .addOverridableChangeWithId(1234L)
+ .build();
+ ApplicationInfo applicationInfo = ApplicationInfoBuilder.create()
+ .withPackageName("com.some.package")
+ .build();
+ PackageManager packageManager = mock(PackageManager.class);
+ when(mContext.getPackageManager()).thenReturn(packageManager);
+ when(packageManager.getApplicationInfo(eq("com.some.package"), anyInt()))
+ .thenReturn(applicationInfo);
+
+ // Force the validator to prevent overriding the change by using a user build.
+ when(mBuildClassifier.isDebuggableBuild()).thenReturn(false);
+ when(mBuildClassifier.isFinalBuild()).thenReturn(true);
+
+ CompatibilityOverrideConfig config = new CompatibilityOverrideConfig(
+ Collections.singletonMap(1234L,
+ new PackageOverride.Builder()
+ .setMaxVersionCode(99L)
+ .setEnabled(true)
+ .build()));
+
+ compatConfig.addOverrides(config, "com.some.package");
+ assertThat(compatConfig.isChangeEnabled(1234L, applicationInfo)).isTrue();
+ }
+
+ @Test
public void testApplyDeferredOverridesAfterInstallingApp() throws Exception {
ApplicationInfo applicationInfo = ApplicationInfoBuilder.create()
.withPackageName("com.notinstalled.foo")
@@ -639,9 +669,18 @@ public class CompatConfigTest {
.build());
when(mPackageManager.getApplicationInfo(eq("bar.baz"), anyInt()))
.thenThrow(new NameNotFoundException());
-
- compatConfig.addOverride(1L, "foo.bar", true);
- compatConfig.addOverride(2L, "bar.baz", false);
+ compatConfig.addOverrides(
+ new CompatibilityOverrideConfig(
+ Collections.singletonMap(
+ 1L,
+ new PackageOverride.Builder().setEnabled(true).build())),
+ "foo.bar");
+ compatConfig.addOverrides(
+ new CompatibilityOverrideConfig(
+ Collections.singletonMap(
+ 2L,
+ new PackageOverride.Builder().setEnabled(false).build())),
+ "bar.baz");
assertThat(readFile(overridesFile)).isEqualTo("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
+ "<overrides>\n"
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 3fc6e9918382..a2664e5f3b0a 100644
--- a/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java
+++ b/services/tests/servicestests/src/com/android/server/compat/PlatformCompatTest.java
@@ -113,7 +113,7 @@ public class PlatformCompatTest {
new CompatibilityChangeInfo(
6L, "", Build.VERSION_CODES.R, -1, false, false, "", false),
new CompatibilityChangeInfo(7L, "", -1, -1, false, true, "", false),
- new CompatibilityChangeInfo(8L, "", -1, -1, false, true, "", true));
+ new CompatibilityChangeInfo(8L, "", -1, -1, true, false, "", true));
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/content/OWNERS b/services/tests/servicestests/src/com/android/server/content/OWNERS
new file mode 100644
index 000000000000..6264a1427c7f
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/content/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/content/OWNERS
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 91342ce925f6..8c08226201a8 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java
@@ -21,6 +21,7 @@ import static android.content.pm.UserInfo.FLAG_PRIMARY;
import static android.content.pm.UserInfo.FLAG_PROFILE;
import static android.os.UserHandle.USER_SYSTEM;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
@@ -110,6 +111,10 @@ public class RebootEscrowManagerTests {
public interface MockableRebootEscrowInjected {
int getBootCount();
+ long getCurrentTimeMillis();
+
+ boolean forceServerBased();
+
void reportMetric(boolean success, int errorCode, int serviceType, int attemptCount,
int escrowDurationInSeconds, int vbmetaDigestStatus, int durationSinceBootComplete);
}
@@ -174,6 +179,9 @@ public class RebootEscrowManagerTests {
@Override
public boolean serverBasedResumeOnReboot() {
+ if (mInjected.forceServerBased()) {
+ return true;
+ }
return mServerBased;
}
@@ -205,9 +213,20 @@ public class RebootEscrowManagerTests {
}
@Override
+ public String getVbmetaDigest(boolean other) {
+ return other ? "" : "fake digest";
+ }
+
+ @Override
+ public long getCurrentTimeMillis() {
+ return mInjected.getCurrentTimeMillis();
+ }
+
+ @Override
public void reportMetric(boolean success, int errorCode, int serviceType, int attemptCount,
int escrowDurationInSeconds, int vbmetaDigestStatus,
int durationSinceBootComplete) {
+
mInjected.reportMetric(success, errorCode, serviceType, attemptCount,
escrowDurationInSeconds, vbmetaDigestStatus, durationSinceBootComplete);
}
@@ -430,16 +449,21 @@ public class RebootEscrowManagerTests {
// pretend reboot happens here
when(mInjected.getBootCount()).thenReturn(1);
+ when(mInjected.getCurrentTimeMillis()).thenReturn(30000L);
+ mStorage.setLong(RebootEscrowManager.REBOOT_ESCROW_KEY_ARMED_TIMESTAMP, 10000L,
+ USER_SYSTEM);
ArgumentCaptor<Boolean> metricsSuccessCaptor = ArgumentCaptor.forClass(Boolean.class);
doNothing().when(mInjected).reportMetric(metricsSuccessCaptor.capture(),
eq(0) /* error code */, eq(1) /* HAL based */, eq(1) /* attempt count */,
- anyInt(), anyInt(), anyInt());
+ eq(20), eq(0) /* vbmeta status */, anyInt());
when(mRebootEscrow.retrieveKey()).thenAnswer(invocation -> keyByteCaptor.getValue());
mService.loadRebootEscrowDataIfAvailable(null);
verify(mRebootEscrow).retrieveKey();
assertTrue(metricsSuccessCaptor.getValue());
verify(mKeyStoreManager).clearKeyStoreEncryptionKey();
+ assertEquals(mStorage.getLong(RebootEscrowManager.REBOOT_ESCROW_KEY_ARMED_TIMESTAMP,
+ -1, USER_SYSTEM), -1);
}
@Test
@@ -468,7 +492,7 @@ public class RebootEscrowManagerTests {
ArgumentCaptor<Boolean> metricsSuccessCaptor = ArgumentCaptor.forClass(Boolean.class);
doNothing().when(mInjected).reportMetric(metricsSuccessCaptor.capture(),
eq(0) /* error code */, eq(2) /* Server based */, eq(1) /* attempt count */,
- anyInt(), anyInt(), anyInt());
+ anyInt(), eq(0) /* vbmeta status */, anyInt());
when(mServiceConnection.unwrap(any(), anyLong()))
.thenAnswer(invocation -> invocation.getArgument(0));
@@ -479,6 +503,84 @@ public class RebootEscrowManagerTests {
}
@Test
+ public void loadRebootEscrowDataIfAvailable_ServerBasedRemoteException_Failure()
+ throws Exception {
+ setServerBasedRebootEscrowProvider();
+
+ when(mInjected.getBootCount()).thenReturn(0);
+ RebootEscrowListener mockListener = mock(RebootEscrowListener.class);
+ mService.setRebootEscrowListener(mockListener);
+ mService.prepareRebootEscrow();
+
+ clearInvocations(mServiceConnection);
+ mService.callToRebootEscrowIfNeeded(PRIMARY_USER_ID, FAKE_SP_VERSION, FAKE_AUTH_TOKEN);
+ verify(mockListener).onPreparedForReboot(eq(true));
+ verify(mServiceConnection, never()).wrapBlob(any(), anyLong(), anyLong());
+
+ // Use x -> x for both wrap & unwrap functions.
+ when(mServiceConnection.wrapBlob(any(), anyLong(), anyLong()))
+ .thenAnswer(invocation -> invocation.getArgument(0));
+ assertTrue(mService.armRebootEscrowIfNeeded());
+ verify(mServiceConnection).wrapBlob(any(), anyLong(), anyLong());
+ assertTrue(mStorage.hasRebootEscrowServerBlob());
+
+ // pretend reboot happens here
+ when(mInjected.getBootCount()).thenReturn(1);
+ ArgumentCaptor<Boolean> metricsSuccessCaptor = ArgumentCaptor.forClass(Boolean.class);
+ ArgumentCaptor<Integer> metricsErrorCodeCaptor = ArgumentCaptor.forClass(Integer.class);
+ doNothing().when(mInjected).reportMetric(metricsSuccessCaptor.capture(),
+ metricsErrorCodeCaptor.capture(), eq(2) /* Server based */,
+ eq(1) /* attempt count */, anyInt(), eq(0) /* vbmeta status */, anyInt());
+
+ when(mServiceConnection.unwrap(any(), anyLong())).thenThrow(RemoteException.class);
+ mService.loadRebootEscrowDataIfAvailable(null);
+ verify(mServiceConnection).unwrap(any(), anyLong());
+ assertFalse(metricsSuccessCaptor.getValue());
+ assertEquals(Integer.valueOf(RebootEscrowManager.ERROR_LOAD_ESCROW_KEY),
+ metricsErrorCodeCaptor.getValue());
+ }
+
+ @Test
+ public void loadRebootEscrowDataIfAvailable_ServerBasedIoError_RetryFailure() throws Exception {
+ setServerBasedRebootEscrowProvider();
+
+ when(mInjected.getBootCount()).thenReturn(0);
+ RebootEscrowListener mockListener = mock(RebootEscrowListener.class);
+ mService.setRebootEscrowListener(mockListener);
+ mService.prepareRebootEscrow();
+
+ clearInvocations(mServiceConnection);
+ mService.callToRebootEscrowIfNeeded(PRIMARY_USER_ID, FAKE_SP_VERSION, FAKE_AUTH_TOKEN);
+ verify(mockListener).onPreparedForReboot(eq(true));
+ verify(mServiceConnection, never()).wrapBlob(any(), anyLong(), anyLong());
+
+ // Use x -> x for both wrap & unwrap functions.
+ when(mServiceConnection.wrapBlob(any(), anyLong(), anyLong()))
+ .thenAnswer(invocation -> invocation.getArgument(0));
+ assertTrue(mService.armRebootEscrowIfNeeded());
+ verify(mServiceConnection).wrapBlob(any(), anyLong(), anyLong());
+ assertTrue(mStorage.hasRebootEscrowServerBlob());
+
+ // pretend reboot happens here
+ when(mInjected.getBootCount()).thenReturn(1);
+ ArgumentCaptor<Boolean> metricsSuccessCaptor = ArgumentCaptor.forClass(Boolean.class);
+ ArgumentCaptor<Integer> metricsErrorCodeCaptor = ArgumentCaptor.forClass(Integer.class);
+ doNothing().when(mInjected).reportMetric(metricsSuccessCaptor.capture(),
+ metricsErrorCodeCaptor.capture(), eq(2) /* Server based */,
+ eq(2) /* attempt count */, anyInt(), eq(0) /* vbmeta status */, anyInt());
+ when(mServiceConnection.unwrap(any(), anyLong())).thenThrow(IOException.class);
+
+ HandlerThread thread = new HandlerThread("RebootEscrowManagerTest");
+ thread.start();
+ mService.loadRebootEscrowDataIfAvailable(new Handler(thread.getLooper()));
+ // Sleep 5s for the retry to complete
+ Thread.sleep(5 * 1000);
+ assertFalse(metricsSuccessCaptor.getValue());
+ assertEquals(Integer.valueOf(RebootEscrowManager.ERROR_RETRY_COUNT_EXHAUSTED),
+ metricsErrorCodeCaptor.getValue());
+ }
+
+ @Test
public void loadRebootEscrowDataIfAvailable_ServerBased_RetrySuccess() throws Exception {
setServerBasedRebootEscrowProvider();
@@ -607,9 +709,14 @@ public class RebootEscrowManagerTests {
when(mInjected.getBootCount()).thenReturn(10);
when(mRebootEscrow.retrieveKey()).thenAnswer(invocation -> keyByteCaptor.getValue());
+ // Trigger a vbmeta digest mismatch
+ mStorage.setString(RebootEscrowManager.REBOOT_ESCROW_KEY_VBMETA_DIGEST,
+ "non sense value", USER_SYSTEM);
mService.loadRebootEscrowDataIfAvailable(null);
verify(mInjected).reportMetric(eq(true), eq(0) /* error code */, eq(1) /* HAL based */,
- eq(1) /* attempt count */, anyInt(), anyInt(), anyInt());
+ eq(1) /* attempt count */, anyInt(), eq(2) /* vbmeta status */, anyInt());
+ assertEquals(mStorage.getString(RebootEscrowManager.REBOOT_ESCROW_KEY_VBMETA_DIGEST,
+ "", USER_SYSTEM), "");
}
@Test
@@ -636,12 +743,17 @@ public class RebootEscrowManagerTests {
when(mInjected.getBootCount()).thenReturn(1);
ArgumentCaptor<Boolean> metricsSuccessCaptor = ArgumentCaptor.forClass(Boolean.class);
+ ArgumentCaptor<Integer> metricsErrorCodeCaptor = ArgumentCaptor.forClass(Integer.class);
+ // Return a null escrow key
doNothing().when(mInjected).reportMetric(metricsSuccessCaptor.capture(),
- anyInt() /* error code */, eq(1) /* HAL based */, eq(1) /* attempt count */,
- anyInt(), anyInt(), anyInt());
- when(mRebootEscrow.retrieveKey()).thenAnswer(invocation -> new byte[32]);
+ metricsErrorCodeCaptor.capture(), eq(1) /* HAL based */,
+ eq(1) /* attempt count */, anyInt(), anyInt(), anyInt());
+
+ when(mRebootEscrow.retrieveKey()).thenAnswer(invocation -> null);
mService.loadRebootEscrowDataIfAvailable(null);
verify(mRebootEscrow).retrieveKey();
assertFalse(metricsSuccessCaptor.getValue());
+ assertEquals(Integer.valueOf(RebootEscrowManager.ERROR_LOAD_ESCROW_KEY),
+ metricsErrorCodeCaptor.getValue());
}
}
diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
index fb01ff6e16c6..100d3ea87a89 100644
--- a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
@@ -1773,57 +1773,75 @@ public class NetworkPolicyManagerServiceTest {
true);
}
+ private void increaseMockedTotalBytes(NetworkStats stats, long rxBytes, long txBytes) {
+ stats.insertEntry(TEST_IFACE, UID_A, SET_ALL, TAG_NONE,
+ rxBytes, 1, txBytes, 1, 0);
+ when(mStatsService.getNetworkTotalBytes(any(), anyLong(), anyLong()))
+ .thenReturn(stats.getTotalBytes());
+ when(mStatsService.getNetworkUidBytes(any(), anyLong(), anyLong()))
+ .thenReturn(stats);
+ }
+
+ private void triggerOnStatsProviderWarningOrLimitReached() throws InterruptedException {
+ final NetworkPolicyManagerInternal npmi = LocalServices
+ .getService(NetworkPolicyManagerInternal.class);
+ npmi.onStatsProviderWarningOrLimitReached("TEST");
+ // Wait for processing of MSG_STATS_PROVIDER_WARNING_OR_LIMIT_REACHED.
+ postMsgAndWaitForCompletion();
+ verify(mStatsService).forceUpdate();
+ // Wait for processing of MSG_*_INTERFACE_QUOTAS.
+ postMsgAndWaitForCompletion();
+ }
+
/**
- * Test that when StatsProvider triggers limit reached, new limit will be calculated and
- * re-armed.
+ * Test that when StatsProvider triggers warning and limit reached, new quotas will be
+ * calculated and re-armed.
*/
@Test
- public void testStatsProviderLimitReached() throws Exception {
+ public void testStatsProviderWarningAndLimitReached() throws Exception {
final int CYCLE_DAY = 15;
final NetworkStats stats = new NetworkStats(0L, 1);
- stats.insertEntry(TEST_IFACE, UID_A, SET_ALL, TAG_NONE,
- 2999, 1, 2000, 1, 0);
- when(mStatsService.getNetworkTotalBytes(any(), anyLong(), anyLong()))
- .thenReturn(stats.getTotalBytes());
- when(mStatsService.getNetworkUidBytes(any(), anyLong(), anyLong()))
- .thenReturn(stats);
+ increaseMockedTotalBytes(stats, 2999, 2000);
// Get active mobile network in place
expectMobileDefaults();
mService.updateNetworks();
- verify(mStatsService).setStatsProviderLimitAsync(TEST_IFACE, Long.MAX_VALUE);
+ verify(mStatsService).setStatsProviderWarningAndLimitAsync(TEST_IFACE, Long.MAX_VALUE,
+ Long.MAX_VALUE);
- // Set limit to 10KB.
+ // Set warning to 7KB and limit to 10KB.
setNetworkPolicies(new NetworkPolicy(
- sTemplateMobileAll, CYCLE_DAY, TIMEZONE_UTC, WARNING_DISABLED, 10000L,
- true));
+ sTemplateMobileAll, CYCLE_DAY, TIMEZONE_UTC, 7000L, 10000L, true));
postMsgAndWaitForCompletion();
- // Verifies that remaining quota is set to providers.
- verify(mStatsService).setStatsProviderLimitAsync(TEST_IFACE, 10000L - 4999L);
-
+ // Verifies that remaining quotas are set to providers.
+ verify(mStatsService).setStatsProviderWarningAndLimitAsync(TEST_IFACE, 2001L, 5001L);
reset(mStatsService);
- // Increase the usage.
- stats.insertEntry(TEST_IFACE, UID_A, SET_ALL, TAG_NONE,
- 1000, 1, 999, 1, 0);
- when(mStatsService.getNetworkTotalBytes(any(), anyLong(), anyLong()))
- .thenReturn(stats.getTotalBytes());
- when(mStatsService.getNetworkUidBytes(any(), anyLong(), anyLong()))
- .thenReturn(stats);
+ // Increase the usage and simulates that limit reached fires earlier by provider,
+ // but actually the quota is not yet reached. Verifies that the limit reached leads to
+ // a force update and new quotas should be set.
+ increaseMockedTotalBytes(stats, 1000, 999);
+ triggerOnStatsProviderWarningOrLimitReached();
+ verify(mStatsService).setStatsProviderWarningAndLimitAsync(TEST_IFACE, 2L, 3002L);
+ reset(mStatsService);
- // Simulates that limit reached fires earlier by provider, but actually the quota is not
- // yet reached.
- final NetworkPolicyManagerInternal npmi = LocalServices
- .getService(NetworkPolicyManagerInternal.class);
- npmi.onStatsProviderLimitReached("TEST");
+ // Increase the usage and simulate warning reached, the new warning should be unlimited
+ // since service will disable warning quota to stop lower layer from keep triggering
+ // warning reached event.
+ increaseMockedTotalBytes(stats, 1000L, 1000);
+ triggerOnStatsProviderWarningOrLimitReached();
+ verify(mStatsService).setStatsProviderWarningAndLimitAsync(
+ TEST_IFACE, Long.MAX_VALUE, 1002L);
+ reset(mStatsService);
- // Verifies that the limit reached leads to a force update and new limit should be set.
- postMsgAndWaitForCompletion();
- verify(mStatsService).forceUpdate();
- postMsgAndWaitForCompletion();
- verify(mStatsService).setStatsProviderLimitAsync(TEST_IFACE, 10000L - 4999L - 1999L);
+ // Increase the usage that over the warning and limit, the new limit should set to 1 to
+ // block the network traffic.
+ increaseMockedTotalBytes(stats, 1000L, 1000);
+ triggerOnStatsProviderWarningOrLimitReached();
+ verify(mStatsService).setStatsProviderWarningAndLimitAsync(TEST_IFACE, Long.MAX_VALUE, 1L);
+ reset(mStatsService);
}
/**
diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/ArtStatsLogUtilsTest.java b/services/tests/servicestests/src/com/android/server/pm/dex/ArtStatsLogUtilsTest.java
index 13d75a77507f..f014119319e9 100644
--- a/services/tests/servicestests/src/com/android/server/pm/dex/ArtStatsLogUtilsTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/ArtStatsLogUtilsTest.java
@@ -22,6 +22,7 @@ import com.android.internal.art.ArtStatsLog;
import com.android.server.pm.dex.ArtStatsLogUtils.ArtStatsLogger;
import org.junit.AfterClass;
+import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
@@ -49,6 +50,9 @@ public final class ArtStatsLogUtilsTest {
private static final String COMPILER_FILTER = "space-profile";
private static final String PROFILE_DEX_METADATA = "primary.prof";
private static final String VDEX_DEX_METADATA = "primary.vdex";
+ private static final String INSTRUCTION_SET = "arm64";
+ private static final String BASE_APK = "base.apk";
+ private static final String SPLIT_APK = "split.apk";
private static final byte[] DEX_CONTENT = "dexData".getBytes();
private static final int COMPILATION_REASON = 1;
private static final int RESULT_CODE = 222;
@@ -97,17 +101,18 @@ public final class ArtStatsLogUtilsTest {
ArtStatsLogUtils.writeStatsLog(
mockLogger,
SESSION_ID,
- apk.toString(),
COMPILER_FILTER,
UID,
COMPILE_TIME,
dexMetadataPath.toString(),
COMPILATION_REASON,
- RESULT_CODE);
+ RESULT_CODE,
+ ArtStatsLog.ART_DATUM_REPORTED__APK_TYPE__ART_APK_TYPE_BASE,
+ INSTRUCTION_SET);
// Assert
verifyWrites(ArtStatsLog.
- ART_DATUM_REPORTED__DEX_METADATA_TYPE__ART_DEX_METADATA_TYPE_PROFILE_AND_VDEX);
+ ART_DATUM_REPORTED__DEX_METADATA_TYPE__ART_DEX_METADATA_TYPE_PROFILE_AND_VDEX);
} finally {
deleteSliently(dexMetadataPath);
deleteSliently(apk);
@@ -127,17 +132,18 @@ public final class ArtStatsLogUtilsTest {
ArtStatsLogUtils.writeStatsLog(
mockLogger,
SESSION_ID,
- apk.toString(),
COMPILER_FILTER,
UID,
COMPILE_TIME,
dexMetadataPath.toString(),
COMPILATION_REASON,
- RESULT_CODE);
+ RESULT_CODE,
+ ArtStatsLog.ART_DATUM_REPORTED__APK_TYPE__ART_APK_TYPE_BASE,
+ INSTRUCTION_SET);
// Assert
verifyWrites(ArtStatsLog.
- ART_DATUM_REPORTED__DEX_METADATA_TYPE__ART_DEX_METADATA_TYPE_PROFILE);
+ ART_DATUM_REPORTED__DEX_METADATA_TYPE__ART_DEX_METADATA_TYPE_PROFILE);
} finally {
deleteSliently(dexMetadataPath);
deleteSliently(apk);
@@ -157,17 +163,18 @@ public final class ArtStatsLogUtilsTest {
ArtStatsLogUtils.writeStatsLog(
mockLogger,
SESSION_ID,
- apk.toString(),
COMPILER_FILTER,
UID,
COMPILE_TIME,
dexMetadataPath.toString(),
COMPILATION_REASON,
- RESULT_CODE);
+ RESULT_CODE,
+ ArtStatsLog.ART_DATUM_REPORTED__APK_TYPE__ART_APK_TYPE_BASE,
+ INSTRUCTION_SET);
// Assert
verifyWrites(ArtStatsLog.
- ART_DATUM_REPORTED__DEX_METADATA_TYPE__ART_DEX_METADATA_TYPE_VDEX);
+ ART_DATUM_REPORTED__DEX_METADATA_TYPE__ART_DEX_METADATA_TYPE_VDEX);
} finally {
deleteSliently(dexMetadataPath);
deleteSliently(apk);
@@ -185,17 +192,18 @@ public final class ArtStatsLogUtilsTest {
ArtStatsLogUtils.writeStatsLog(
mockLogger,
SESSION_ID,
- apk.toString(),
COMPILER_FILTER,
UID,
COMPILE_TIME,
/*dexMetadataPath=*/ null,
COMPILATION_REASON,
- RESULT_CODE);
+ RESULT_CODE,
+ ArtStatsLog.ART_DATUM_REPORTED__APK_TYPE__ART_APK_TYPE_BASE,
+ INSTRUCTION_SET);
// Assert
verifyWrites(ArtStatsLog.
- ART_DATUM_REPORTED__DEX_METADATA_TYPE__ART_DEX_METADATA_TYPE_NONE);
+ ART_DATUM_REPORTED__DEX_METADATA_TYPE__ART_DEX_METADATA_TYPE_NONE);
} finally {
deleteSliently(apk);
}
@@ -214,23 +222,35 @@ public final class ArtStatsLogUtilsTest {
ArtStatsLogUtils.writeStatsLog(
mockLogger,
SESSION_ID,
- apk.toString(),
COMPILER_FILTER,
UID,
COMPILE_TIME,
dexMetadataPath.toString(),
COMPILATION_REASON,
- RESULT_CODE);
+ RESULT_CODE,
+ ArtStatsLog.ART_DATUM_REPORTED__APK_TYPE__ART_APK_TYPE_BASE,
+ INSTRUCTION_SET);
// Assert
verifyWrites(ArtStatsLog.
- ART_DATUM_REPORTED__DEX_METADATA_TYPE__ART_DEX_METADATA_TYPE_UNKNOWN);
+ ART_DATUM_REPORTED__DEX_METADATA_TYPE__ART_DEX_METADATA_TYPE_UNKNOWN);
} finally {
deleteSliently(dexMetadataPath);
deleteSliently(apk);
}
}
+ @Test
+ public void testGetApkType() {
+ // Act
+ int result1 = ArtStatsLogUtils.getApkType(BASE_APK);
+ int result2 = ArtStatsLogUtils.getApkType(SPLIT_APK);
+
+ // Assert
+ Assert.assertEquals(result1, ArtStatsLog.ART_DATUM_REPORTED__APK_TYPE__ART_APK_TYPE_BASE);
+ Assert.assertEquals(result2, ArtStatsLog.ART_DATUM_REPORTED__APK_TYPE__ART_APK_TYPE_SPLIT);
+ }
+
private void verifyWrites(int dexMetadataType) {
InOrder inorder = inOrder(mockLogger);
inorder.verify(mockLogger).write(
@@ -239,7 +259,9 @@ public final class ArtStatsLogUtilsTest {
COMPILER_FILTER,
ArtStatsLog.ART_DATUM_REPORTED__KIND__ART_DATUM_DEX2OAT_RESULT_CODE,
RESULT_CODE,
- dexMetadataType);
+ dexMetadataType,
+ ArtStatsLog.ART_DATUM_REPORTED__APK_TYPE__ART_APK_TYPE_BASE,
+ INSTRUCTION_SET);
inorder.verify(mockLogger).write(
SESSION_ID,
UID,
@@ -247,7 +269,9 @@ public final class ArtStatsLogUtilsTest {
COMPILER_FILTER,
ArtStatsLog.ART_DATUM_REPORTED__KIND__ART_DATUM_DEX2OAT_TOTAL_TIME,
COMPILE_TIME,
- dexMetadataType);
+ dexMetadataType,
+ ArtStatsLog.ART_DATUM_REPORTED__APK_TYPE__ART_APK_TYPE_BASE,
+ INSTRUCTION_SET);
}
private Path zipFiles(String suffix, Path... files) throws IOException {
diff --git a/services/tests/servicestests/utils-mockito/com/android/server/testutils/OWNERS b/services/tests/servicestests/utils-mockito/com/android/server/testutils/OWNERS
new file mode 100644
index 000000000000..d825dfd7cf00
--- /dev/null
+++ b/services/tests/servicestests/utils-mockito/com/android/server/testutils/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/pm/OWNERS
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 4259831c15f8..ee89e1c840d6 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -833,10 +833,10 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
@Test
public void testDefaultAssistant_overrideDefault() {
- final int userId = 0;
+ final int userId = mContext.getUserId();
final String testComponent = "package/class";
final List<UserInfo> userInfos = new ArrayList<>();
- userInfos.add(new UserInfo(0, "", 0));
+ userInfos.add(new UserInfo(userId, "", 0));
final ArraySet<ComponentName> validAssistants = new ArraySet<>();
validAssistants.add(ComponentName.unflattenFromString(testComponent));
when(mActivityManager.isLowRamDevice()).thenReturn(false);
@@ -2393,7 +2393,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
.thenReturn(mTestNotificationChannel);
reset(mListeners);
- mBinderService.updateNotificationChannelForPackage(PKG, 0, mTestNotificationChannel);
+ mBinderService.updateNotificationChannelForPackage(PKG, mUid, mTestNotificationChannel);
verify(mListeners, times(1)).notifyNotificationChannelChanged(eq(PKG),
eq(Process.myUserHandle()), eq(mTestNotificationChannel),
eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED));
@@ -2929,7 +2929,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
@Test
public void testSetListenerAccessForUser() throws Exception {
- UserHandle user = UserHandle.of(10);
+ UserHandle user = UserHandle.of(mContext.getUserId() + 10);
ComponentName c = ComponentName.unflattenFromString("package/Component");
mBinderService.setNotificationListenerAccessGrantedForUser(c, user.getIdentifier(), true);
@@ -2945,20 +2945,20 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
@Test
public void testSetAssistantAccessForUser() throws Exception {
- UserHandle user = UserHandle.of(10);
- List<UserInfo> uis = new ArrayList<>();
UserInfo ui = new UserInfo();
- ui.id = 10;
+ ui.id = mContext.getUserId() + 10;
+ UserHandle user = UserHandle.of(ui.id);
+ List<UserInfo> uis = new ArrayList<>();
uis.add(ui);
ComponentName c = ComponentName.unflattenFromString("package/Component");
- when(mUm.getEnabledProfiles(10)).thenReturn(uis);
+ when(mUm.getEnabledProfiles(ui.id)).thenReturn(uis);
mBinderService.setNotificationAssistantAccessGrantedForUser(c, user.getIdentifier(), true);
verify(mContext, times(1)).sendBroadcastAsUser(any(), eq(user), any());
verify(mAssistants, times(1)).setPackageOrComponentEnabled(
c.flattenToString(), user.getIdentifier(), true, true);
- verify(mAssistants).setUserSet(10, true);
+ verify(mAssistants).setUserSet(ui.id, true);
verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
c.flattenToString(), user.getIdentifier(), false, true);
verify(mListeners, never()).setPackageOrComponentEnabled(
@@ -2967,7 +2967,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
@Test
public void testGetAssistantAllowedForUser() throws Exception {
- UserHandle user = UserHandle.of(10);
+ UserHandle user = UserHandle.of(mContext.getUserId() + 10);
try {
mBinderService.getAllowedNotificationAssistantForUser(user.getIdentifier());
} catch (IllegalStateException e) {
@@ -2987,12 +2987,12 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
throw e;
}
}
- verify(mAssistants, times(1)).getAllowedComponents(0);
+ verify(mAssistants, times(1)).getAllowedComponents(mContext.getUserId());
}
@Test
public void testSetDndAccessForUser() throws Exception {
- UserHandle user = UserHandle.of(10);
+ UserHandle user = UserHandle.of(mContext.getUserId() + 10);
ComponentName c = ComponentName.unflattenFromString("package/Component");
mBinderService.setNotificationPolicyAccessGrantedForUser(
c.getPackageName(), user.getIdentifier(), true);
@@ -3012,9 +3012,9 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
mBinderService.setNotificationListenerAccessGranted(c, true);
verify(mListeners, times(1)).setPackageOrComponentEnabled(
- c.flattenToString(), 0, true, true);
+ c.flattenToString(), mContext.getUserId(), true, true);
verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
- c.flattenToString(), 0, false, true);
+ c.flattenToString(), mContext.getUserId(), false, true);
verify(mAssistants, never()).setPackageOrComponentEnabled(
any(), anyInt(), anyBoolean(), anyBoolean());
}
@@ -3023,7 +3023,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
public void testSetAssistantAccess() throws Exception {
List<UserInfo> uis = new ArrayList<>();
UserInfo ui = new UserInfo();
- ui.id = 0;
+ ui.id = mContext.getUserId();
uis.add(ui);
when(mUm.getEnabledProfiles(ui.id)).thenReturn(uis);
ComponentName c = ComponentName.unflattenFromString("package/Component");
@@ -3031,9 +3031,9 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
mBinderService.setNotificationAssistantAccessGranted(c, true);
verify(mAssistants, times(1)).setPackageOrComponentEnabled(
- c.flattenToString(), 0, true, true);
+ c.flattenToString(), ui.id, true, true);
verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
- c.flattenToString(), 0, false, true);
+ c.flattenToString(), ui.id, false, true);
verify(mListeners, never()).setPackageOrComponentEnabled(
any(), anyInt(), anyBoolean(), anyBoolean());
}
@@ -3042,10 +3042,10 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
public void testSetAssistantAccess_multiProfile() throws Exception {
List<UserInfo> uis = new ArrayList<>();
UserInfo ui = new UserInfo();
- ui.id = 0;
+ ui.id = mContext.getUserId();
uis.add(ui);
UserInfo ui10 = new UserInfo();
- ui10.id = 10;
+ ui10.id = mContext.getUserId() + 10;
uis.add(ui10);
when(mUm.getEnabledProfiles(ui.id)).thenReturn(uis);
ComponentName c = ComponentName.unflattenFromString("package/Component");
@@ -3053,13 +3053,13 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
mBinderService.setNotificationAssistantAccessGranted(c, true);
verify(mAssistants, times(1)).setPackageOrComponentEnabled(
- c.flattenToString(), 0, true, true);
+ c.flattenToString(), ui.id, true, true);
verify(mAssistants, times(1)).setPackageOrComponentEnabled(
- c.flattenToString(), 10, true, true);
+ c.flattenToString(), ui10.id, true, true);
verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
- c.flattenToString(), 0, false, true);
+ c.flattenToString(), ui.id, false, true);
verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
- c.flattenToString(), 10, false, true);
+ c.flattenToString(), ui10.id, false, true);
verify(mListeners, never()).setPackageOrComponentEnabled(
any(), anyInt(), anyBoolean(), anyBoolean());
}
@@ -3072,16 +3072,16 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
when(mAssistants.getAllowedComponents(anyInt())).thenReturn(componentList);
List<UserInfo> uis = new ArrayList<>();
UserInfo ui = new UserInfo();
- ui.id = 0;
+ ui.id = mContext.getUserId();
uis.add(ui);
when(mUm.getEnabledProfiles(ui.id)).thenReturn(uis);
mBinderService.setNotificationAssistantAccessGranted(null, true);
verify(mAssistants, times(1)).setPackageOrComponentEnabled(
- c.flattenToString(), 0, true, false);
+ c.flattenToString(), ui.id, true, false);
verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
- c.flattenToString(), 0, false, false);
+ c.flattenToString(), ui.id, false, false);
verify(mListeners, never()).setPackageOrComponentEnabled(
any(), anyInt(), anyBoolean(), anyBoolean());
}
@@ -3090,21 +3090,21 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
public void testSetAssistantAccessForUser_nullWithAllowedAssistant() throws Exception {
List<UserInfo> uis = new ArrayList<>();
UserInfo ui = new UserInfo();
- ui.id = 10;
+ ui.id = mContext.getUserId() + 10;
uis.add(ui);
UserHandle user = ui.getUserHandle();
ArrayList<ComponentName> componentList = new ArrayList<>();
ComponentName c = ComponentName.unflattenFromString("package/Component");
componentList.add(c);
when(mAssistants.getAllowedComponents(anyInt())).thenReturn(componentList);
- when(mUm.getEnabledProfiles(10)).thenReturn(uis);
+ when(mUm.getEnabledProfiles(ui.id)).thenReturn(uis);
mBinderService.setNotificationAssistantAccessGrantedForUser(
null, user.getIdentifier(), true);
verify(mAssistants, times(1)).setPackageOrComponentEnabled(
c.flattenToString(), user.getIdentifier(), true, false);
- verify(mAssistants).setUserSet(10, true);
+ verify(mAssistants).setUserSet(ui.id, true);
verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
c.flattenToString(), user.getIdentifier(), false, false);
verify(mListeners, never()).setPackageOrComponentEnabled(
@@ -3116,10 +3116,10 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
throws Exception {
List<UserInfo> uis = new ArrayList<>();
UserInfo ui = new UserInfo();
- ui.id = 0;
+ ui.id = mContext.getUserId();
uis.add(ui);
UserInfo ui10 = new UserInfo();
- ui10.id = 10;
+ ui10.id = mContext.getUserId() + 10;
uis.add(ui10);
UserHandle user = ui.getUserHandle();
ArrayList<ComponentName> componentList = new ArrayList<>();
@@ -3135,8 +3135,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
c.flattenToString(), user.getIdentifier(), true, false);
verify(mAssistants, times(1)).setPackageOrComponentEnabled(
c.flattenToString(), ui10.id, true, false);
- verify(mAssistants).setUserSet(0, true);
- verify(mAssistants).setUserSet(10, true);
+ verify(mAssistants).setUserSet(ui.id, true);
+ verify(mAssistants).setUserSet(ui10.id, true);
verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
c.flattenToString(), user.getIdentifier(), false, false);
verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
@@ -3152,7 +3152,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
mBinderService.setNotificationPolicyAccessGranted(c.getPackageName(), true);
verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
- c.getPackageName(), 0, true, true);
+ c.getPackageName(), mContext.getUserId(), true, true);
verify(mAssistants, never()).setPackageOrComponentEnabled(
any(), anyInt(), anyBoolean(), anyBoolean());
verify(mListeners, never()).setPackageOrComponentEnabled(
@@ -3179,7 +3179,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
ComponentName c = ComponentName.unflattenFromString("package/Component");
List<UserInfo> uis = new ArrayList<>();
UserInfo ui = new UserInfo();
- ui.id = 0;
+ ui.id = mContext.getUserId();
uis.add(ui);
when(mUm.getEnabledProfiles(ui.id)).thenReturn(uis);
@@ -3214,9 +3214,9 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
mBinderService.setNotificationListenerAccessGranted(c, true);
verify(mListeners, times(1)).setPackageOrComponentEnabled(
- c.flattenToString(), 0, true, true);
+ c.flattenToString(), mContext.getUserId(), true, true);
verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
- c.flattenToString(), 0, false, true);
+ c.flattenToString(), mContext.getUserId(), false, true);
verify(mAssistants, never()).setPackageOrComponentEnabled(
any(), anyInt(), anyBoolean(), anyBoolean());
}
@@ -3228,7 +3228,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
ComponentName c = ComponentName.unflattenFromString("package/Component");
List<UserInfo> uis = new ArrayList<>();
UserInfo ui = new UserInfo();
- ui.id = 0;
+ ui.id = mContext.getUserId();
uis.add(ui);
when(mUm.getEnabledProfiles(ui.id)).thenReturn(uis);
@@ -3237,9 +3237,9 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
verify(mListeners, never()).setPackageOrComponentEnabled(
anyString(), anyInt(), anyBoolean(), anyBoolean());
verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
- c.flattenToString(), 0, false, true);
+ c.flattenToString(), ui.id, false, true);
verify(mAssistants, times(1)).setPackageOrComponentEnabled(
- c.flattenToString(), 0, true, true);
+ c.flattenToString(), ui.id, true, true);
}
@Test
@@ -3253,7 +3253,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
verify(mListeners, never()).setPackageOrComponentEnabled(
anyString(), anyInt(), anyBoolean(), anyBoolean());
verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
- c.getPackageName(), 0, true, true);
+ c.getPackageName(), mContext.getUserId(), true, true);
verify(mAssistants, never()).setPackageOrComponentEnabled(
any(), anyInt(), anyBoolean(), anyBoolean());
}
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index 477592ba4129..26cea2ca7a6c 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -837,20 +837,31 @@ public class UsbDeviceManager implements ActivityTaskManagerInternal.ScreenObser
boolean prevHostConnected = mHostConnected;
UsbPort port = (UsbPort) args.arg1;
UsbPortStatus status = (UsbPortStatus) args.arg2;
- mHostConnected = status.getCurrentDataRole() == DATA_ROLE_HOST;
- mSourcePower = status.getCurrentPowerRole() == POWER_ROLE_SOURCE;
- mSinkPower = status.getCurrentPowerRole() == POWER_ROLE_SINK;
- mAudioAccessoryConnected = (status.getCurrentMode() == MODE_AUDIO_ACCESSORY);
+
+ if (status != null) {
+ mHostConnected = status.getCurrentDataRole() == DATA_ROLE_HOST;
+ mSourcePower = status.getCurrentPowerRole() == POWER_ROLE_SOURCE;
+ mSinkPower = status.getCurrentPowerRole() == POWER_ROLE_SINK;
+ mAudioAccessoryConnected = (status.getCurrentMode() == MODE_AUDIO_ACCESSORY);
+
+ // Ideally we want to see if PR_SWAP and DR_SWAP is supported.
+ // But, this should be suffice, since, all four combinations are only supported
+ // when PR_SWAP and DR_SWAP are supported.
+ mSupportsAllCombinations = status.isRoleCombinationSupported(
+ POWER_ROLE_SOURCE, DATA_ROLE_HOST)
+ && status.isRoleCombinationSupported(POWER_ROLE_SINK, DATA_ROLE_HOST)
+ && status.isRoleCombinationSupported(POWER_ROLE_SOURCE,
+ DATA_ROLE_DEVICE)
+ && status.isRoleCombinationSupported(POWER_ROLE_SINK, DATA_ROLE_DEVICE);
+ } else {
+ mHostConnected = false;
+ mSourcePower = false;
+ mSinkPower = false;
+ mAudioAccessoryConnected = false;
+ mSupportsAllCombinations = false;
+ }
+
mAudioAccessorySupported = port.isModeSupported(MODE_AUDIO_ACCESSORY);
- // Ideally we want to see if PR_SWAP and DR_SWAP is supported.
- // But, this should be suffice, since, all four combinations are only supported
- // when PR_SWAP and DR_SWAP are supported.
- mSupportsAllCombinations = status.isRoleCombinationSupported(
- POWER_ROLE_SOURCE, DATA_ROLE_HOST)
- && status.isRoleCombinationSupported(POWER_ROLE_SINK, DATA_ROLE_HOST)
- && status.isRoleCombinationSupported(POWER_ROLE_SOURCE,
- DATA_ROLE_DEVICE)
- && status.isRoleCombinationSupported(POWER_ROLE_SINK, DATA_ROLE_DEVICE);
args.recycle();
updateUsbNotification(false);
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index ae1984e67c9c..7c234fcc949e 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -17,7 +17,6 @@
package android.telephony;
import android.Manifest;
-import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
@@ -32,10 +31,11 @@ import android.os.PersistableBundle;
import android.os.RemoteException;
import android.service.carrier.CarrierService;
import android.telecom.TelecomManager;
+import android.telephony.gba.TlsParams;
+import android.telephony.gba.UaSecurityProtocolIdentifier;
import android.telephony.ims.ImsReasonInfo;
import android.telephony.ims.ImsRegistrationAttributes;
import android.telephony.ims.ImsSsData;
-import android.telephony.ims.SipDelegateManager;
import android.telephony.ims.feature.MmTelFeature;
import android.telephony.ims.feature.RcsFeature;
@@ -3616,6 +3616,71 @@ public class CarrierConfigManager {
public static final String ENABLE_EAP_METHOD_PREFIX_BOOL = "enable_eap_method_prefix_bool";
/**
+ * Indicates that GBA_ME should be used for GBA authentication, as defined in 3GPP TS 33.220.
+ * @hide
+ */
+ @SystemApi
+ public static final int GBA_ME = 1;
+
+ /**
+ * Indicates that GBA_U should be used for GBA authentication, as defined in 3GPP TS 33.220.
+ * @hide
+ */
+ @SystemApi
+ public static final int GBA_U = 2;
+
+ /**
+ * Indicates that GBA_Digest should be used for GBA authentication, as defined
+ * in 3GPP TS 33.220.
+ * @hide
+ */
+ @SystemApi
+ public static final int GBA_DIGEST = 3;
+
+ /**
+ * An integer representing the GBA mode to use for requesting credentials
+ * via {@link TelephonyManager#bootstrapAuthenticationRequest}.
+ *
+ * One of {@link #GBA_ME}, {@link #GBA_U}, or {@link #GBA_DIGEST}.
+ * @hide
+ */
+ @SystemApi
+ public static final String KEY_GBA_MODE_INT = "gba_mode_int";
+
+ /**
+ * An integer representing the organization code to be used when building the
+ * {@link UaSecurityProtocolIdentifier} used when requesting GBA authentication.
+ *
+ * See the {@code ORG_} constants in {@link UaSecurityProtocolIdentifier}.
+ * @hide
+ */
+ @SystemApi
+ public static final String KEY_GBA_UA_SECURITY_ORGANIZATION_INT =
+ "gba_ua_security_organization_int";
+
+ /**
+ * An integer representing the security protocol to be used when building the
+ * {@link UaSecurityProtocolIdentifier} used when requesting GBA authentication.
+ *
+ * See the {@code UA_SECURITY_PROTOCOL_} constants in {@link UaSecurityProtocolIdentifier}.
+ * @hide
+ */
+ @SystemApi
+ public static final String KEY_GBA_UA_SECURITY_PROTOCOL_INT =
+ "gba_ua_security_protocol_int";
+
+ /**
+ * An integer representing the cipher suite to be used when building the
+ * {@link UaSecurityProtocolIdentifier} used when requesting GBA authentication.
+ *
+ * See the {@code TLS_} constants in {@link android.telephony.gba.TlsParams}.
+ * @hide
+ */
+ @SystemApi
+ public static final String KEY_GBA_UA_TLS_CIPHER_SUITE_INT =
+ "gba_ua_tls_cipher_suite_int";
+
+ /**
* GPS configs. See the GNSS HAL documentation for more details.
*/
public static final class Gps {
@@ -4026,6 +4091,14 @@ public class CarrierConfigManager {
public static final String KEY_NON_RCS_CAPABILITIES_CACHE_EXPIRATION_SEC_INT =
KEY_PREFIX + "non_rcs_capabilities_cache_expiration_sec_int";
+ /**
+ * Specifies the RCS feature tag allowed for the carrier.
+ *
+ * <p>The values refer to RCC.07 2.4.4.
+ */
+ public static final String KEY_RCS_FEATURE_TAG_ALLOWED_STRING_ARRAY =
+ KEY_PREFIX + "rcs_feature_tag_allowed_string_array";
+
private Ims() {}
private static PersistableBundle getDefaults() {
@@ -4039,6 +4112,27 @@ public class CarrierConfigManager {
defaults.putBoolean(KEY_RCS_BULK_CAPABILITY_EXCHANGE_BOOL, false);
defaults.putBoolean(KEY_ENABLE_PRESENCE_GROUP_SUBSCRIBE_BOOL, true);
defaults.putInt(KEY_NON_RCS_CAPABILITIES_CACHE_EXPIRATION_SEC_INT, 30 * 24 * 60 * 60);
+ defaults.putStringArray(KEY_RCS_FEATURE_TAG_ALLOWED_STRING_ARRAY, new String[]{
+ "+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.largemsg\"",
+ "+g.3gpp.icsi-ref=\"urn%3Aurn-7%3A3gpp-service.ims.icsi.oma.cpm.deferred\"",
+ "+g.gsma.rcs.cpm.pager-large",
+ "+g.3gpp.icsi-ref=\"urn%3Aurn-7%3A3gpp-service.ims.icsi.oma.cpm.session\"",
+ "+g.3gpp.icsi-ref=\"urn%3Aurn-7%3A3gpp-service.ims.icsi.oma.cpm.session\"",
+ "+g.3gpp.iari-ref=\"urn%3Aurn-7%3A3gpp-application.ims.iari.rcs.fthttp\"",
+ "+g.3gpp.iari-ref=\"urn%3Aurn-7%3A3gpp-application.ims.iari.rcs.ftsms\"",
+ "+g.3gpp.iari-ref=\"urn%3Aurn-7%3A3gpp-service.ims.icsi.gsma.callcomposer\"",
+ "+g.gsma.callcomposer",
+ "+g.3gpp.icsi-ref=\"urn%3Aurn-7%3A3gpp-service.ims.icsi.gsma.callunanswered\"",
+ "+g.3gpp.icsi-ref=\"urn%3Aurn-7%3A3gpp-service.ims.icsi.gsma.sharedmap\"",
+ "+g.3gpp.icsi-ref=\"urn%3Aurn-7%3A3gpp-service.ims.icsi.gsma.sharedsketch\"",
+ "+g.3gpp.iari-ref=\"urn%3Aurn-7%3A3gpp-application.ims.iari.rcs.geopush\"",
+ "+g.3gpp.iari-ref=\"urn%3Aurn-7%3A3gpp-application.ims.iari.rcs.geosms\"",
+ "+g.3gpp.iari-ref=\"urn%3Aurn-7%3A3gpp-application.ims.iari.rcs.chatbot\"",
+ "+g.3gpp.iari-ref=\"urn%3Aurn-7%3A3gpp-application.ims.iari.rcs.chatbot.sa\"",
+ "+g.gsma.rcs.botversion=\"#=1,#=2\"",
+ "+g.gsma.rcs.cpimext"});
+
return defaults;
}
}
@@ -4794,6 +4888,13 @@ public class CarrierConfigManager {
// Default wifi configurations.
sDefaults.putAll(Wifi.getDefaults());
sDefaults.putBoolean(ENABLE_EAP_METHOD_PREFIX_BOOL, false);
+ sDefaults.putInt(KEY_GBA_MODE_INT, GBA_ME);
+ sDefaults.putInt(KEY_GBA_UA_SECURITY_ORGANIZATION_INT,
+ UaSecurityProtocolIdentifier.ORG_3GPP);
+ sDefaults.putInt(KEY_GBA_UA_SECURITY_PROTOCOL_INT,
+ UaSecurityProtocolIdentifier.UA_SECURITY_PROTOCOL_3GPP_TLS_DEFAULT);
+ sDefaults.putInt(KEY_GBA_UA_TLS_CIPHER_SUITE_INT, TlsParams.TLS_NULL_WITH_NULL_NULL);
+
sDefaults.putBoolean(KEY_SHOW_FORWARDED_NUMBER_BOOL, false);
sDefaults.putLong(KEY_DATA_SWITCH_VALIDATION_MIN_GAP_LONG, TimeUnit.DAYS.toMillis(1));
sDefaults.putStringArray(KEY_MISSED_INCOMING_CALL_SMS_ORIGINATOR_STRING_ARRAY,
diff --git a/telephony/java/android/telephony/PhysicalChannelConfig.java b/telephony/java/android/telephony/PhysicalChannelConfig.java
index dfe269cbb0d9..1c9cd94b245d 100644
--- a/telephony/java/android/telephony/PhysicalChannelConfig.java
+++ b/telephony/java/android/telephony/PhysicalChannelConfig.java
@@ -292,6 +292,14 @@ public final class PhysicalChannelConfig implements Parcelable {
}
/**
+ * Return a copy of this PhysicalChannelConfig object but redact all the location info.
+ * @hide
+ */
+ public PhysicalChannelConfig createLocationInfoSanitizedCopy() {
+ return new Builder(this).setPhysicalCellId(PHYSICAL_CELL_ID_UNKNOWN).build();
+ }
+
+ /**
* @return String representation of the connection status
* @hide
*/
@@ -540,6 +548,23 @@ public final class PhysicalChannelConfig implements Parcelable {
mBand = BAND_UNKNOWN;
}
+ /**
+ * Builder object constructed from existing PhysicalChannelConfig object.
+ * @hide
+ */
+ public Builder(PhysicalChannelConfig config) {
+ mNetworkType = config.getNetworkType();
+ mFrequencyRange = config.getFrequencyRange();
+ mDownlinkChannelNumber = config.getDownlinkChannelNumber();
+ mUplinkChannelNumber = config.getUplinkChannelNumber();
+ mCellBandwidthDownlinkKhz = config.getCellBandwidthDownlinkKhz();
+ mCellBandwidthUplinkKhz = config.getCellBandwidthUplinkKhz();
+ mCellConnectionStatus = config.getConnectionStatus();
+ mContextIds = Arrays.copyOf(config.getContextIds(), config.getContextIds().length);
+ mPhysicalCellId = config.getPhysicalCellId();
+ mBand = config.getBand();
+ }
+
public PhysicalChannelConfig build() {
return new PhysicalChannelConfig(this);
}
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index f110daecd952..2d06062cfa44 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -564,6 +564,7 @@ public class ServiceState implements Parcelable {
* @hide
*/
@UnsupportedAppUsage
+ @TestApi
public int getDataRegState() {
return mDataRegState;
}
diff --git a/telephony/java/android/telephony/SmsMessage.java b/telephony/java/android/telephony/SmsMessage.java
index cfb29f124b43..5a12865fb2a0 100644
--- a/telephony/java/android/telephony/SmsMessage.java
+++ b/telephony/java/android/telephony/SmsMessage.java
@@ -300,9 +300,12 @@ public class SmsMessage {
* @param data Message data.
* @param isCdma Indicates weather the type of the SMS is CDMA.
* @return An SmsMessage representing the message.
+ *
+ * @hide
*/
+ @SystemApi
@Nullable
- public static SmsMessage createSmsSubmitPdu(@NonNull byte[] data, boolean isCdma) {
+ public static SmsMessage createFromNativeSmsSubmitPdu(@NonNull byte[] data, boolean isCdma) {
SmsMessageBase wrappedMessage;
if (isCdma) {
@@ -318,23 +321,6 @@ public class SmsMessage {
}
/**
- * Create an SmsMessage from a native SMS-Submit PDU, specified by Bluetooth Message Access
- * Profile Specification v1.4.2 5.8.
- * This is used by Bluetooth MAP profile to decode message when sending non UTF-8 SMS messages.
- *
- * @param data Message data.
- * @param isCdma Indicates weather the type of the SMS is CDMA.
- * @return An SmsMessage representing the message.
- *
- * @hide
- */
- @SystemApi
- @Nullable
- public static SmsMessage createFromNativeSmsSubmitPdu(@NonNull byte[] data, boolean isCdma) {
- return null;
- }
-
- /**
* Get the TP-Layer-Length for the given SMS-SUBMIT PDU Basically, the
* length in bytes (not hex chars) less the SMSC header
*
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index bae032c7da6c..a2467f2067ac 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -99,6 +99,7 @@ import android.util.Pair;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.os.BackgroundThread;
import com.android.internal.telephony.CellNetworkScanResult;
import com.android.internal.telephony.IBooleanConsumer;
import com.android.internal.telephony.ICallForwardingInfoCallback;
@@ -128,6 +129,7 @@ import java.util.Map;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.Executor;
+import java.util.concurrent.RejectedExecutionException;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
@@ -417,6 +419,27 @@ public class TelephonyManager {
}
/**
+ * Post a runnable to the BackgroundThread.
+ *
+ * Used to invoke user callbacks without calling into the caller's executor from the caller's
+ * calling thread context, for example to provide asynchronous error information that is
+ * generated locally (not over a binder thread).
+ *
+ * <p>This is not necessary unless you are invoking caller's code asynchronously from within
+ * the caller's thread context.
+ *
+ * @param r a runnable.
+ */
+ private static void runOnBackgroundThread(@NonNull Runnable r) {
+ try {
+ BackgroundThread.getExecutor().execute(r);
+ } catch (RejectedExecutionException e) {
+ throw new IllegalStateException(
+ "Failed to post a callback from the caller's thread context.", e);
+ }
+ }
+
+ /**
* Returns the multi SIM variant
* Returns DSDS for Dual SIM Dual Standby
* Returns DSDA for Dual SIM Dual Active
@@ -5875,7 +5898,7 @@ public class TelephonyManager {
/**
* Error response to
- * {@link android.telephony.TelephonyManager#requestCellInfoUpdate requestCellInfoUpdate()}.
+ * {@link TelephonyManager#requestCellInfoUpdate requestCellInfoUpdate()}.
*
* Invoked when an error condition prevents updated {@link CellInfo} from being fetched
* and returned from the modem. Callers of requestCellInfoUpdate() should override this
@@ -5893,6 +5916,20 @@ public class TelephonyManager {
};
/**
+ * Used for checking if the target SDK version for the current process is S or above.
+ *
+ * <p> Applies to the following methods:
+ * {@link #requestCellInfoUpdate},
+ * {@link #setPreferredOpportunisticDataSubscription},
+ * {@link #updateAvailableNetworks},
+ * requestNumberVerification(),
+ * setSimPowerStateForSlot(),
+ */
+ @ChangeId
+ @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.R)
+ private static final long NULL_TELEPHONY_THROW_NO_CB = 182185642L;
+
+ /**
* Requests all available cell information from the current subscription for observed
* camped/registered, serving, and neighboring cells.
*
@@ -5912,7 +5949,14 @@ public class TelephonyManager {
@NonNull @CallbackExecutor Executor executor, @NonNull CellInfoCallback callback) {
try {
ITelephony telephony = getITelephony();
- if (telephony == null) return;
+ if (telephony == null) {
+ if (Compatibility.isChangeEnabled(NULL_TELEPHONY_THROW_NO_CB)) {
+ throw new IllegalStateException("Telephony is null");
+ } else {
+ return;
+ }
+ }
+
telephony.requestCellInfoUpdate(
getSubId(),
new ICellInfoCallback.Stub() {
@@ -5939,6 +5983,8 @@ public class TelephonyManager {
}
}, getOpPackageName(), getAttributionTag());
} catch (RemoteException ex) {
+ runOnBackgroundThread(() -> executor.execute(
+ () -> callback.onError(CellInfoCallback.ERROR_MODEM_ERROR, ex)));
}
}
@@ -5966,7 +6012,14 @@ public class TelephonyManager {
@NonNull @CallbackExecutor Executor executor, @NonNull CellInfoCallback callback) {
try {
ITelephony telephony = getITelephony();
- if (telephony == null) return;
+ if (telephony == null) {
+ if (Compatibility.isChangeEnabled(NULL_TELEPHONY_THROW_NO_CB)) {
+ throw new IllegalStateException("Telephony is null");
+ } else {
+ return;
+ }
+ }
+
telephony.requestCellInfoUpdateWithWorkSource(
getSubId(),
new ICellInfoCallback.Stub() {
@@ -5994,6 +6047,8 @@ public class TelephonyManager {
}
}, getOpPackageName(), getAttributionTag(), workSource);
} catch (RemoteException ex) {
+ runOnBackgroundThread(() -> executor.execute(
+ () -> callback.onError(CellInfoCallback.ERROR_MODEM_ERROR, ex)));
}
}
@@ -6960,14 +7015,21 @@ public class TelephonyManager {
try {
ITelephony telephony = getITelephony();
- if (telephony != null) {
- telephony.requestNumberVerification(range, timeoutMillis, internalCallback,
- getOpPackageName());
+ if (telephony == null) {
+ if (Compatibility.isChangeEnabled(NULL_TELEPHONY_THROW_NO_CB)) {
+ throw new IllegalStateException("Telephony is null");
+ } else {
+ return;
+ }
}
+
+ telephony.requestNumberVerification(range, timeoutMillis, internalCallback,
+ getOpPackageName());
} catch (RemoteException ex) {
Rlog.e(TAG, "requestNumberVerification RemoteException", ex);
- executor.execute(() ->
- callback.onVerificationFailed(NumberVerificationCallback.REASON_UNSPECIFIED));
+ runOnBackgroundThread(() -> executor.execute(
+ () -> callback.onVerificationFailed(
+ NumberVerificationCallback.REASON_UNSPECIFIED)));
}
}
@@ -10333,6 +10395,8 @@ public class TelephonyManager {
}
try {
ITelephony telephony = getITelephony();
+ if (telephony == null) throw new IllegalStateException("Telephony is null.");
+
IIntegerConsumer internalCallback = new IIntegerConsumer.Stub() {
@Override
public void accept(int result) {
@@ -10340,11 +10404,18 @@ public class TelephonyManager {
Binder.withCleanCallingIdentity(() -> callback.accept(result)));
}
};
- if (telephony != null) {
- telephony.setSimPowerStateForSlotWithCallback(slotIndex, state, internalCallback);
+ if (telephony == null) {
+ if (Compatibility.isChangeEnabled(NULL_TELEPHONY_THROW_NO_CB)) {
+ throw new IllegalStateException("Telephony is null");
+ } else {
+ return;
+ }
}
+ telephony.setSimPowerStateForSlotWithCallback(slotIndex, state, internalCallback);
} catch (RemoteException e) {
Log.e(TAG, "Error calling ITelephony#setSimPowerStateForSlot", e);
+ runOnBackgroundThread(() -> executor.execute(
+ () -> callback.accept(SET_SIM_POWER_STATE_MODEM_ERROR)));
} catch (SecurityException e) {
Log.e(TAG, "Permission error calling ITelephony#setSimPowerStateForSlot",
e);
@@ -12774,22 +12845,12 @@ public class TelephonyManager {
try {
IOns iOpportunisticNetworkService = getIOns();
if (iOpportunisticNetworkService == null) {
- if (executor == null || callback == null) {
- return;
- }
- final long identity = Binder.clearCallingIdentity();
- try {
- executor.execute(() -> {
- if (Compatibility.isChangeEnabled(CALLBACK_ON_MORE_ERROR_CODE_CHANGE)) {
- callback.accept(SET_OPPORTUNISTIC_SUB_REMOTE_SERVICE_EXCEPTION);
- } else {
- callback.accept(SET_OPPORTUNISTIC_SUB_INACTIVE_SUBSCRIPTION);
- }
- });
- } finally {
- Binder.restoreCallingIdentity(identity);
+ if (Compatibility.isChangeEnabled(NULL_TELEPHONY_THROW_NO_CB)) {
+ throw new IllegalStateException("Opportunistic Network Service is null");
+ } else {
+ // Let the general remote exception handling catch this.
+ throw new RemoteException("Null Opportunistic Network Service!");
}
- return;
}
ISetOpportunisticDataCallback callbackStub = new ISetOpportunisticDataCallback.Stub() {
@Override
@@ -12812,9 +12873,18 @@ public class TelephonyManager {
.setPreferredDataSubscriptionId(subId, needValidation, callbackStub,
pkgForDebug);
} catch (RemoteException ex) {
- Rlog.e(TAG, "setPreferredDataSubscriptionId RemoteException", ex);
+ Rlog.e(TAG, "setPreferredOpportunisticDataSubscription RemoteException", ex);
+ if (executor == null || callback == null) {
+ return;
+ }
+ runOnBackgroundThread(() -> executor.execute(() -> {
+ if (Compatibility.isChangeEnabled(CALLBACK_ON_MORE_ERROR_CODE_CHANGE)) {
+ callback.accept(SET_OPPORTUNISTIC_SUB_REMOTE_SERVICE_EXCEPTION);
+ } else {
+ callback.accept(SET_OPPORTUNISTIC_SUB_INACTIVE_SUBSCRIPTION);
+ }
+ }));
}
- return;
}
/**
@@ -12871,37 +12941,18 @@ public class TelephonyManager {
@Nullable @CallbackExecutor Executor executor,
@UpdateAvailableNetworksResult @Nullable Consumer<Integer> callback) {
String pkgForDebug = mContext != null ? mContext.getOpPackageName() : "<unknown>";
+ Objects.requireNonNull(availableNetworks, "availableNetworks must not be null.");
try {
IOns iOpportunisticNetworkService = getIOns();
- if (iOpportunisticNetworkService == null || availableNetworks == null) {
- if (executor == null || callback == null) {
- return;
- }
- if (iOpportunisticNetworkService == null) {
- final long identity = Binder.clearCallingIdentity();
- try {
- executor.execute(() -> {
- if (Compatibility.isChangeEnabled(CALLBACK_ON_MORE_ERROR_CODE_CHANGE)) {
- callback.accept(UPDATE_AVAILABLE_NETWORKS_REMOTE_SERVICE_EXCEPTION);
- } else {
- callback.accept(UPDATE_AVAILABLE_NETWORKS_UNKNOWN_FAILURE);
- }
- });
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
+ if (iOpportunisticNetworkService == null) {
+ if (Compatibility.isChangeEnabled(NULL_TELEPHONY_THROW_NO_CB)) {
+ throw new IllegalStateException("Opportunistic Network Service is null");
} else {
- final long identity = Binder.clearCallingIdentity();
- try {
- executor.execute(() -> {
- callback.accept(UPDATE_AVAILABLE_NETWORKS_INVALID_ARGUMENTS);
- });
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
+ // Let the general remote exception handling catch this.
+ throw new RemoteException("Null Opportunistic Network Service!");
}
- return;
}
+
IUpdateAvailableNetworksCallback callbackStub =
new IUpdateAvailableNetworksCallback.Stub() {
@Override
@@ -12909,20 +12960,25 @@ public class TelephonyManager {
if (executor == null || callback == null) {
return;
}
- final long identity = Binder.clearCallingIdentity();
- try {
- executor.execute(() -> {
- callback.accept(result);
- });
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
+ Binder.withCleanCallingIdentity(() -> {
+ executor.execute(() -> callback.accept(result));
+ });
}
};
- iOpportunisticNetworkService.updateAvailableNetworks(availableNetworks, callbackStub,
- pkgForDebug);
+ iOpportunisticNetworkService
+ .updateAvailableNetworks(availableNetworks, callbackStub, pkgForDebug);
} catch (RemoteException ex) {
Rlog.e(TAG, "updateAvailableNetworks RemoteException", ex);
+ if (executor == null || callback == null) {
+ return;
+ }
+ runOnBackgroundThread(() -> executor.execute(() -> {
+ if (Compatibility.isChangeEnabled(CALLBACK_ON_MORE_ERROR_CODE_CHANGE)) {
+ callback.accept(UPDATE_AVAILABLE_NETWORKS_REMOTE_SERVICE_EXCEPTION);
+ } else {
+ callback.accept(UPDATE_AVAILABLE_NETWORKS_UNKNOWN_FAILURE);
+ }
+ }));
}
}
@@ -14570,7 +14626,12 @@ public class TelephonyManager {
* DataThrottlingRequest#DATA_THROTTLING_ACTION_NO_DATA_THROTTLING} can still be requested in
* order to undo the mitigations above it (i.e {@link
* ThermalMitigationRequest#THERMAL_MITIGATION_ACTION_VOICE_ONLY} and/or {@link
- * ThermalMitigationRequest#THERMAL_MITIGATION_ACTION_RADIO_OFF}).
+ * ThermalMitigationRequest#THERMAL_MITIGATION_ACTION_RADIO_OFF}). </p>
+ *
+ * <p> In addition to the {@link Manifest.permission#MODIFY_PHONE_STATE} permission, callers of
+ * this API must also be listed in the device configuration as an authorized app in
+ * {@code packages/services/Telephony/res/values/config.xml} under the
+ * {@code thermal_mitigation_allowlisted_packages} key. </p>
*
* @param thermalMitigationRequest Thermal mitigation request. See {@link
* ThermalMitigationRequest} for details.
@@ -14589,7 +14650,8 @@ public class TelephonyManager {
try {
ITelephony telephony = getITelephony();
if (telephony != null) {
- return telephony.sendThermalMitigationRequest(getSubId(), thermalMitigationRequest);
+ return telephony.sendThermalMitigationRequest(getSubId(), thermalMitigationRequest,
+ getOpPackageName());
}
throw new IllegalStateException("telephony service is null.");
} catch (RemoteException ex) {
diff --git a/telephony/java/android/telephony/data/EpsBearerQosSessionAttributes.java b/telephony/java/android/telephony/data/EpsBearerQosSessionAttributes.java
index 406c38bf60ef..9bc7a5c6cf96 100644
--- a/telephony/java/android/telephony/data/EpsBearerQosSessionAttributes.java
+++ b/telephony/java/android/telephony/data/EpsBearerQosSessionAttributes.java
@@ -53,7 +53,7 @@ public final class EpsBearerQosSessionAttributes implements Parcelable, QosSessi
*
* @return the qci of the session
*/
- public int getQci() {
+ public int getQosIdentifier() {
return mQci;
}
@@ -66,7 +66,7 @@ public final class EpsBearerQosSessionAttributes implements Parcelable, QosSessi
*
* @return the guaranteed bit rate in kbps
*/
- public long getGuaranteedUplinkBitRate() {
+ public long getGuaranteedUplinkBitRateKbps() {
return mGuaranteedUplinkBitRate;
}
@@ -79,7 +79,7 @@ public final class EpsBearerQosSessionAttributes implements Parcelable, QosSessi
*
* @return the guaranteed bit rate in kbps
*/
- public long getGuaranteedDownlinkBitRate() {
+ public long getGuaranteedDownlinkBitRateKbps() {
return mGuaranteedDownlinkBitRate;
}
@@ -92,7 +92,7 @@ public final class EpsBearerQosSessionAttributes implements Parcelable, QosSessi
*
* @return the max uplink bit rate in kbps
*/
- public long getMaxUplinkBitRate() {
+ public long getMaxUplinkBitRateKbps() {
return mMaxUplinkBitRate;
}
@@ -105,7 +105,7 @@ public final class EpsBearerQosSessionAttributes implements Parcelable, QosSessi
*
* @return the max downlink bit rate in kbps
*/
- public long getMaxDownlinkBitRate() {
+ public long getMaxDownlinkBitRateKbps() {
return mMaxDownlinkBitRate;
}
diff --git a/telephony/java/android/telephony/data/NrQos.java b/telephony/java/android/telephony/data/NrQos.java
index 2011eed26977..fe124ac15393 100644
--- a/telephony/java/android/telephony/data/NrQos.java
+++ b/telephony/java/android/telephony/data/NrQos.java
@@ -50,6 +50,18 @@ public final class NrQos extends Qos implements Parcelable {
return new NrQos(in);
}
+ public int get5Qi() {
+ return fiveQi;
+ }
+
+ public int getQfi() {
+ return qosFlowId;
+ }
+
+ public int getAveragingWindow() {
+ return averagingWindowMs;
+ }
+
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
super.writeToParcel(Qos.QOS_TYPE_NR, dest, flags);
diff --git a/telephony/java/android/telephony/data/NrQosSessionAttributes.aidl b/telephony/java/android/telephony/data/NrQosSessionAttributes.aidl
new file mode 100644
index 000000000000..fd3bbb0865cb
--- /dev/null
+++ b/telephony/java/android/telephony/data/NrQosSessionAttributes.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.data;
+
+ parcelable NrQosSessionAttributes;
diff --git a/telephony/java/android/telephony/data/NrQosSessionAttributes.java b/telephony/java/android/telephony/data/NrQosSessionAttributes.java
new file mode 100644
index 000000000000..4c37687910a1
--- /dev/null
+++ b/telephony/java/android/telephony/data/NrQosSessionAttributes.java
@@ -0,0 +1,259 @@
+/*
+ * 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.data;
+
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.net.QosSessionAttributes;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.UnknownHostException;
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Provides Qos attributes of an NR bearer.
+ *
+ * {@hide}
+ */
+@SystemApi
+public final class NrQosSessionAttributes implements Parcelable, QosSessionAttributes {
+ private static final String TAG = NrQosSessionAttributes.class.getSimpleName();
+ private final int m5Qi;
+ private final @IntRange(from=1, to=63) int mQfi;
+ private final long mMaxUplinkBitRate;
+ private final long mMaxDownlinkBitRate;
+ private final long mGuaranteedUplinkBitRate;
+ private final long mGuaranteedDownlinkBitRate;
+ private final long mAveragingWindow;
+ @NonNull private final List<InetSocketAddress> mRemoteAddresses;
+
+ /**
+ * 5G QOS Identifier (5QI), see 3GPP TS 24.501 and 23.501.
+ * The allowed values are standard values(1-9, 65-68, 69-70, 75, 79-80, 82-85)
+ * defined in the spec and operator specific values in the range 128-254.
+ *
+ * @return the 5QI of the QOS flow
+ */
+ public int getQosIdentifier() {
+ return m5Qi;
+ }
+
+ /**
+ * QOS flow identifier of the QOS flow description in the
+ * range of 1 to 63. see 3GPP TS 24.501 and 23.501.
+ *
+ * @return the QOS flow identifier of the session
+ */
+ public @IntRange(from=1, to=63) int getQosFlowIdentifier() {
+ return mQfi;
+ }
+
+ /**
+ * Minimum bit rate in kbps that is guaranteed to be provided by the network on the uplink.
+ *
+ * see 3GPP TS 24.501 section 6.2.5
+ *
+ * Note: The Qos Session may be shared with OTHER applications besides yours.
+ *
+ * @return the guaranteed bit rate in kbps
+ */
+ public long getGuaranteedUplinkBitRateKbps() {
+ return mGuaranteedUplinkBitRate;
+ }
+
+ /**
+ * Minimum bit rate in kbps that is guaranteed to be provided by the network on the downlink.
+ *
+ * see 3GPP TS 24.501 section 6.2.5
+ *
+ * Note: The Qos Session may be shared with OTHER applications besides yours.
+ *
+ * @return the guaranteed bit rate in kbps
+ */
+ public long getGuaranteedDownlinkBitRateKbps() {
+ return mGuaranteedDownlinkBitRate;
+ }
+
+ /**
+ * The maximum uplink kbps that the network will accept.
+ *
+ * see 3GPP TS 24.501 section 6.2.5
+ *
+ * Note: The Qos Session may be shared with OTHER applications besides yours.
+ *
+ * @return the max uplink bit rate in kbps
+ */
+ public long getMaxUplinkBitRateKbps() {
+ return mMaxUplinkBitRate;
+ }
+
+ /**
+ * The maximum downlink kbps that the network can provide.
+ *
+ * see 3GPP TS 24.501 section 6.2.5
+ *
+ * Note: The Qos Session may be shared with OTHER applications besides yours.
+ *
+ * @return the max downlink bit rate in kbps
+ */
+ public long getMaxDownlinkBitRateKbps() {
+ return mMaxDownlinkBitRate;
+ }
+
+ /**
+ * The duration in milliseconds over which the maximum bit rates and guaranteed bit rates
+ * are calculated
+ *
+ * see 3GPP TS 24.501 section 6.2.5
+ *
+ * @return the averaging window duration in milliseconds
+ */
+ @NonNull
+ public Duration getBitRateWindowDuration() {
+ return Duration.ofMillis(mAveragingWindow);
+ }
+
+ /**
+ * List of remote addresses associated with the Qos Session. The given uplink bit rates apply
+ * to this given list of remote addresses.
+ *
+ * Note: In the event that the list is empty, it is assumed that the uplink bit rates apply to
+ * all remote addresses that are not contained in a different set of attributes.
+ *
+ * @return list of remote socket addresses that the attributes apply to
+ */
+ @NonNull
+ public List<InetSocketAddress> getRemoteAddresses() {
+ return mRemoteAddresses;
+ }
+
+ /**
+ * ..ctor for attributes
+ *
+ * @param fiveQi 5G quality class indicator
+ * @param qfi QOS flow identifier
+ * @param maxDownlinkBitRate the max downlink bit rate in kbps
+ * @param maxUplinkBitRate the max uplink bit rate in kbps
+ * @param guaranteedDownlinkBitRate the guaranteed downlink bit rate in kbps
+ * @param guaranteedUplinkBitRate the guaranteed uplink bit rate in kbps
+ * @param averagingWindow the averaging window duration in milliseconds
+ * @param remoteAddresses the remote addresses that the uplink bit rates apply to
+ *
+ * @hide
+ */
+ public NrQosSessionAttributes(final int fiveQi, final int qfi,
+ final long maxDownlinkBitRate, final long maxUplinkBitRate,
+ final long guaranteedDownlinkBitRate, final long guaranteedUplinkBitRate,
+ final long averagingWindow, @NonNull final List<InetSocketAddress> remoteAddresses) {
+ Objects.requireNonNull(remoteAddresses, "remoteAddress must be non-null");
+ m5Qi = fiveQi;
+ mQfi = qfi;
+ mMaxDownlinkBitRate = maxDownlinkBitRate;
+ mMaxUplinkBitRate = maxUplinkBitRate;
+ mGuaranteedDownlinkBitRate = guaranteedDownlinkBitRate;
+ mGuaranteedUplinkBitRate = guaranteedUplinkBitRate;
+ mAveragingWindow = averagingWindow;
+
+ final List<InetSocketAddress> remoteAddressesTemp = copySocketAddresses(remoteAddresses);
+ mRemoteAddresses = Collections.unmodifiableList(remoteAddressesTemp);
+ }
+
+ private static List<InetSocketAddress> copySocketAddresses(
+ @NonNull final List<InetSocketAddress> remoteAddresses) {
+ final List<InetSocketAddress> remoteAddressesTemp = new ArrayList<>();
+ for (final InetSocketAddress socketAddress : remoteAddresses) {
+ if (socketAddress != null && socketAddress.getAddress() != null) {
+ remoteAddressesTemp.add(socketAddress);
+ }
+ }
+ return remoteAddressesTemp;
+ }
+
+ private NrQosSessionAttributes(@NonNull final Parcel in) {
+ m5Qi = in.readInt();
+ mQfi = in.readInt();
+ mMaxDownlinkBitRate = in.readLong();
+ mMaxUplinkBitRate = in.readLong();
+ mGuaranteedDownlinkBitRate = in.readLong();
+ mGuaranteedUplinkBitRate = in.readLong();
+ mAveragingWindow = in.readLong();
+
+ final int size = in.readInt();
+ final List<InetSocketAddress> remoteAddresses = new ArrayList<>(size);
+ for (int i = 0; i < size; i++) {
+ final byte[] addressBytes = in.createByteArray();
+ final int port = in.readInt();
+ try {
+ remoteAddresses.add(
+ new InetSocketAddress(InetAddress.getByAddress(addressBytes), port));
+ } catch (final UnknownHostException e) {
+ // Impossible case since its filtered out the null values in the ..ctor
+ Log.e(TAG, "unable to unparcel remote address at index: " + i, e);
+ }
+ }
+ mRemoteAddresses = Collections.unmodifiableList(remoteAddresses);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull final Parcel dest, final int flags) {
+ dest.writeInt(m5Qi);
+ dest.writeInt(mQfi);
+ dest.writeLong(mMaxDownlinkBitRate);
+ dest.writeLong(mMaxUplinkBitRate);
+ dest.writeLong(mGuaranteedDownlinkBitRate);
+ dest.writeLong(mGuaranteedUplinkBitRate);
+ dest.writeLong(mAveragingWindow);
+
+ final int size = mRemoteAddresses.size();
+ dest.writeInt(size);
+ for (int i = 0; i < size; i++) {
+ final InetSocketAddress address = mRemoteAddresses.get(i);
+ dest.writeByteArray(address.getAddress().getAddress());
+ dest.writeInt(address.getPort());
+ }
+ }
+
+ @NonNull
+ public static final Creator<NrQosSessionAttributes> CREATOR =
+ new Creator<NrQosSessionAttributes>() {
+ @NonNull
+ @Override
+ public NrQosSessionAttributes createFromParcel(@NonNull final Parcel in) {
+ return new NrQosSessionAttributes(in);
+ }
+
+ @NonNull
+ @Override
+ public NrQosSessionAttributes[] newArray(final int size) {
+ return new NrQosSessionAttributes[size];
+ }
+ };
+}
diff --git a/telephony/java/android/telephony/ims/RcsContactUceCapability.java b/telephony/java/android/telephony/ims/RcsContactUceCapability.java
index 52d0f036788c..a133eadb3517 100644
--- a/telephony/java/android/telephony/ims/RcsContactUceCapability.java
+++ b/telephony/java/android/telephony/ims/RcsContactUceCapability.java
@@ -29,7 +29,9 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.HashSet;
import java.util.List;
+import java.util.Set;
/**
* Contains the User Capability Exchange capabilities corresponding to a contact's URI.
@@ -110,7 +112,6 @@ public final class RcsContactUceCapability implements Parcelable {
/**
* Builder to help construct {@link RcsContactUceCapability} instances when capabilities were
* queried through SIP OPTIONS.
- * @hide
*/
public static final class OptionsBuilder {
@@ -151,7 +152,7 @@ public final class RcsContactUceCapability implements Parcelable {
* @param tags the list of the supported feature tags
* @return this OptionBuilder
*/
- public @NonNull OptionsBuilder addFeatureTags(@NonNull List<String> tags) {
+ public @NonNull OptionsBuilder addFeatureTags(@NonNull Set<String> tags) {
mCapabilities.mFeatureTags.addAll(tags);
return this;
}
@@ -220,7 +221,7 @@ public final class RcsContactUceCapability implements Parcelable {
private @CapabilityMechanism int mCapabilityMechanism;
private @RequestResult int mRequestResult;
- private final List<String> mFeatureTags = new ArrayList<>();
+ private final Set<String> mFeatureTags = new HashSet<>();
private final List<RcsContactPresenceTuple> mPresenceTuples = new ArrayList<>();
private RcsContactUceCapability(@NonNull Uri contactUri, @CapabilityMechanism int mechanism,
@@ -235,7 +236,9 @@ public final class RcsContactUceCapability implements Parcelable {
mCapabilityMechanism = in.readInt();
mSourceType = in.readInt();
mRequestResult = in.readInt();
- in.readStringList(mFeatureTags);
+ List<String> featureTagList = new ArrayList<>();
+ in.readStringList(featureTagList);
+ mFeatureTags.addAll(featureTagList);
in.readParcelableList(mPresenceTuples, RcsContactPresenceTuple.class.getClassLoader());
}
@@ -245,7 +248,7 @@ public final class RcsContactUceCapability implements Parcelable {
out.writeInt(mCapabilityMechanism);
out.writeInt(mSourceType);
out.writeInt(mRequestResult);
- out.writeStringList(mFeatureTags);
+ out.writeStringList(new ArrayList<>(mFeatureTags));
out.writeParcelableList(mPresenceTuples, flags);
}
@@ -285,7 +288,20 @@ public final class RcsContactUceCapability implements Parcelable {
if (mCapabilityMechanism != CAPABILITY_MECHANISM_OPTIONS) {
return Collections.emptyList();
}
- return Collections.unmodifiableList(mFeatureTags);
+ return Collections.unmodifiableList(new ArrayList<>(mFeatureTags));
+ }
+
+ /**
+ * @return The feature tags present in the OPTIONS response from the network.
+ * <p>
+ * Note: this is only populated if {@link #getCapabilityMechanism} is
+ * {@link RcsContactUceCapability#CAPABILITY_MECHANISM_OPTIONS}
+ */
+ public @NonNull Set<String> getFeatureTags() {
+ if (mCapabilityMechanism != CAPABILITY_MECHANISM_OPTIONS) {
+ return Collections.emptySet();
+ }
+ return Collections.unmodifiableSet(mFeatureTags);
}
/**
diff --git a/telephony/java/android/telephony/ims/aidl/CapabilityExchangeAidlWrapper.java b/telephony/java/android/telephony/ims/aidl/CapabilityExchangeAidlWrapper.java
index a217d1321342..c3d7325f2e0a 100644
--- a/telephony/java/android/telephony/ims/aidl/CapabilityExchangeAidlWrapper.java
+++ b/telephony/java/android/telephony/ims/aidl/CapabilityExchangeAidlWrapper.java
@@ -26,7 +26,8 @@ import android.telephony.ims.RcsContactUceCapability;
import android.telephony.ims.stub.CapabilityExchangeEventListener;
import android.util.Log;
-import java.util.List;
+import java.util.ArrayList;
+import java.util.Set;
/**
* The ICapabilityExchangeEventListener wrapper class to store the listener which is registered by
@@ -84,7 +85,7 @@ public class CapabilityExchangeAidlWrapper implements CapabilityExchangeEventLis
* request to the framework.
*/
public void onRemoteCapabilityRequest(@NonNull Uri contactUri,
- @NonNull List<String> remoteCapabilities, @NonNull OptionsRequestCallback callback)
+ @NonNull Set<String> remoteCapabilities, @NonNull OptionsRequestCallback callback)
throws ImsException {
ICapabilityExchangeEventListener listener = mListenerBinder;
if (listener == null) {
@@ -114,7 +115,8 @@ public class CapabilityExchangeAidlWrapper implements CapabilityExchangeEventLis
};
try {
- listener.onRemoteCapabilityRequest(contactUri, remoteCapabilities, internalCallback);
+ listener.onRemoteCapabilityRequest(contactUri, new ArrayList<>(remoteCapabilities),
+ internalCallback);
} catch (RemoteException e) {
Log.w(LOG_TAG, "Remote capability request exception: " + e);
throw new ImsException("Remote is not available",
diff --git a/telephony/java/android/telephony/ims/feature/RcsFeature.java b/telephony/java/android/telephony/ims/feature/RcsFeature.java
index 85703f8de5e5..b384e50d9f03 100644
--- a/telephony/java/android/telephony/ims/feature/RcsFeature.java
+++ b/telephony/java/android/telephony/ims/feature/RcsFeature.java
@@ -47,6 +47,7 @@ import com.android.internal.telephony.util.TelephonyUtils;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.HashSet;
import java.util.List;
import java.util.concurrent.CancellationException;
import java.util.concurrent.CompletableFuture;
@@ -145,8 +146,8 @@ public class RcsFeature extends ImsFeature {
throws RemoteException {
OptionsResponseCallback callbackWrapper = new RcsOptionsResponseAidlWrapper(callback);
executeMethodAsync(() -> mReference.getCapabilityExchangeImplBaseInternal()
- .sendOptionsCapabilityRequest(contactUri, myCapabilities, callbackWrapper),
- "sendOptionsCapabilityRequest");
+ .sendOptionsCapabilityRequest(contactUri, new HashSet<>(myCapabilities),
+ callbackWrapper), "sendOptionsCapabilityRequest");
}
// Call the methods with a clean calling identity on the executor and wait indefinitely for
@@ -390,6 +391,7 @@ public class RcsFeature extends ImsFeature {
* event to the framework.
* @return An instance of {@link RcsCapabilityExchangeImplBase} that implements capability
* exchange if it is supported by the device.
+ * @hide
*/
public @NonNull RcsCapabilityExchangeImplBase createCapabilityExchangeImpl(
@NonNull Executor executor, @NonNull CapabilityExchangeEventListener listener) {
@@ -398,14 +400,45 @@ public class RcsFeature extends ImsFeature {
}
/**
+ * Retrieve the implementation of UCE for this {@link RcsFeature}, which can use either
+ * presence or OPTIONS for capability exchange.
+ *
+ * Will only be requested by the framework if capability exchange is configured
+ * as capable during a
+ * {@link #changeEnabledCapabilities(CapabilityChangeRequest, CapabilityCallbackProxy)}
+ * operation and the RcsFeature sets the status of the capability to true using
+ * {@link #notifyCapabilitiesStatusChanged(RcsImsCapabilities)}.
+ *
+ * @param listener A {@link CapabilityExchangeEventListener} to send the capability exchange
+ * event to the framework.
+ * @return An instance of {@link RcsCapabilityExchangeImplBase} that implements capability
+ * exchange if it is supported by the device.
+ */
+ public @NonNull RcsCapabilityExchangeImplBase createCapabilityExchangeImpl(
+ @NonNull CapabilityExchangeEventListener listener) {
+ // Base Implementation, override to implement functionality
+ return new RcsCapabilityExchangeImplBase();
+ }
+
+ /**
* Remove the given CapabilityExchangeImplBase instance.
* @param capExchangeImpl The {@link RcsCapabilityExchangeImplBase} instance to be removed.
+ * @hide
*/
public void removeCapabilityExchangeImpl(
@NonNull RcsCapabilityExchangeImplBase capExchangeImpl) {
// Override to implement the process of removing RcsCapabilityExchangeImplBase instance.
}
+ /**
+ * Remove the given CapabilityExchangeImplBase instance.
+ * @param capExchangeImpl The {@link RcsCapabilityExchangeImplBase} instance to be destroyed.
+ */
+ public void destroyCapabilityExchangeImpl(
+ @NonNull RcsCapabilityExchangeImplBase capExchangeImpl) {
+ // Override to implement the process of destroying RcsCapabilityExchangeImplBase instance.
+ }
+
/**{@inheritDoc}*/
@Override
public void onFeatureRemoved() {
diff --git a/telephony/java/android/telephony/ims/stub/CapabilityExchangeEventListener.java b/telephony/java/android/telephony/ims/stub/CapabilityExchangeEventListener.java
index 62955487897f..a3be8dab2891 100644
--- a/telephony/java/android/telephony/ims/stub/CapabilityExchangeEventListener.java
+++ b/telephony/java/android/telephony/ims/stub/CapabilityExchangeEventListener.java
@@ -26,7 +26,7 @@ import android.telephony.ims.RcsUceAdapter;
import android.telephony.ims.feature.ImsFeature;
import android.telephony.ims.feature.RcsFeature;
-import java.util.List;
+import java.util.Set;
/**
* The interface that is used by the framework to listen to events from the vendor RCS stack
@@ -98,7 +98,8 @@ public interface CapabilityExchangeEventListener {
* {@link OptionsRequestCallback#onRespondToCapabilityRequestWithError}.
* @param contactUri The URI associated with the remote contact that is
* requesting capabilities.
- * @param remoteCapabilities The remote contact's capability information.
+ * @param remoteCapabilities The remote contact's capability information. The capability
+ * information is in the format defined in RCC.07 section 2.6.1.3.
* @param callback The callback of this request which is sent from the remote user.
* @throws ImsException If this {@link RcsCapabilityExchangeImplBase} instance is not
* currently connected to the framework. This can happen if the {@link RcsFeature} is not
@@ -107,6 +108,6 @@ public interface CapabilityExchangeEventListener {
* cases when the Telephony stack has crashed.
*/
void onRemoteCapabilityRequest(@NonNull Uri contactUri,
- @NonNull List<String> remoteCapabilities,
+ @NonNull Set<String> remoteCapabilities,
@NonNull OptionsRequestCallback callback) throws ImsException;
}
diff --git a/telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java b/telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java
index 03e17fbc2c0d..a117adcfb99a 100644
--- a/telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java
@@ -33,6 +33,7 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Collection;
import java.util.List;
+import java.util.Set;
import java.util.concurrent.Executor;
/**
@@ -355,12 +356,13 @@ public class RcsCapabilityExchangeImplBase {
void onTerminated(@NonNull String reason, long retryAfterMilliseconds) throws ImsException;
}
- private final Executor mBinderExecutor;
+ private Executor mBinderExecutor;
/**
* Create a new RcsCapabilityExchangeImplBase instance.
*
* @param executor The executor that remote calls from the framework will be called on.
+ * @hide
*/
public RcsCapabilityExchangeImplBase(@NonNull Executor executor) {
if (executor == null) {
@@ -370,6 +372,12 @@ public class RcsCapabilityExchangeImplBase {
}
/**
+ * Create a new RcsCapabilityExchangeImplBase instance.
+ */
+ public RcsCapabilityExchangeImplBase() {
+ }
+
+ /**
* The user capabilities of one or multiple contacts have been requested by the framework.
* <p>
* The implementer must follow up this call with an
@@ -433,6 +441,7 @@ public class RcsCapabilityExchangeImplBase {
* @param contactUri The URI of the remote user that we wish to get the capabilities of.
* @param myCapabilities The capabilities of this device to send to the remote user.
* @param callback The callback of this request which is sent from the remote user.
+ * @hide
*/
// executor used is defined in the constructor.
@SuppressLint("ExecutorRegistration")
@@ -446,4 +455,27 @@ public class RcsCapabilityExchangeImplBase {
// Do not do anything, this is a stub implementation.
}
}
+
+ /**
+ * Push one's own capabilities to a remote user via the SIP OPTIONS presence exchange mechanism
+ * in order to receive the capabilities of the remote user in response.
+ * <p>
+ * The implementer must use {@link OptionsResponseCallback} to send the response of
+ * this query from the network back to the framework.
+ * @param contactUri The URI of the remote user that we wish to get the capabilities of.
+ * @param myCapabilities The capabilities of this device to send to the remote user.
+ * @param callback The callback of this request which is sent from the remote user.
+ */
+ // executor used is defined in the constructor.
+ @SuppressLint("ExecutorRegistration")
+ public void sendOptionsCapabilityRequest(@NonNull Uri contactUri,
+ @NonNull Set<String> myCapabilities, @NonNull OptionsResponseCallback callback) {
+ // Stub - to be implemented by service
+ Log.w(LOG_TAG, "sendOptionsCapabilityRequest called with no implementation.");
+ try {
+ callback.onCommandError(COMMAND_CODE_NOT_SUPPORTED);
+ } catch (ImsException e) {
+ // Do not do anything, this is a stub implementation.
+ }
+ }
}
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 45702c311ff3..97078c3dd76e 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -2231,10 +2231,12 @@ interface ITelephony {
*
* @param subId the id of the subscription
* @param thermalMitigationRequest holds the parameters necessary for the request.
+ * @param callingPackage the package name of the calling package.
* @throws InvalidThermalMitigationRequestException if the parametes are invalid.
*/
int sendThermalMitigationRequest(int subId,
- in ThermalMitigationRequest thermalMitigationRequest);
+ in ThermalMitigationRequest thermalMitigationRequest,
+ String callingPackage);
/**
* Get the Generic Bootstrapping Architecture authentication keys
@@ -2325,6 +2327,16 @@ interface ITelephony {
boolean getCarrierSingleRegistrationEnabled(int subId);
/**
+ * Overrides the ims feature validation result
+ */
+ boolean setImsFeatureValidationOverride(int subId, String enabled);
+
+ /**
+ * Gets the ims feature validation override value
+ */
+ boolean getImsFeatureValidationOverride(int subId);
+
+ /**
* Return the mobile provisioning url that is used to launch a browser to allow users to manage
* their mobile plan.
*/
diff --git a/tests/net/common/java/android/net/NetworkAgentConfigTest.kt b/tests/net/common/java/android/net/NetworkAgentConfigTest.kt
index a4d8353d1253..1e54093bf111 100644
--- a/tests/net/common/java/android/net/NetworkAgentConfigTest.kt
+++ b/tests/net/common/java/android/net/NetworkAgentConfigTest.kt
@@ -19,6 +19,7 @@ package android.net
import android.os.Build
import androidx.test.filters.SmallTest
import androidx.test.runner.AndroidJUnit4
+import com.android.modules.utils.build.SdkLevel.isAtLeastS
import com.android.testutils.DevSdkIgnoreRule
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
import com.android.testutils.assertParcelSane
@@ -44,7 +45,13 @@ class NetworkAgentConfigTest {
setPartialConnectivityAcceptable(false)
setUnvalidatedConnectivityAcceptable(true)
}.build()
- assertParcelSane(config, 10)
+ if (isAtLeastS()) {
+ // From S, the config will have 12 items
+ assertParcelSane(config, 12)
+ } else {
+ // For R or below, the config will have 10 items
+ assertParcelSane(config, 10)
+ }
}
@Test @IgnoreUpTo(Build.VERSION_CODES.Q)
diff --git a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
index d40b88ca599f..1f50e31cf243 100644
--- a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
+++ b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
@@ -329,7 +329,8 @@ public class NetworkCapabilitiesTest {
if (isAtLeastS()) {
netCap.setSubIds(Set.of(TEST_SUBID1, TEST_SUBID2));
netCap.setUids(uids);
- } else if (isAtLeastR()) {
+ }
+ if (isAtLeastR()) {
netCap.setOwnerUid(123);
netCap.setAdministratorUids(new int[] {5, 11});
}
@@ -531,11 +532,22 @@ public class NetworkCapabilitiesTest {
assertFalse(nc1.equalsNetCapabilities(nc2));
nc2.addUnwantedCapability(NET_CAPABILITY_INTERNET);
assertTrue(nc1.equalsNetCapabilities(nc2));
-
- nc1.removeCapability(NET_CAPABILITY_INTERNET);
- assertFalse(nc1.equalsNetCapabilities(nc2));
- nc2.removeCapability(NET_CAPABILITY_INTERNET);
- assertTrue(nc1.equalsNetCapabilities(nc2));
+ if (isAtLeastS()) {
+ // Remove a required capability doesn't affect unwanted capabilities.
+ // This is a behaviour change from S.
+ nc1.removeCapability(NET_CAPABILITY_INTERNET);
+ assertTrue(nc1.equalsNetCapabilities(nc2));
+
+ nc1.removeUnwantedCapability(NET_CAPABILITY_INTERNET);
+ assertFalse(nc1.equalsNetCapabilities(nc2));
+ nc2.removeUnwantedCapability(NET_CAPABILITY_INTERNET);
+ assertTrue(nc1.equalsNetCapabilities(nc2));
+ } else {
+ nc1.removeCapability(NET_CAPABILITY_INTERNET);
+ assertFalse(nc1.equalsNetCapabilities(nc2));
+ nc2.removeCapability(NET_CAPABILITY_INTERNET);
+ assertTrue(nc1.equalsNetCapabilities(nc2));
+ }
}
@Test
@@ -596,11 +608,21 @@ public class NetworkCapabilitiesTest {
// This will effectively move NOT_ROAMING capability from required to unwanted for nc1.
nc1.addUnwantedCapability(NET_CAPABILITY_NOT_ROAMING);
- nc2.combineCapabilities(nc1);
- // We will get this capability in both requested and unwanted lists thus this request
- // will never be satisfied.
- assertTrue(nc2.hasCapability(NET_CAPABILITY_NOT_ROAMING));
- assertTrue(nc2.hasUnwantedCapability(NET_CAPABILITY_NOT_ROAMING));
+ if (isAtLeastS()) {
+ // From S, it is not allowed to have the same capability in both wanted and
+ // unwanted list.
+ assertThrows(IllegalArgumentException.class, () -> nc2.combineCapabilities(nc1));
+ // Remove unwanted capability to continue other tests.
+ nc1.removeUnwantedCapability(NET_CAPABILITY_NOT_ROAMING);
+ } else {
+ nc2.combineCapabilities(nc1);
+ // We will get this capability in both requested and unwanted lists thus this request
+ // will never be satisfied.
+ assertTrue(nc2.hasCapability(NET_CAPABILITY_NOT_ROAMING));
+ assertTrue(nc2.hasUnwantedCapability(NET_CAPABILITY_NOT_ROAMING));
+ // For R or below, remove unwanted capability via removeCapability.
+ nc1.removeCapability(NET_CAPABILITY_NOT_ROAMING);
+ }
nc1.setSSID(TEST_SSID);
nc2.combineCapabilities(nc1);
diff --git a/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt b/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt
index db49e0b0047e..b6e42743e2a3 100644
--- a/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt
+++ b/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt
@@ -73,7 +73,7 @@ import kotlin.test.assertTrue
import kotlin.test.fail
const val SERVICE_BIND_TIMEOUT_MS = 5_000L
-const val TEST_TIMEOUT_MS = 1_000L
+const val TEST_TIMEOUT_MS = 10_000L
/**
* Test that exercises an instrumented version of ConnectivityService against an instrumented
diff --git a/tests/net/java/android/net/ConnectivityManagerTest.java b/tests/net/java/android/net/ConnectivityManagerTest.java
index 6fc605e269fe..6cbdd258c00a 100644
--- a/tests/net/java/android/net/ConnectivityManagerTest.java
+++ b/tests/net/java/android/net/ConnectivityManagerTest.java
@@ -41,10 +41,10 @@ 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.anyBoolean;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.anyBoolean;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -64,6 +64,7 @@ import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.Messenger;
+import android.os.Process;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -219,8 +220,8 @@ public class ConnectivityManagerTest {
ArgumentCaptor<Messenger> captor = ArgumentCaptor.forClass(Messenger.class);
// register callback
- when(mService.requestNetwork(any(), anyInt(), captor.capture(), anyInt(), any(), anyInt(),
- anyInt(), any(), nullable(String.class))).thenReturn(request);
+ when(mService.requestNetwork(anyInt(), any(), anyInt(), captor.capture(), anyInt(), any(),
+ anyInt(), anyInt(), any(), nullable(String.class))).thenReturn(request);
manager.requestNetwork(request, callback, handler);
// callback triggers
@@ -247,8 +248,8 @@ public class ConnectivityManagerTest {
ArgumentCaptor<Messenger> captor = ArgumentCaptor.forClass(Messenger.class);
// register callback
- when(mService.requestNetwork(any(), anyInt(), captor.capture(), anyInt(), any(), anyInt(),
- anyInt(), any(), nullable(String.class))).thenReturn(req1);
+ when(mService.requestNetwork(anyInt(), any(), anyInt(), captor.capture(), anyInt(), any(),
+ anyInt(), anyInt(), any(), nullable(String.class))).thenReturn(req1);
manager.requestNetwork(req1, callback, handler);
// callback triggers
@@ -265,8 +266,8 @@ public class ConnectivityManagerTest {
verify(callback, timeout(100).times(0)).onLosing(any(), anyInt());
// callback can be registered again
- when(mService.requestNetwork(any(), anyInt(), captor.capture(), anyInt(), any(), anyInt(),
- anyInt(), any(), nullable(String.class))).thenReturn(req2);
+ when(mService.requestNetwork(anyInt(), any(), anyInt(), captor.capture(), anyInt(), any(),
+ anyInt(), anyInt(), any(), nullable(String.class))).thenReturn(req2);
manager.requestNetwork(req2, callback, handler);
// callback triggers
@@ -289,8 +290,8 @@ public class ConnectivityManagerTest {
info.targetSdkVersion = VERSION_CODES.N_MR1 + 1;
when(mCtx.getApplicationInfo()).thenReturn(info);
- when(mService.requestNetwork(any(), anyInt(), any(), anyInt(), any(), anyInt(), anyInt(),
- any(), nullable(String.class))).thenReturn(request);
+ when(mService.requestNetwork(anyInt(), any(), anyInt(), any(), anyInt(), any(), anyInt(),
+ anyInt(), any(), nullable(String.class))).thenReturn(request);
Handler handler = new Handler(Looper.getMainLooper());
manager.requestNetwork(request, callback, handler);
@@ -357,34 +358,40 @@ public class ConnectivityManagerTest {
final NetworkCallback callback = new ConnectivityManager.NetworkCallback();
manager.requestNetwork(request, callback);
- verify(mService).requestNetwork(eq(request.networkCapabilities),
+ verify(mService).requestNetwork(eq(Process.INVALID_UID), eq(request.networkCapabilities),
eq(REQUEST.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE), anyInt(),
eq(testPkgName), eq(testAttributionTag));
reset(mService);
// Verify that register network callback does not calls requestNetwork at all.
manager.registerNetworkCallback(request, callback);
- verify(mService, never()).requestNetwork(any(), anyInt(), any(), anyInt(), any(), anyInt(),
- anyInt(), any(), any());
+ verify(mService, never()).requestNetwork(anyInt(), any(), anyInt(), any(), anyInt(), any(),
+ anyInt(), anyInt(), any(), any());
verify(mService).listenForNetwork(eq(request.networkCapabilities), any(), any(), anyInt(),
eq(testPkgName), eq(testAttributionTag));
reset(mService);
+ Handler handler = new Handler(ConnectivityThread.getInstanceLooper());
+
manager.registerDefaultNetworkCallback(callback);
- verify(mService).requestNetwork(eq(null),
+ verify(mService).requestNetwork(eq(Process.INVALID_UID), eq(null),
eq(TRACK_DEFAULT.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE), anyInt(),
eq(testPkgName), eq(testAttributionTag));
reset(mService);
- Handler handler = new Handler(ConnectivityThread.getInstanceLooper());
+ manager.registerDefaultNetworkCallbackAsUid(42, callback, handler);
+ verify(mService).requestNetwork(eq(42), eq(null),
+ eq(TRACK_DEFAULT.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE), anyInt(),
+ eq(testPkgName), eq(testAttributionTag));
+
manager.requestBackgroundNetwork(request, handler, callback);
- verify(mService).requestNetwork(eq(request.networkCapabilities),
+ verify(mService).requestNetwork(eq(Process.INVALID_UID), eq(request.networkCapabilities),
eq(BACKGROUND_REQUEST.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE), anyInt(),
eq(testPkgName), eq(testAttributionTag));
reset(mService);
manager.registerSystemDefaultNetworkCallback(callback, handler);
- verify(mService).requestNetwork(eq(null),
+ verify(mService).requestNetwork(eq(Process.INVALID_UID), eq(null),
eq(TRACK_SYSTEM_DEFAULT.ordinal()), any(), anyInt(), any(), eq(TYPE_NONE), anyInt(),
eq(testPkgName), eq(testAttributionTag));
reset(mService);
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index ed9a44b614d5..14c72f1445a9 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -18,6 +18,7 @@ package com.android.server;
import static android.Manifest.permission.CHANGE_NETWORK_STATE;
import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS;
+import static android.Manifest.permission.NETWORK_SETTINGS;
import static android.app.PendingIntent.FLAG_IMMUTABLE;
import static android.content.Intent.ACTION_USER_ADDED;
import static android.content.Intent.ACTION_USER_REMOVED;
@@ -30,10 +31,14 @@ import static android.content.pm.PackageManager.MATCH_ANY_USER;
import static android.content.pm.PackageManager.PERMISSION_DENIED;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.net.ConnectivityManager.ACTION_CAPTIVE_PORTAL_SIGN_IN;
+import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_DATA_SAVER;
+import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_MASK;
+import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_USER_RESTRICTED;
+import static android.net.ConnectivityManager.BLOCKED_REASON_BATTERY_SAVER;
+import static android.net.ConnectivityManager.BLOCKED_REASON_NONE;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
import static android.net.ConnectivityManager.EXTRA_NETWORK_INFO;
import static android.net.ConnectivityManager.EXTRA_NETWORK_TYPE;
-import static android.net.ConnectivityManager.NETID_UNSET;
import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OFF;
import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC;
import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME;
@@ -91,10 +96,6 @@ import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET;
import static android.net.NetworkCapabilities.TRANSPORT_VPN;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI_AWARE;
-import static android.net.NetworkPolicyManager.BLOCKED_METERED_REASON_DATA_SAVER;
-import static android.net.NetworkPolicyManager.BLOCKED_METERED_REASON_USER_RESTRICTED;
-import static android.net.NetworkPolicyManager.BLOCKED_REASON_BATTERY_SAVER;
-import static android.net.NetworkPolicyManager.BLOCKED_REASON_NONE;
import static android.net.OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PAID;
import static android.net.OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK;
import static android.net.OemNetworkPreferences.OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY;
@@ -266,6 +267,7 @@ import android.security.Credentials;
import android.system.Os;
import android.telephony.TelephonyManager;
import android.telephony.data.EpsBearerQosSessionAttributes;
+import android.telephony.data.NrQosSessionAttributes;
import android.test.mock.MockContentResolver;
import android.text.TextUtils;
import android.util.ArraySet;
@@ -715,6 +717,9 @@ public class ConnectivityServiceTest {
private int mProbesSucceeded;
private String mNmValidationRedirectUrl = null;
private boolean mNmProvNotificationRequested = false;
+ private Runnable mCreatedCallback;
+ private Runnable mUnwantedCallback;
+ private Runnable mDisconnectedCallback;
private final ConditionVariable mNetworkStatusReceived = new ConditionVariable();
// Contains the redirectUrl from networkStatus(). Before reading, wait for
@@ -769,6 +774,24 @@ public class ConnectivityServiceTest {
mRedirectUrl = redirectUrl;
mNetworkStatusReceived.open();
}
+
+ @Override
+ public void onNetworkCreated() {
+ super.onNetworkCreated();
+ if (mCreatedCallback != null) mCreatedCallback.run();
+ }
+
+ @Override
+ public void onNetworkUnwanted() {
+ super.onNetworkUnwanted();
+ if (mUnwantedCallback != null) mUnwantedCallback.run();
+ }
+
+ @Override
+ public void onNetworkDestroyed() {
+ super.onNetworkDestroyed();
+ if (mDisconnectedCallback != null) mDisconnectedCallback.run();
+ }
};
assertEquals(na.getNetwork().netId, nmNetworkCaptor.getValue().netId);
@@ -970,6 +993,18 @@ public class ConnectivityServiceTest {
p.timestampMillis = DATA_STALL_TIMESTAMP;
mNmCallbacks.notifyDataStallSuspected(p);
}
+
+ public void setCreatedCallback(Runnable r) {
+ mCreatedCallback = r;
+ }
+
+ public void setUnwantedCallback(Runnable r) {
+ mUnwantedCallback = r;
+ }
+
+ public void setDisconnectedCallback(Runnable r) {
+ mDisconnectedCallback = r;
+ }
}
/**
@@ -1178,11 +1213,6 @@ public class ConnectivityServiceTest {
}
@Override
- public int getNetId() {
- return (mMockNetworkAgent == null) ? NETID_UNSET : mMockNetworkAgent.getNetwork().netId;
- }
-
- @Override
public int getActiveVpnType() {
return mVpnType;
}
@@ -1206,10 +1236,10 @@ public class ConnectivityServiceTest {
mNetworkCapabilities);
mMockNetworkAgent.waitForIdle(TIMEOUT_MS);
- verify(mMockNetd, times(1)).networkAddUidRanges(eq(mMockVpn.getNetId()),
+ verify(mMockNetd, times(1)).networkAddUidRanges(eq(mMockVpn.getNetwork().getNetId()),
eq(toUidRangeStableParcels(uids)));
verify(mMockNetd, never())
- .networkRemoveUidRanges(eq(mMockVpn.getNetId()), any());
+ .networkRemoveUidRanges(eq(mMockVpn.getNetwork().getNetId()), any());
mAgentRegistered = true;
updateState(NetworkInfo.DetailedState.CONNECTED, "registerAgent");
mNetworkCapabilities.set(mMockNetworkAgent.getNetworkCapabilities());
@@ -1378,10 +1408,21 @@ public class ConnectivityServiceTest {
}
private void mockUidNetworkingBlocked() {
- doAnswer(i -> NetworkPolicyManager.isUidBlocked(mBlockedReasons, i.getArgument(1))
+ doAnswer(i -> isUidBlocked(mBlockedReasons, i.getArgument(1))
).when(mNetworkPolicyManager).isUidNetworkingBlocked(anyInt(), anyBoolean());
}
+ private boolean isUidBlocked(int blockedReasons, boolean meteredNetwork) {
+ final int blockedOnAllNetworksReason = (blockedReasons & ~BLOCKED_METERED_REASON_MASK);
+ if (blockedOnAllNetworksReason != BLOCKED_REASON_NONE) {
+ return true;
+ }
+ if (meteredNetwork) {
+ return blockedReasons != BLOCKED_REASON_NONE;
+ }
+ return false;
+ }
+
private void setBlockedReasonChanged(int blockedReasons) {
mBlockedReasons = blockedReasons;
mPolicyCallback.onUidBlockedReasonChanged(Process.myUid(), blockedReasons);
@@ -1451,6 +1492,23 @@ public class ConnectivityServiceTest {
});
}
+ private interface ExceptionalRunnable {
+ void run() throws Exception;
+ }
+
+ private void withPermission(String permission, ExceptionalRunnable r) throws Exception {
+ if (mServiceContext.checkCallingOrSelfPermission(permission) == PERMISSION_GRANTED) {
+ r.run();
+ return;
+ }
+ try {
+ mServiceContext.setPermission(permission, PERMISSION_GRANTED);
+ r.run();
+ } finally {
+ mServiceContext.setPermission(permission, PERMISSION_DENIED);
+ }
+ }
+
private static final int PRIMARY_USER = 0;
private static final UidRange PRIMARY_UIDRANGE =
UidRange.createForUser(UserHandle.of(PRIMARY_USER));
@@ -1559,7 +1617,7 @@ public class ConnectivityServiceTest {
doReturn(mNetworkStack).when(deps).getNetworkStack();
doReturn(mSystemProperties).when(deps).getSystemProperties();
doReturn(mock(ProxyTracker.class)).when(deps).makeProxyTracker(any(), any());
- doReturn(true).when(deps).queryUserAccess(anyInt(), anyInt());
+ doReturn(true).when(deps).queryUserAccess(anyInt(), any(), any());
doAnswer(inv -> {
mPolicyTracker = new WrappedMultinetworkPolicyTracker(
inv.getArgument(0), inv.getArgument(1), inv.getArgument(2));
@@ -2426,8 +2484,7 @@ public class ConnectivityServiceTest {
public void networkCallbacksSanitizationTest_Sanitize() throws Exception {
mServiceContext.setPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
PERMISSION_DENIED);
- mServiceContext.setPermission(Manifest.permission.NETWORK_SETTINGS,
- PERMISSION_DENIED);
+ mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_DENIED);
doNetworkCallbacksSanitizationTest(true /* sanitized */);
}
@@ -2435,7 +2492,7 @@ public class ConnectivityServiceTest {
public void networkCallbacksSanitizationTest_NoSanitize_NetworkStack() throws Exception {
mServiceContext.setPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
PERMISSION_GRANTED);
- mServiceContext.setPermission(Manifest.permission.NETWORK_SETTINGS, PERMISSION_DENIED);
+ mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_DENIED);
doNetworkCallbacksSanitizationTest(false /* sanitized */);
}
@@ -2443,7 +2500,7 @@ public class ConnectivityServiceTest {
public void networkCallbacksSanitizationTest_NoSanitize_Settings() throws Exception {
mServiceContext.setPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
PERMISSION_DENIED);
- mServiceContext.setPermission(Manifest.permission.NETWORK_SETTINGS, PERMISSION_GRANTED);
+ mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_GRANTED);
doNetworkCallbacksSanitizationTest(false /* sanitized */);
}
@@ -2787,6 +2844,94 @@ public class ConnectivityServiceTest {
}
@Test
+ public void testNetworkAgentCallbacks() throws Exception {
+ // Keeps track of the order of events that happen in this test.
+ final LinkedBlockingQueue<String> eventOrder = new LinkedBlockingQueue<>();
+
+ final NetworkRequest request = new NetworkRequest.Builder()
+ .addTransportType(TRANSPORT_WIFI).build();
+ final TestNetworkCallback callback = new TestNetworkCallback();
+ final AtomicReference<Network> wifiNetwork = new AtomicReference<>();
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
+
+ // Expectations for state when various callbacks fire. These expectations run on the handler
+ // thread and not on the test thread because they need to prevent the handler thread from
+ // advancing while they examine state.
+
+ // 1. When onCreated fires, netd has been told to create the network.
+ mWiFiNetworkAgent.setCreatedCallback(() -> {
+ eventOrder.offer("onNetworkCreated");
+ wifiNetwork.set(mWiFiNetworkAgent.getNetwork());
+ assertNotNull(wifiNetwork.get());
+ try {
+ verify(mMockNetd).networkCreatePhysical(wifiNetwork.get().getNetId(),
+ INetd.PERMISSION_NONE);
+ } catch (RemoteException impossible) {
+ fail();
+ }
+ });
+
+ // 2. onNetworkUnwanted isn't precisely ordered with respect to any particular events. Just
+ // check that it is fired at some point after disconnect.
+ mWiFiNetworkAgent.setUnwantedCallback(() -> eventOrder.offer("onNetworkUnwanted"));
+
+ // 3. While the teardown timer is running, connectivity APIs report the network is gone, but
+ // netd has not yet been told to destroy it.
+ final Runnable duringTeardown = () -> {
+ eventOrder.offer("timePasses");
+ assertNull(mCm.getLinkProperties(wifiNetwork.get()));
+ try {
+ verify(mMockNetd, never()).networkDestroy(wifiNetwork.get().getNetId());
+ } catch (RemoteException impossible) {
+ fail();
+ }
+ };
+
+ // 4. After onNetworkDisconnected is called, connectivity APIs report the network is gone,
+ // and netd has been told to destroy it.
+ mWiFiNetworkAgent.setDisconnectedCallback(() -> {
+ eventOrder.offer("onNetworkDisconnected");
+ assertNull(mCm.getLinkProperties(wifiNetwork.get()));
+ try {
+ verify(mMockNetd).networkDestroy(wifiNetwork.get().getNetId());
+ } catch (RemoteException impossible) {
+ fail();
+ }
+ });
+
+ // Connect a network, and file a request for it after it has come up, to ensure the nascent
+ // timer is cleared and the test does not have to wait for it. Filing the request after the
+ // network has come up is necessary because ConnectivityService does not appear to clear the
+ // nascent timer if the first request satisfied by the network was filed before the network
+ // connected.
+ // TODO: fix this bug, file the request before connecting, and remove the waitForIdle.
+ mWiFiNetworkAgent.connectWithoutInternet();
+ waitForIdle();
+ mCm.requestNetwork(request, callback);
+ callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
+
+ // Set teardown delay and make sure CS has processed it.
+ mWiFiNetworkAgent.getNetworkAgent().setTeardownDelayMs(300);
+ waitForIdle();
+
+ // Post the duringTeardown lambda to the handler so it fires while teardown is in progress.
+ // The delay must be long enough it will run after the unregisterNetworkCallback has torn
+ // down the network and started the teardown timer, and short enough that the lambda is
+ // scheduled to run before the teardown timer.
+ final Handler h = new Handler(mCsHandlerThread.getLooper());
+ h.postDelayed(duringTeardown, 150);
+
+ // Disconnect the network and check that events happened in the right order.
+ mCm.unregisterNetworkCallback(callback);
+ assertEquals("onNetworkCreated", eventOrder.poll(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+ assertEquals("onNetworkUnwanted", eventOrder.poll(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+ assertEquals("timePasses", eventOrder.poll(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+ assertEquals("onNetworkDisconnected", eventOrder.poll(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+
+ mCm.unregisterNetworkCallback(callback);
+ }
+
+ @Test
public void testExplicitlySelected() throws Exception {
NetworkRequest request = new NetworkRequest.Builder()
.clearCapabilities().addCapability(NET_CAPABILITY_INTERNET)
@@ -3427,8 +3572,7 @@ public class ConnectivityServiceTest {
@Test
public void testCaptivePortalApi() throws Exception {
- mServiceContext.setPermission(
- android.Manifest.permission.NETWORK_SETTINGS, PERMISSION_GRANTED);
+ mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_GRANTED);
final TestNetworkCallback captivePortalCallback = new TestNetworkCallback();
final NetworkRequest captivePortalRequest = new NetworkRequest.Builder()
@@ -3462,8 +3606,7 @@ public class ConnectivityServiceTest {
private TestNetworkCallback setupNetworkCallbackAndConnectToWifi() throws Exception {
// Grant NETWORK_SETTINGS permission to be able to receive LinkProperties change callbacks
// with sensitive (captive portal) data
- mServiceContext.setPermission(
- android.Manifest.permission.NETWORK_SETTINGS, PERMISSION_GRANTED);
+ mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_GRANTED);
final TestNetworkCallback captivePortalCallback = new TestNetworkCallback();
final NetworkRequest captivePortalRequest = new NetworkRequest.Builder()
@@ -3813,8 +3956,9 @@ public class ConnectivityServiceTest {
NetworkCapabilities networkCapabilities = new NetworkCapabilities();
networkCapabilities.addTransportType(TRANSPORT_WIFI)
.setNetworkSpecifier(new MatchAllNetworkSpecifier());
- mService.requestNetwork(networkCapabilities, NetworkRequest.Type.REQUEST.ordinal(),
- null, 0, null, ConnectivityManager.TYPE_WIFI, NetworkCallback.FLAG_NONE,
+ mService.requestNetwork(Process.INVALID_UID, networkCapabilities,
+ NetworkRequest.Type.REQUEST.ordinal(), null, 0, null,
+ ConnectivityManager.TYPE_WIFI, NetworkCallback.FLAG_NONE,
mContext.getPackageName(), getAttributionTag());
});
@@ -3896,8 +4040,7 @@ public class ConnectivityServiceTest {
@Test
public void testRegisterDefaultNetworkCallback() throws Exception {
// NETWORK_SETTINGS is necessary to call registerSystemDefaultNetworkCallback.
- mServiceContext.setPermission(Manifest.permission.NETWORK_SETTINGS,
- PERMISSION_GRANTED);
+ mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_GRANTED);
final TestNetworkCallback defaultNetworkCallback = new TestNetworkCallback();
mCm.registerDefaultNetworkCallback(defaultNetworkCallback);
@@ -4043,7 +4186,7 @@ public class ConnectivityServiceTest {
}
@Test
- public void testRegisterSystemDefaultCallbackRequiresNetworkSettings() throws Exception {
+ public void testRegisterPrivilegedDefaultCallbacksRequireNetworkSettings() throws Exception {
mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
mCellNetworkAgent.connect(false /* validated */);
@@ -4052,12 +4195,18 @@ public class ConnectivityServiceTest {
assertThrows(SecurityException.class,
() -> mCm.registerSystemDefaultNetworkCallback(callback, handler));
callback.assertNoCallback();
+ assertThrows(SecurityException.class,
+ () -> mCm.registerDefaultNetworkCallbackAsUid(APP1_UID, callback, handler));
+ callback.assertNoCallback();
- mServiceContext.setPermission(Manifest.permission.NETWORK_SETTINGS,
- PERMISSION_GRANTED);
+ mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_GRANTED);
mCm.registerSystemDefaultNetworkCallback(callback, handler);
callback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
mCm.unregisterNetworkCallback(callback);
+
+ mCm.registerDefaultNetworkCallbackAsUid(APP1_UID, callback, handler);
+ callback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
+ mCm.unregisterNetworkCallback(callback);
}
private void setCaptivePortalMode(int mode) {
@@ -5371,10 +5520,11 @@ public class ConnectivityServiceTest {
}
@Test
- public void testNetworkCallbackMaximum() {
+ public void testNetworkCallbackMaximum() throws Exception {
final int MAX_REQUESTS = 100;
final int CALLBACKS = 89;
final int INTENTS = 11;
+ final int SYSTEM_ONLY_MAX_REQUESTS = 250;
assertEquals(MAX_REQUESTS, CALLBACKS + INTENTS);
NetworkRequest networkRequest = new NetworkRequest.Builder().build();
@@ -5423,6 +5573,33 @@ public class ConnectivityServiceTest {
new Intent("d"), FLAG_IMMUTABLE))
);
+ // The system gets another SYSTEM_ONLY_MAX_REQUESTS slots.
+ final Handler handler = new Handler(ConnectivityThread.getInstanceLooper());
+ withPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, () -> {
+ ArrayList<NetworkCallback> systemRegistered = new ArrayList<>();
+ for (int i = 0; i < SYSTEM_ONLY_MAX_REQUESTS - 1; i++) {
+ NetworkCallback cb = new NetworkCallback();
+ if (i % 2 == 0) {
+ mCm.registerDefaultNetworkCallbackAsUid(1000000 + i, cb, handler);
+ } else {
+ mCm.registerNetworkCallback(networkRequest, cb);
+ }
+ systemRegistered.add(cb);
+ }
+ waitForIdle();
+
+ assertThrows(TooManyRequestsException.class, () ->
+ mCm.registerDefaultNetworkCallbackAsUid(1001042, new NetworkCallback(),
+ handler));
+ assertThrows(TooManyRequestsException.class, () ->
+ mCm.registerNetworkCallback(networkRequest, new NetworkCallback()));
+
+ for (NetworkCallback callback : systemRegistered) {
+ mCm.unregisterNetworkCallback(callback);
+ }
+ waitForIdle(); // Wait for requests to be unregistered before giving up the permission.
+ });
+
for (Object o : registered) {
if (o instanceof NetworkCallback) {
mCm.unregisterNetworkCallback((NetworkCallback)o);
@@ -5449,6 +5626,30 @@ public class ConnectivityServiceTest {
waitForIdle();
for (int i = 0; i < MAX_REQUESTS; i++) {
+ NetworkCallback networkCallback = new NetworkCallback();
+ mCm.registerDefaultNetworkCallback(networkCallback);
+ mCm.unregisterNetworkCallback(networkCallback);
+ }
+ waitForIdle();
+
+ for (int i = 0; i < MAX_REQUESTS; i++) {
+ NetworkCallback networkCallback = new NetworkCallback();
+ mCm.registerDefaultNetworkCallback(networkCallback);
+ mCm.unregisterNetworkCallback(networkCallback);
+ }
+ waitForIdle();
+
+ withPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, () -> {
+ for (int i = 0; i < MAX_REQUESTS; i++) {
+ NetworkCallback networkCallback = new NetworkCallback();
+ mCm.registerDefaultNetworkCallbackAsUid(1000000 + i, networkCallback,
+ new Handler(ConnectivityThread.getInstanceLooper()));
+ mCm.unregisterNetworkCallback(networkCallback);
+ }
+ });
+ waitForIdle();
+
+ for (int i = 0; i < MAX_REQUESTS; i++) {
final PendingIntent pendingIntent = PendingIntent.getBroadcast(
mContext, 0 /* requestCode */, new Intent("e" + i), FLAG_IMMUTABLE);
mCm.requestNetwork(networkRequest, pendingIntent);
@@ -6441,8 +6642,7 @@ public class ConnectivityServiceTest {
@Test
public void testVpnNetworkActive() throws Exception {
// NETWORK_SETTINGS is necessary to call registerSystemDefaultNetworkCallback.
- mServiceContext.setPermission(Manifest.permission.NETWORK_SETTINGS,
- PERMISSION_GRANTED);
+ mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_GRANTED);
final int uid = Process.myUid();
@@ -6934,8 +7134,7 @@ public class ConnectivityServiceTest {
@Test
public void testRestrictedProfileAffectsVpnUidRanges() throws Exception {
// NETWORK_SETTINGS is necessary to see the UID ranges in NetworkCapabilities.
- mServiceContext.setPermission(Manifest.permission.NETWORK_SETTINGS,
- PERMISSION_GRANTED);
+ mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_GRANTED);
final NetworkRequest request = new NetworkRequest.Builder()
.removeCapability(NET_CAPABILITY_NOT_VPN)
@@ -7021,8 +7220,7 @@ public class ConnectivityServiceTest {
mServiceContext.setPermission(
Manifest.permission.CONTROL_VPN, PERMISSION_GRANTED);
// Necessary to see the UID ranges in NetworkCapabilities.
- mServiceContext.setPermission(
- Manifest.permission.NETWORK_SETTINGS, PERMISSION_GRANTED);
+ mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_GRANTED);
final NetworkRequest request = new NetworkRequest.Builder()
.removeCapability(NET_CAPABILITY_NOT_VPN)
@@ -7257,6 +7455,20 @@ public class ConnectivityServiceTest {
mMockVpn.disconnect();
}
+ private class DetailedBlockedStatusCallback extends TestNetworkCallback {
+ public void expectAvailableThenValidatedCallbacks(HasNetwork n, int blockedStatus) {
+ super.expectAvailableThenValidatedCallbacks(n.getNetwork(), blockedStatus, TIMEOUT_MS);
+ }
+ public void expectBlockedStatusCallback(HasNetwork n, int blockedStatus) {
+ // This doesn't work:
+ // super.expectBlockedStatusCallback(blockedStatus, n.getNetwork());
+ super.expectBlockedStatusCallback(blockedStatus, n.getNetwork(), TIMEOUT_MS);
+ }
+ public void onBlockedStatusChanged(Network network, int blockedReasons) {
+ getHistory().add(new CallbackEntry.BlockedStatusInt(network, blockedReasons));
+ }
+ }
+
@Test
public void testNetworkBlockedStatus() throws Exception {
final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback();
@@ -7264,11 +7476,16 @@ public class ConnectivityServiceTest {
.addTransportType(TRANSPORT_CELLULAR)
.build();
mCm.registerNetworkCallback(cellRequest, cellNetworkCallback);
+ final DetailedBlockedStatusCallback detailedCallback = new DetailedBlockedStatusCallback();
+ mCm.registerNetworkCallback(cellRequest, detailedCallback);
+
mockUidNetworkingBlocked();
mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
mCellNetworkAgent.connect(true);
cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+ detailedCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent,
+ BLOCKED_REASON_NONE);
assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
@@ -7276,17 +7493,23 @@ public class ConnectivityServiceTest {
setBlockedReasonChanged(BLOCKED_REASON_BATTERY_SAVER);
cellNetworkCallback.expectBlockedStatusCallback(true, mCellNetworkAgent);
+ detailedCallback.expectBlockedStatusCallback(mCellNetworkAgent,
+ BLOCKED_REASON_BATTERY_SAVER);
assertNull(mCm.getActiveNetwork());
assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
assertExtraInfoFromCmBlocked(mCellNetworkAgent);
- // ConnectivityService should cache it not to invoke the callback again.
+ // If blocked state does not change but blocked reason does, the boolean callback is called.
+ // TODO: investigate de-duplicating.
setBlockedReasonChanged(BLOCKED_METERED_REASON_USER_RESTRICTED);
- cellNetworkCallback.assertNoCallback();
+ cellNetworkCallback.expectBlockedStatusCallback(true, mCellNetworkAgent);
+ detailedCallback.expectBlockedStatusCallback(mCellNetworkAgent,
+ BLOCKED_METERED_REASON_USER_RESTRICTED);
setBlockedReasonChanged(BLOCKED_REASON_NONE);
cellNetworkCallback.expectBlockedStatusCallback(false, mCellNetworkAgent);
+ detailedCallback.expectBlockedStatusCallback(mCellNetworkAgent, BLOCKED_REASON_NONE);
assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
@@ -7294,6 +7517,8 @@ public class ConnectivityServiceTest {
setBlockedReasonChanged(BLOCKED_METERED_REASON_DATA_SAVER);
cellNetworkCallback.expectBlockedStatusCallback(true, mCellNetworkAgent);
+ detailedCallback.expectBlockedStatusCallback(mCellNetworkAgent,
+ BLOCKED_METERED_REASON_DATA_SAVER);
assertNull(mCm.getActiveNetwork());
assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
@@ -7303,6 +7528,8 @@ public class ConnectivityServiceTest {
mCellNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
cellNetworkCallback.expectCapabilitiesWith(NET_CAPABILITY_NOT_METERED, mCellNetworkAgent);
cellNetworkCallback.expectBlockedStatusCallback(false, mCellNetworkAgent);
+ detailedCallback.expectCapabilitiesWith(NET_CAPABILITY_NOT_METERED, mCellNetworkAgent);
+ detailedCallback.expectBlockedStatusCallback(mCellNetworkAgent, BLOCKED_REASON_NONE);
assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
@@ -7312,6 +7539,10 @@ public class ConnectivityServiceTest {
cellNetworkCallback.expectCapabilitiesWithout(NET_CAPABILITY_NOT_METERED,
mCellNetworkAgent);
cellNetworkCallback.expectBlockedStatusCallback(true, mCellNetworkAgent);
+ detailedCallback.expectCapabilitiesWithout(NET_CAPABILITY_NOT_METERED,
+ mCellNetworkAgent);
+ detailedCallback.expectBlockedStatusCallback(mCellNetworkAgent,
+ BLOCKED_METERED_REASON_DATA_SAVER);
assertNull(mCm.getActiveNetwork());
assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
@@ -7319,6 +7550,7 @@ public class ConnectivityServiceTest {
setBlockedReasonChanged(BLOCKED_REASON_NONE);
cellNetworkCallback.expectBlockedStatusCallback(false, mCellNetworkAgent);
+ detailedCallback.expectBlockedStatusCallback(mCellNetworkAgent, BLOCKED_REASON_NONE);
assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
@@ -7326,10 +7558,13 @@ public class ConnectivityServiceTest {
setBlockedReasonChanged(BLOCKED_REASON_NONE);
cellNetworkCallback.assertNoCallback();
+ detailedCallback.assertNoCallback();
// Restrict background data. Networking is not blocked because the network is unmetered.
setBlockedReasonChanged(BLOCKED_METERED_REASON_DATA_SAVER);
cellNetworkCallback.expectBlockedStatusCallback(true, mCellNetworkAgent);
+ detailedCallback.expectBlockedStatusCallback(mCellNetworkAgent,
+ BLOCKED_METERED_REASON_DATA_SAVER);
assertNull(mCm.getActiveNetwork());
assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
assertNetworkInfo(TYPE_MOBILE, DetailedState.BLOCKED);
@@ -7339,12 +7574,14 @@ public class ConnectivityServiceTest {
setBlockedReasonChanged(BLOCKED_REASON_NONE);
cellNetworkCallback.expectBlockedStatusCallback(false, mCellNetworkAgent);
+ detailedCallback.expectBlockedStatusCallback(mCellNetworkAgent, BLOCKED_REASON_NONE);
assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
assertExtraInfoFromCmPresent(mCellNetworkAgent);
setBlockedReasonChanged(BLOCKED_REASON_NONE);
cellNetworkCallback.assertNoCallback();
+ detailedCallback.assertNoCallback();
assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
assertActiveNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
assertNetworkInfo(TYPE_MOBILE, DetailedState.CONNECTED);
@@ -7471,8 +7708,7 @@ public class ConnectivityServiceTest {
Manifest.permission.CONTROL_ALWAYS_ON_VPN, PERMISSION_GRANTED);
mServiceContext.setPermission(
Manifest.permission.CONTROL_VPN, PERMISSION_GRANTED);
- mServiceContext.setPermission(
- Manifest.permission.NETWORK_SETTINGS, PERMISSION_GRANTED);
+ mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_GRANTED);
final TestNetworkCallback callback = new TestNetworkCallback();
final NetworkRequest request = new NetworkRequest.Builder()
@@ -7490,6 +7726,10 @@ public class ConnectivityServiceTest {
final TestNetworkCallback vpnUidDefaultCallback = new TestNetworkCallback();
registerDefaultNetworkCallbackAsUid(vpnUidDefaultCallback, VPN_UID);
+ final TestNetworkCallback vpnDefaultCallbackAsUid = new TestNetworkCallback();
+ mCm.registerDefaultNetworkCallbackAsUid(VPN_UID, vpnDefaultCallbackAsUid,
+ new Handler(ConnectivityThread.getInstanceLooper()));
+
final int uid = Process.myUid();
final int userId = UserHandle.getUserId(uid);
final ArrayList<String> allowList = new ArrayList<>();
@@ -7509,6 +7749,7 @@ public class ConnectivityServiceTest {
defaultCallback.expectAvailableCallbacksUnvalidatedAndBlocked(mWiFiNetworkAgent);
vpnUidCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
vpnUidDefaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
+ vpnDefaultCallbackAsUid.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID));
assertNull(mCm.getActiveNetwork());
assertActiveNetworkInfo(TYPE_WIFI, DetailedState.BLOCKED);
@@ -7522,6 +7763,7 @@ public class ConnectivityServiceTest {
defaultCallback.expectBlockedStatusCallback(false, mWiFiNetworkAgent);
vpnUidCallback.assertNoCallback();
vpnUidDefaultCallback.assertNoCallback();
+ vpnDefaultCallbackAsUid.assertNoCallback();
expectNetworkRejectNonSecureVpn(inOrder, false, firstHalf, secondHalf);
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID));
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
@@ -7537,6 +7779,7 @@ public class ConnectivityServiceTest {
defaultCallback.assertNoCallback();
vpnUidCallback.assertNoCallback();
vpnUidDefaultCallback.assertNoCallback();
+ vpnDefaultCallbackAsUid.assertNoCallback();
// The following requires that the UID of this test package is greater than VPN_UID. This
// is always true in practice because a plain AOSP build with no apps installed has almost
@@ -7558,6 +7801,7 @@ public class ConnectivityServiceTest {
defaultCallback.assertNoCallback();
vpnUidCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
vpnUidDefaultCallback.assertNoCallback();
+ vpnDefaultCallbackAsUid.assertNoCallback();
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID));
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
@@ -7579,6 +7823,7 @@ public class ConnectivityServiceTest {
assertBlockedCallbackInAnyOrder(callback, true, mWiFiNetworkAgent, mCellNetworkAgent);
vpnUidCallback.assertNoCallback();
vpnUidDefaultCallback.assertNoCallback();
+ vpnDefaultCallbackAsUid.assertNoCallback();
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID));
assertNull(mCm.getActiveNetwork());
assertActiveNetworkInfo(TYPE_WIFI, DetailedState.BLOCKED);
@@ -7591,6 +7836,7 @@ public class ConnectivityServiceTest {
assertBlockedCallbackInAnyOrder(callback, false, mWiFiNetworkAgent, mCellNetworkAgent);
vpnUidCallback.assertNoCallback();
vpnUidDefaultCallback.assertNoCallback();
+ vpnDefaultCallbackAsUid.assertNoCallback();
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID));
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
@@ -7606,6 +7852,7 @@ public class ConnectivityServiceTest {
defaultCallback.assertNoCallback();
vpnUidCallback.assertNoCallback();
vpnUidDefaultCallback.assertNoCallback();
+ vpnDefaultCallbackAsUid.assertNoCallback();
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID));
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
@@ -7618,6 +7865,7 @@ public class ConnectivityServiceTest {
defaultCallback.assertNoCallback();
vpnUidCallback.assertNoCallback();
vpnUidDefaultCallback.assertNoCallback();
+ vpnDefaultCallbackAsUid.assertNoCallback();
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID));
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
@@ -7631,6 +7879,7 @@ public class ConnectivityServiceTest {
assertBlockedCallbackInAnyOrder(callback, true, mWiFiNetworkAgent, mCellNetworkAgent);
vpnUidCallback.assertNoCallback();
vpnUidDefaultCallback.assertNoCallback();
+ vpnDefaultCallbackAsUid.assertNoCallback();
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID));
assertNull(mCm.getActiveNetwork());
assertActiveNetworkInfo(TYPE_WIFI, DetailedState.BLOCKED);
@@ -7642,6 +7891,7 @@ public class ConnectivityServiceTest {
defaultCallback.expectAvailableThenValidatedCallbacks(mMockVpn);
vpnUidCallback.assertNoCallback(); // vpnUidCallback has NOT_VPN capability.
vpnUidDefaultCallback.assertNoCallback(); // VPN does not apply to VPN_UID
+ vpnDefaultCallbackAsUid.assertNoCallback();
assertEquals(mMockVpn.getNetwork(), mCm.getActiveNetwork());
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetworkForUid(VPN_UID));
assertActiveNetworkInfo(TYPE_WIFI, DetailedState.CONNECTED);
@@ -7654,12 +7904,14 @@ public class ConnectivityServiceTest {
defaultCallback.expectAvailableCallbacksUnvalidatedAndBlocked(mWiFiNetworkAgent);
vpnUidCallback.assertNoCallback();
vpnUidDefaultCallback.assertNoCallback();
+ vpnDefaultCallbackAsUid.assertNoCallback();
assertNull(mCm.getActiveNetwork());
mCm.unregisterNetworkCallback(callback);
mCm.unregisterNetworkCallback(defaultCallback);
mCm.unregisterNetworkCallback(vpnUidCallback);
mCm.unregisterNetworkCallback(vpnUidDefaultCallback);
+ mCm.unregisterNetworkCallback(vpnDefaultCallbackAsUid);
}
private void setupLegacyLockdownVpn() {
@@ -7692,8 +7944,7 @@ public class ConnectivityServiceTest {
mServiceContext.setPermission(
Manifest.permission.CONTROL_VPN, PERMISSION_GRANTED);
// For LockdownVpnTracker to call registerSystemDefaultNetworkCallback.
- mServiceContext.setPermission(
- Manifest.permission.NETWORK_SETTINGS, PERMISSION_GRANTED);
+ mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_GRANTED);
final NetworkRequest request = new NetworkRequest.Builder().clearCapabilities().build();
final TestNetworkCallback callback = new TestNetworkCallback();
@@ -8823,8 +9074,7 @@ public class ConnectivityServiceTest {
private void denyAllLocationPrivilegedPermissions() {
mServiceContext.setPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
PERMISSION_DENIED);
- mServiceContext.setPermission(Manifest.permission.NETWORK_SETTINGS,
- PERMISSION_DENIED);
+ mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_DENIED);
mServiceContext.setPermission(Manifest.permission.NETWORK_STACK,
PERMISSION_DENIED);
mServiceContext.setPermission(Manifest.permission.NETWORK_SETUP_WIZARD,
@@ -9080,7 +9330,7 @@ public class ConnectivityServiceTest {
@Test
public void testCreateForCallerWithLocalMacAddressSanitizedWithSettingsPermission()
throws Exception {
- mServiceContext.setPermission(Manifest.permission.NETWORK_SETTINGS, PERMISSION_GRANTED);
+ mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_GRANTED);
final TransportInfo transportInfo = mock(TransportInfo.class);
when(transportInfo.getApplicableRedactions())
@@ -9761,10 +10011,12 @@ public class ConnectivityServiceTest {
assertContainsExactly(exemptUidCaptor.getValue(), Process.VPN_UID, exemptUid);
if (add) {
- inOrder.verify(mMockNetd, times(1)).networkAddUidRanges(eq(mMockVpn.getNetId()),
+ inOrder.verify(mMockNetd, times(1))
+ .networkAddUidRanges(eq(mMockVpn.getNetwork().getNetId()),
eq(toUidRangeStableParcels(vpnRanges)));
} else {
- inOrder.verify(mMockNetd, times(1)).networkRemoveUidRanges(eq(mMockVpn.getNetId()),
+ inOrder.verify(mMockNetd, times(1))
+ .networkRemoveUidRanges(eq(mMockVpn.getNetwork().getNetId()),
eq(toUidRangeStableParcels(vpnRanges)));
}
@@ -9805,8 +10057,8 @@ public class ConnectivityServiceTest {
for (int reqTypeInt : invalidReqTypeInts) {
assertThrows("Expect throws for invalid request type " + reqTypeInt,
IllegalArgumentException.class,
- () -> mService.requestNetwork(nc, reqTypeInt, null, 0, null,
- ConnectivityManager.TYPE_NONE, NetworkCallback.FLAG_NONE,
+ () -> mService.requestNetwork(Process.INVALID_UID, nc, reqTypeInt, null, 0,
+ null, ConnectivityManager.TYPE_NONE, NetworkCallback.FLAG_NONE,
mContext.getPackageName(), getAttributionTag())
);
}
@@ -9925,7 +10177,7 @@ public class ConnectivityServiceTest {
&& session.getSessionType() == QosSession.TYPE_EPS_BEARER), eq(attributes));
mQosCallbackMockHelper.mAgentWrapper.getNetworkAgent()
- .sendQosSessionLost(qosCallbackId, sessionId);
+ .sendQosSessionLost(qosCallbackId, sessionId, QosSession.TYPE_EPS_BEARER);
waitForIdle();
verify(mQosCallbackMockHelper.mCallback).onQosSessionLost(argThat(session ->
session.getSessionId() == sessionId
@@ -9933,6 +10185,36 @@ public class ConnectivityServiceTest {
}
@Test
+ public void testNrQosCallbackAvailableAndLost() throws Exception {
+ mQosCallbackMockHelper = new QosCallbackMockHelper();
+ final int sessionId = 10;
+ final int qosCallbackId = 1;
+
+ when(mQosCallbackMockHelper.mFilter.validate())
+ .thenReturn(QosCallbackException.EX_TYPE_FILTER_NONE);
+ mQosCallbackMockHelper.registerQosCallback(
+ mQosCallbackMockHelper.mFilter, mQosCallbackMockHelper.mCallback);
+ waitForIdle();
+
+ final NrQosSessionAttributes attributes = new NrQosSessionAttributes(
+ 1, 2, 3, 4, 5, 6, 7, new ArrayList<>());
+ mQosCallbackMockHelper.mAgentWrapper.getNetworkAgent()
+ .sendQosSessionAvailable(qosCallbackId, sessionId, attributes);
+ waitForIdle();
+
+ verify(mQosCallbackMockHelper.mCallback).onNrQosSessionAvailable(argThat(session ->
+ session.getSessionId() == sessionId
+ && session.getSessionType() == QosSession.TYPE_NR_BEARER), eq(attributes));
+
+ mQosCallbackMockHelper.mAgentWrapper.getNetworkAgent()
+ .sendQosSessionLost(qosCallbackId, sessionId, QosSession.TYPE_NR_BEARER);
+ waitForIdle();
+ verify(mQosCallbackMockHelper.mCallback).onQosSessionLost(argThat(session ->
+ session.getSessionId() == sessionId
+ && session.getSessionType() == QosSession.TYPE_NR_BEARER));
+ }
+
+ @Test
public void testQosCallbackTooManyRequests() throws Exception {
mQosCallbackMockHelper = new QosCallbackMockHelper();
@@ -10367,8 +10649,7 @@ public class ConnectivityServiceTest {
private void registerDefaultNetworkCallbacks() {
// Using Manifest.permission.NETWORK_SETTINGS for registerSystemDefaultNetworkCallback()
- mServiceContext.setPermission(
- Manifest.permission.NETWORK_SETTINGS, PERMISSION_GRANTED);
+ mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_GRANTED);
mSystemDefaultNetworkCallback = new TestNetworkCallback();
mDefaultNetworkCallback = new TestNetworkCallback();
mProfileDefaultNetworkCallback = new TestNetworkCallback();
@@ -10377,8 +10658,8 @@ public class ConnectivityServiceTest {
mCm.registerDefaultNetworkCallback(mDefaultNetworkCallback);
registerDefaultNetworkCallbackAsUid(mProfileDefaultNetworkCallback,
TEST_WORK_PROFILE_APP_UID);
- mServiceContext.setPermission(
- Manifest.permission.NETWORK_SETTINGS, PERMISSION_DENIED);
+ // TODO: test using ConnectivityManager#registerDefaultNetworkCallbackAsUid as well.
+ mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_DENIED);
}
private void unregisterDefaultNetworkCallbacks() {
@@ -10396,7 +10677,7 @@ public class ConnectivityServiceTest {
private void setupMultipleDefaultNetworksForOemNetworkPreferenceNotCurrentUidTest(
@OemNetworkPreferences.OemNetworkPreference final int networkPrefToSetup)
throws Exception {
- final int testPackageNameUid = 123;
+ final int testPackageNameUid = TEST_PACKAGE_UID;
final String testPackageName = "per.app.defaults.package";
setupMultipleDefaultNetworksForOemNetworkPreferenceTest(
networkPrefToSetup, testPackageNameUid, testPackageName);
@@ -10532,6 +10813,11 @@ public class ConnectivityServiceTest {
mCm.registerDefaultNetworkCallback(defaultNetworkCallback);
defaultNetworkCallback.assertNoCallback();
+ final TestNetworkCallback otherUidDefaultCallback = new TestNetworkCallback();
+ withPermission(NETWORK_SETTINGS, () ->
+ mCm.registerDefaultNetworkCallbackAsUid(TEST_PACKAGE_UID, otherUidDefaultCallback,
+ new Handler(ConnectivityThread.getInstanceLooper())));
+
// Setup the test process to use networkPref for their default network.
setupMultipleDefaultNetworksForOemNetworkPreferenceCurrentUidTest(networkPref);
@@ -10542,19 +10828,22 @@ public class ConnectivityServiceTest {
null,
mEthernetNetworkAgent.getNetwork());
- // At this point with a restricted network used, the available callback should trigger
+ // At this point with a restricted network used, the available callback should trigger.
defaultNetworkCallback.expectAvailableThenValidatedCallbacks(mEthernetNetworkAgent);
assertEquals(defaultNetworkCallback.getLastAvailableNetwork(),
mEthernetNetworkAgent.getNetwork());
+ otherUidDefaultCallback.assertNoCallback();
// Now bring down the default network which should trigger a LOST callback.
setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, false);
// At this point, with no network is available, the lost callback should trigger
defaultNetworkCallback.expectCallback(CallbackEntry.LOST, mEthernetNetworkAgent);
+ otherUidDefaultCallback.assertNoCallback();
// Confirm we can unregister without issues.
mCm.unregisterNetworkCallback(defaultNetworkCallback);
+ mCm.unregisterNetworkCallback(otherUidDefaultCallback);
}
@Test
@@ -10572,6 +10861,11 @@ public class ConnectivityServiceTest {
mCm.registerDefaultNetworkCallback(defaultNetworkCallback);
defaultNetworkCallback.assertNoCallback();
+ final TestNetworkCallback otherUidDefaultCallback = new TestNetworkCallback();
+ withPermission(NETWORK_SETTINGS, () ->
+ mCm.registerDefaultNetworkCallbackAsUid(TEST_PACKAGE_UID, otherUidDefaultCallback,
+ new Handler(ConnectivityThread.getInstanceLooper())));
+
// Bring up ethernet with OEM_PAID. This will satisfy NET_CAPABILITY_OEM_PAID.
// The active nai for the default is null at this point as this is a restricted network.
setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, true);
@@ -10583,15 +10877,19 @@ public class ConnectivityServiceTest {
defaultNetworkCallback.expectAvailableThenValidatedCallbacks(mEthernetNetworkAgent);
assertEquals(defaultNetworkCallback.getLastAvailableNetwork(),
mEthernetNetworkAgent.getNetwork());
+ otherUidDefaultCallback.assertNoCallback();
// Now bring down the default network which should trigger a LOST callback.
setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, false);
+ otherUidDefaultCallback.assertNoCallback();
// At this point, with no network is available, the lost callback should trigger
defaultNetworkCallback.expectCallback(CallbackEntry.LOST, mEthernetNetworkAgent);
+ otherUidDefaultCallback.assertNoCallback();
// Confirm we can unregister without issues.
mCm.unregisterNetworkCallback(defaultNetworkCallback);
+ mCm.unregisterNetworkCallback(otherUidDefaultCallback);
}
@Test
@@ -10605,6 +10903,11 @@ public class ConnectivityServiceTest {
mCm.registerDefaultNetworkCallback(defaultNetworkCallback);
defaultNetworkCallback.assertNoCallback();
+ final TestNetworkCallback otherUidDefaultCallback = new TestNetworkCallback();
+ withPermission(NETWORK_SETTINGS, () ->
+ mCm.registerDefaultNetworkCallbackAsUid(TEST_PACKAGE_UID, otherUidDefaultCallback,
+ new Handler(ConnectivityThread.getInstanceLooper())));
+
// Setup a process different than the test process to use the default network. This means
// that the defaultNetworkCallback won't be tracked by the per-app policy.
setupMultipleDefaultNetworksForOemNetworkPreferenceNotCurrentUidTest(networkPref);
@@ -10620,6 +10923,9 @@ public class ConnectivityServiceTest {
defaultNetworkCallback.assertNoCallback();
assertDefaultNetworkCapabilities(userId /* no networks */);
+ // The other UID does have access, and gets a callback.
+ otherUidDefaultCallback.expectAvailableThenValidatedCallbacks(mEthernetNetworkAgent);
+
// Bring up unrestricted cellular. This should now satisfy the default network.
setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, true);
verifyMultipleDefaultNetworksTracksCorrectly(expectedOemPrefRequestSize,
@@ -10627,25 +10933,31 @@ public class ConnectivityServiceTest {
mEthernetNetworkAgent.getNetwork());
// At this point with an unrestricted network used, the available callback should trigger
+ // The other UID is unaffected and remains on the paid network.
defaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
assertEquals(defaultNetworkCallback.getLastAvailableNetwork(),
mCellNetworkAgent.getNetwork());
assertDefaultNetworkCapabilities(userId, mCellNetworkAgent);
+ otherUidDefaultCallback.assertNoCallback();
// Now bring down the per-app network.
setOemNetworkPreferenceAgentConnected(TRANSPORT_ETHERNET, false);
- // Since the callback didn't use the per-app network, no callback should fire.
+ // Since the callback didn't use the per-app network, only the other UID gets a callback.
+ // Because the preference specifies no fallback, it does not switch to cellular.
defaultNetworkCallback.assertNoCallback();
+ otherUidDefaultCallback.expectCallback(CallbackEntry.LOST, mEthernetNetworkAgent);
// Now bring down the default network.
setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, false);
// As this callback was tracking the default, this should now trigger.
defaultNetworkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
+ otherUidDefaultCallback.assertNoCallback();
// Confirm we can unregister without issues.
mCm.unregisterNetworkCallback(defaultNetworkCallback);
+ mCm.unregisterNetworkCallback(otherUidDefaultCallback);
}
/**
diff --git a/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java b/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
index 8c5d1d6d05e5..8b072c49de82 100644
--- a/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
+++ b/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
@@ -22,7 +22,9 @@ import static android.net.metrics.INetdEventListener.EVENT_GETHOSTBYNAME;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
@@ -56,6 +58,7 @@ import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -80,6 +83,12 @@ public class IpConnectivityMetricsTest {
IpConnectivityMetrics mService;
NetdEventListenerService mNetdListener;
+ private static final NetworkCapabilities CAPABILITIES_WIFI = new NetworkCapabilities.Builder()
+ .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
+ .build();
+ private static final NetworkCapabilities CAPABILITIES_CELL = new NetworkCapabilities.Builder()
+ .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
+ .build();
@Before
public void setUp() {
@@ -263,14 +272,6 @@ public class IpConnectivityMetricsTest {
// TODO: instead of comparing textpb to textpb, parse textpb and compare proto to proto.
IpConnectivityLog logger = new IpConnectivityLog(mService.impl);
- NetworkCapabilities ncWifi = new NetworkCapabilities();
- NetworkCapabilities ncCell = new NetworkCapabilities();
- ncWifi.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
- ncCell.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
-
- when(mCm.getNetworkCapabilities(new Network(100))).thenReturn(ncWifi);
- when(mCm.getNetworkCapabilities(new Network(101))).thenReturn(ncCell);
-
ApfStats apfStats = new ApfStats.Builder()
.setDurationMs(45000)
.setReceivedRas(10)
@@ -584,11 +585,21 @@ public class IpConnectivityMetricsTest {
return buffer.toString();
}
- void connectEvent(int netid, int error, int latencyMs, String ipAddr) throws Exception {
- mNetdListener.onConnectEvent(netid, error, latencyMs, ipAddr, 80, 1);
+ private void setCapabilities(int netId) {
+ final ArgumentCaptor<ConnectivityManager.NetworkCallback> networkCallback =
+ ArgumentCaptor.forClass(ConnectivityManager.NetworkCallback.class);
+ verify(mCm).registerNetworkCallback(any(), networkCallback.capture());
+ networkCallback.getValue().onCapabilitiesChanged(new Network(netId),
+ netId == 100 ? CAPABILITIES_WIFI : CAPABILITIES_CELL);
+ }
+
+ void connectEvent(int netId, int error, int latencyMs, String ipAddr) throws Exception {
+ setCapabilities(netId);
+ mNetdListener.onConnectEvent(netId, error, latencyMs, ipAddr, 80, 1);
}
void dnsEvent(int netId, int type, int result, int latency) throws Exception {
+ setCapabilities(netId);
mNetdListener.onDnsEvent(netId, type, result, latency, "", null, 0, 0);
}
diff --git a/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java b/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java
index 8ccea1aa3474..50aaaee24418 100644
--- a/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java
+++ b/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java
@@ -23,8 +23,9 @@ import static com.android.testutils.MiscAsserts.assertStringContains;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.verify;
import android.content.Context;
import android.net.ConnectivityManager;
@@ -42,6 +43,7 @@ import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.IpCon
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import java.io.FileOutputStream;
import java.io.PrintWriter;
@@ -61,18 +63,16 @@ public class NetdEventListenerServiceTest {
NetdEventListenerService mService;
ConnectivityManager mCm;
+ private static final NetworkCapabilities CAPABILITIES_WIFI = new NetworkCapabilities.Builder()
+ .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
+ .build();
+ private static final NetworkCapabilities CAPABILITIES_CELL = new NetworkCapabilities.Builder()
+ .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
+ .build();
@Before
public void setUp() {
- NetworkCapabilities ncWifi = new NetworkCapabilities();
- NetworkCapabilities ncCell = new NetworkCapabilities();
- ncWifi.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
- ncCell.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
-
mCm = mock(ConnectivityManager.class);
- when(mCm.getNetworkCapabilities(new Network(100))).thenReturn(ncWifi);
- when(mCm.getNetworkCapabilities(new Network(101))).thenReturn(ncCell);
-
mService = new NetdEventListenerService(mCm);
}
@@ -470,7 +470,16 @@ public class NetdEventListenerServiceTest {
assertEquals(want, got);
}
+ private void setCapabilities(int netId) {
+ final ArgumentCaptor<ConnectivityManager.NetworkCallback> networkCallback =
+ ArgumentCaptor.forClass(ConnectivityManager.NetworkCallback.class);
+ verify(mCm).registerNetworkCallback(any(), networkCallback.capture());
+ networkCallback.getValue().onCapabilitiesChanged(new Network(netId),
+ netId == 100 ? CAPABILITIES_WIFI : CAPABILITIES_CELL);
+ }
+
Thread connectEventAction(int netId, int error, int latencyMs, String ipAddr) {
+ setCapabilities(netId);
return new Thread(() -> {
try {
mService.onConnectEvent(netId, error, latencyMs, ipAddr, 80, 1);
@@ -481,6 +490,7 @@ public class NetdEventListenerServiceTest {
}
void dnsEvent(int netId, int type, int result, int latency) throws Exception {
+ setCapabilities(netId);
mService.onDnsEvent(netId, type, result, latency, "", null, 0, 0);
}
diff --git a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
index 9334e2c4ad77..eeeb4fb1d929 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
@@ -89,6 +89,7 @@ import android.net.NetworkStats;
import android.net.NetworkStatsHistory;
import android.net.NetworkTemplate;
import android.net.UnderlyingNetworkInfo;
+import android.net.TelephonyNetworkSpecifier;
import android.net.netstats.provider.INetworkStatsProviderCallback;
import android.os.ConditionVariable;
import android.os.Handler;
@@ -1280,6 +1281,77 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
}
@Test
+ public void testDualVilteProviderStats() throws Exception {
+ // Pretend that network comes online.
+ expectDefaultSettings();
+ final int subId1 = 1;
+ final int subId2 = 2;
+ final NetworkStateSnapshot[] states = new NetworkStateSnapshot[]{
+ buildImsState(IMSI_1, subId1, TEST_IFACE),
+ buildImsState(IMSI_2, subId2, TEST_IFACE2)};
+ expectNetworkStatsSummary(buildEmptyStats());
+ expectNetworkStatsUidDetail(buildEmptyStats());
+
+ // Register custom provider and retrieve callback.
+ final TestableNetworkStatsProviderBinder provider =
+ new TestableNetworkStatsProviderBinder();
+ final INetworkStatsProviderCallback cb =
+ mService.registerNetworkStatsProvider("TEST", provider);
+ assertNotNull(cb);
+
+ mService.forceUpdateIfaces(NETWORKS_MOBILE, states, getActiveIface(states),
+ new UnderlyingNetworkInfo[0]);
+
+ // Verifies that one requestStatsUpdate will be called during iface update.
+ provider.expectOnRequestStatsUpdate(0 /* unused */);
+
+ // Create some initial traffic and report to the service.
+ incrementCurrentTime(HOUR_IN_MILLIS);
+ final String vtIface1 = NetworkStats.IFACE_VT + subId1;
+ final String vtIface2 = NetworkStats.IFACE_VT + subId2;
+ final NetworkStats expectedStats = new NetworkStats(0L, 1)
+ .addEntry(new NetworkStats.Entry(vtIface1, UID_RED, SET_DEFAULT,
+ TAG_NONE, METERED_YES, ROAMING_NO, DEFAULT_NETWORK_YES,
+ 128L, 2L, 128L, 2L, 1L))
+ .addEntry(new NetworkStats.Entry(vtIface2, UID_RED, SET_DEFAULT,
+ TAG_NONE, METERED_YES, ROAMING_NO, DEFAULT_NETWORK_YES,
+ 64L, 1L, 64L, 1L, 1L));
+ cb.notifyStatsUpdated(0 /* unused */, expectedStats, expectedStats);
+
+ // Make another empty mutable stats object. This is necessary since the new NetworkStats
+ // object will be used to compare with the old one in NetworkStatsRecoder, two of them
+ // cannot be the same object.
+ expectNetworkStatsUidDetail(buildEmptyStats());
+
+ forcePollAndWaitForIdle();
+
+ // Verifies that one requestStatsUpdate and setAlert will be called during polling.
+ provider.expectOnRequestStatsUpdate(0 /* unused */);
+ provider.expectOnSetAlert(MB_IN_BYTES);
+
+ // Verifies that service recorded history, does not verify uid tag part.
+ assertUidTotal(sTemplateImsi1, UID_RED, 128L, 2L, 128L, 2L, 1);
+
+ // Verifies that onStatsUpdated updates the stats accordingly.
+ NetworkStats stats = mSession.getSummaryForAllUid(
+ sTemplateImsi1, Long.MIN_VALUE, Long.MAX_VALUE, true);
+ assertEquals(1, stats.size());
+ assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO,
+ DEFAULT_NETWORK_YES, 128L, 2L, 128L, 2L, 1L);
+
+ stats = mSession.getSummaryForAllUid(
+ sTemplateImsi2, Long.MIN_VALUE, Long.MAX_VALUE, true);
+ assertEquals(1, stats.size());
+ assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, TAG_NONE, METERED_YES, ROAMING_NO,
+ DEFAULT_NETWORK_YES, 64L, 1L, 64L, 1L, 1L);
+
+ // Verifies that unregister the callback will remove the provider from service.
+ cb.unregister();
+ forcePollAndWaitForIdle();
+ provider.assertNoCallback();
+ }
+
+ @Test
public void testStatsProviderSetAlert() throws Exception {
// Pretend that network comes online.
expectDefaultSettings();
@@ -1616,6 +1688,20 @@ public class NetworkStatsServiceTest extends NetworkStatsBaseTest {
TYPE_MOBILE);
}
+ private static NetworkStateSnapshot buildImsState(
+ String subscriberId, int subId, String ifaceName) {
+ final LinkProperties prop = new LinkProperties();
+ prop.setInterfaceName(ifaceName);
+ final NetworkCapabilities capabilities = new NetworkCapabilities();
+ capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED, true);
+ capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING, true);
+ capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_IMS, true);
+ capabilities.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
+ capabilities.setNetworkSpecifier(new TelephonyNetworkSpecifier(subId));
+ return new NetworkStateSnapshot(
+ MOBILE_NETWORK, capabilities, prop, subscriberId, TYPE_MOBILE);
+ }
+
private long getElapsedRealtime() {
return mElapsedRealtime;
}
diff --git a/tests/vcn/java/android/net/vcn/VcnManagerTest.java b/tests/vcn/java/android/net/vcn/VcnManagerTest.java
index 7515971b8307..516c206672d2 100644
--- a/tests/vcn/java/android/net/vcn/VcnManagerTest.java
+++ b/tests/vcn/java/android/net/vcn/VcnManagerTest.java
@@ -204,7 +204,7 @@ public class VcnManagerTest {
new VcnStatusCallbackBinder(INLINE_EXECUTOR, mMockStatusCallback);
cbBinder.onVcnStatusChanged(VCN_STATUS_CODE_ACTIVE);
- verify(mMockStatusCallback).onVcnStatusChanged(VCN_STATUS_CODE_ACTIVE);
+ verify(mMockStatusCallback).onStatusChanged(VCN_STATUS_CODE_ACTIVE);
cbBinder.onGatewayConnectionError(
UNDERLYING_NETWORK_CAPABILITIES,
diff --git a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
index a9d5822be226..f15d4204d125 100644
--- a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
+++ b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
@@ -19,6 +19,8 @@ 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 android.telephony.TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
+import static android.telephony.TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS;
import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot;
import static com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionTrackerCallback;
@@ -47,7 +49,9 @@ import static org.mockito.Mockito.when;
import android.annotation.NonNull;
import android.app.AppOpsManager;
+import android.content.BroadcastReceiver;
import android.content.Context;
+import android.content.Intent;
import android.net.ConnectivityManager;
import android.net.LinkProperties;
import android.net.NetworkCapabilities;
@@ -238,9 +242,14 @@ public class VcnManagementServiceTest {
doReturn(Collections.singletonList(TEST_SUBSCRIPTION_INFO))
.when(mSubMgr)
.getSubscriptionsInGroup(any());
- doReturn(isPrivileged)
+ doReturn(mTelMgr)
.when(mTelMgr)
- .hasCarrierPrivileges(eq(TEST_SUBSCRIPTION_INFO.getSubscriptionId()));
+ .createForSubscriptionId(eq(TEST_SUBSCRIPTION_INFO.getSubscriptionId()));
+ doReturn(isPrivileged
+ ? CARRIER_PRIVILEGE_STATUS_HAS_ACCESS
+ : CARRIER_PRIVILEGE_STATUS_NO_ACCESS)
+ .when(mTelMgr)
+ .checkCarrierPrivilegesForPackage(eq(TEST_PACKAGE_NAME));
}
@Test
@@ -329,6 +338,13 @@ public class VcnManagementServiceTest {
return captor.getValue();
}
+ private BroadcastReceiver getPackageChangeReceiver() {
+ final ArgumentCaptor<BroadcastReceiver> captor =
+ ArgumentCaptor.forClass(BroadcastReceiver.class);
+ verify(mMockContext).registerReceiver(captor.capture(), any(), any(), any());
+ return captor.getValue();
+ }
+
private Vcn startAndGetVcnInstance(ParcelUuid uuid) {
mVcnMgmtSvc.setVcnConfig(uuid, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
return mVcnMgmtSvc.getAllVcns().get(uuid);
@@ -391,7 +407,7 @@ public class VcnManagementServiceTest {
mTestLooper.moveTimeForward(
VcnManagementService.CARRIER_PRIVILEGES_LOST_TEARDOWN_DELAY_MS / 2);
mTestLooper.dispatchAll();
- mVcnMgmtSvc.clearVcnConfig(TEST_UUID_2);
+ mVcnMgmtSvc.clearVcnConfig(TEST_UUID_2, TEST_PACKAGE_NAME);
final Vcn newInstance = startAndGetVcnInstance(TEST_UUID_2);
// Verify that new instance was different, and the old one was torn down
@@ -405,6 +421,42 @@ public class VcnManagementServiceTest {
}
@Test
+ public void testPackageChangeListenerRegistered() throws Exception {
+ verify(mMockContext).registerReceiver(any(BroadcastReceiver.class), argThat(filter -> {
+ return filter.hasAction(Intent.ACTION_PACKAGE_ADDED)
+ && filter.hasAction(Intent.ACTION_PACKAGE_REPLACED)
+ && filter.hasAction(Intent.ACTION_PACKAGE_REMOVED);
+ }), any(), any());
+ }
+
+ @Test
+ public void testPackageChangeListener_packageAdded() throws Exception {
+ final BroadcastReceiver receiver = getPackageChangeReceiver();
+
+ verify(mMockContext).registerReceiver(any(), argThat(filter -> {
+ return filter.hasAction(Intent.ACTION_PACKAGE_ADDED)
+ && filter.hasAction(Intent.ACTION_PACKAGE_REPLACED)
+ && filter.hasAction(Intent.ACTION_PACKAGE_REMOVED);
+ }), any(), any());
+
+ receiver.onReceive(mMockContext, new Intent(Intent.ACTION_PACKAGE_ADDED));
+ verify(mSubscriptionTracker).handleSubscriptionsChanged();
+ }
+
+ @Test
+ public void testPackageChangeListener_packageRemoved() throws Exception {
+ final BroadcastReceiver receiver = getPackageChangeReceiver();
+
+ verify(mMockContext).registerReceiver(any(), argThat(filter -> {
+ return filter.hasAction(Intent.ACTION_PACKAGE_REMOVED)
+ && filter.hasAction(Intent.ACTION_PACKAGE_REMOVED);
+ }), any(), any());
+
+ receiver.onReceive(mMockContext, new Intent(Intent.ACTION_PACKAGE_REMOVED));
+ verify(mSubscriptionTracker).handleSubscriptionsChanged();
+ }
+
+ @Test
public void testSetVcnConfigRequiresNonSystemServer() throws Exception {
doReturn(Process.SYSTEM_UID).when(mMockDeps).getBinderCallingUid();
@@ -492,7 +544,7 @@ public class VcnManagementServiceTest {
doReturn(Process.SYSTEM_UID).when(mMockDeps).getBinderCallingUid();
try {
- mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1);
+ mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1, TEST_PACKAGE_NAME);
fail("Expected IllegalStateException exception for system server");
} catch (IllegalStateException expected) {
}
@@ -505,7 +557,7 @@ public class VcnManagementServiceTest {
.getBinderCallingUid();
try {
- mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1);
+ mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1, TEST_PACKAGE_NAME);
fail("Expected security exception for non system user");
} catch (SecurityException expected) {
}
@@ -516,15 +568,24 @@ public class VcnManagementServiceTest {
setupMockedCarrierPrivilege(false);
try {
- mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1);
+ mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1, TEST_PACKAGE_NAME);
fail("Expected security exception for missing carrier privileges");
} catch (SecurityException expected) {
}
}
@Test
+ public void testClearVcnConfigMismatchedPackages() throws Exception {
+ try {
+ mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1, "IncorrectPackage");
+ fail("Expected security exception due to mismatched packages");
+ } catch (SecurityException expected) {
+ }
+ }
+
+ @Test
public void testClearVcnConfig() throws Exception {
- mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1);
+ mVcnMgmtSvc.clearVcnConfig(TEST_UUID_1, TEST_PACKAGE_NAME);
assertTrue(mVcnMgmtSvc.getConfigs().isEmpty());
verify(mConfigReadWriteHelper).writeToDisk(any(PersistableBundle.class));
}
@@ -535,7 +596,7 @@ public class VcnManagementServiceTest {
mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_2, mMockStatusCallback, TEST_PACKAGE_NAME);
verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_ACTIVE);
- mVcnMgmtSvc.clearVcnConfig(TEST_UUID_2);
+ mVcnMgmtSvc.clearVcnConfig(TEST_UUID_2, TEST_PACKAGE_NAME);
verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_NOT_CONFIGURED);
}
@@ -564,7 +625,7 @@ public class VcnManagementServiceTest {
verify(vcnInstance).updateConfig(TEST_VCN_CONFIG);
// Verify Vcn is stopped if it was already started
- mVcnMgmtSvc.clearVcnConfig(TEST_UUID_2);
+ mVcnMgmtSvc.clearVcnConfig(TEST_UUID_2, TEST_PACKAGE_NAME);
verify(vcnInstance).teardownAsynchronously();
}
@@ -781,7 +842,7 @@ public class VcnManagementServiceTest {
mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
- mVcnMgmtSvc.clearVcnConfig(TEST_UUID_2);
+ mVcnMgmtSvc.clearVcnConfig(TEST_UUID_2, TEST_PACKAGE_NAME);
verify(mMockPolicyListener).onPolicyChanged();
}
diff --git a/tests/vcn/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java b/tests/vcn/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java
index 1ef1a61f17ea..631c862d2bfd 100644
--- a/tests/vcn/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java
+++ b/tests/vcn/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java
@@ -328,7 +328,7 @@ public class UnderlyingNetworkTrackerTest {
public void testRecordTrackerCallbackNotifiedForNetworkSuspended() {
RouteSelectionCallback cb = verifyRegistrationOnAvailableAndGetCallback();
- cb.onNetworkSuspended(mNetwork);
+ cb.onCapabilitiesChanged(mNetwork, SUSPENDED_NETWORK_CAPABILITIES);
UnderlyingNetworkRecord expectedRecord =
new UnderlyingNetworkRecord(
@@ -336,7 +336,11 @@ public class UnderlyingNetworkTrackerTest {
SUSPENDED_NETWORK_CAPABILITIES,
INITIAL_LINK_PROPERTIES,
false /* isBlocked */);
- verify(mNetworkTrackerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
+ verify(mNetworkTrackerCb, times(1)).onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
+ // onSelectedUnderlyingNetworkChanged() won't be fired twice if network capabilities doesn't
+ // change.
+ cb.onCapabilitiesChanged(mNetwork, SUSPENDED_NETWORK_CAPABILITIES);
+ verify(mNetworkTrackerCb, times(1)).onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
}
@Test
@@ -344,7 +348,7 @@ public class UnderlyingNetworkTrackerTest {
RouteSelectionCallback cb =
verifyRegistrationOnAvailableAndGetCallback(SUSPENDED_NETWORK_CAPABILITIES);
- cb.onNetworkResumed(mNetwork);
+ cb.onCapabilitiesChanged(mNetwork, INITIAL_NETWORK_CAPABILITIES);
UnderlyingNetworkRecord expectedRecord =
new UnderlyingNetworkRecord(
@@ -352,7 +356,11 @@ public class UnderlyingNetworkTrackerTest {
INITIAL_NETWORK_CAPABILITIES,
INITIAL_LINK_PROPERTIES,
false /* isBlocked */);
- verify(mNetworkTrackerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
+ verify(mNetworkTrackerCb, times(1)).onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
+ // onSelectedUnderlyingNetworkChanged() won't be fired twice if network capabilities doesn't
+ // change.
+ cb.onCapabilitiesChanged(mNetwork, INITIAL_NETWORK_CAPABILITIES);
+ verify(mNetworkTrackerCb, times(1)).onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
}
@Test
diff --git a/tests/vcn/java/com/android/server/vcn/VcnTest.java b/tests/vcn/java/com/android/server/vcn/VcnTest.java
index 4fa63d4ff640..c853fc50fdf7 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnTest.java
@@ -29,6 +29,7 @@ import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -139,8 +140,7 @@ public class VcnTest {
mTestLooper.dispatchAll();
}
- @Test
- public void testSubscriptionSnapshotUpdatesVcnGatewayConnections() {
+ private void verifyUpdateSubscriptionSnapshotNotifiesConnectionGateways(boolean isActive) {
final NetworkRequestListener requestListener = verifyAndGetRequestListener();
startVcnGatewayWithCapabilities(requestListener, TEST_CAPS[0]);
@@ -150,14 +150,27 @@ public class VcnTest {
final TelephonySubscriptionSnapshot updatedSnapshot =
mock(TelephonySubscriptionSnapshot.class);
+ mVcn.setIsActive(isActive);
+
mVcn.updateSubscriptionSnapshot(updatedSnapshot);
mTestLooper.dispatchAll();
for (final VcnGatewayConnection gateway : gatewayConnections) {
- verify(gateway).updateSubscriptionSnapshot(eq(updatedSnapshot));
+ verify(gateway, isActive ? times(1) : never())
+ .updateSubscriptionSnapshot(eq(updatedSnapshot));
}
}
+ @Test
+ public void testSubscriptionSnapshotUpdatesVcnGatewayConnections() {
+ verifyUpdateSubscriptionSnapshotNotifiesConnectionGateways(true /* isActive */);
+ }
+
+ @Test
+ public void testSubscriptionSnapshotUpdatesVcnGatewayConnectionsWhileInactive() {
+ verifyUpdateSubscriptionSnapshotNotifiesConnectionGateways(false /* isActive */);
+ }
+
private void triggerVcnRequestListeners(NetworkRequestListener requestListener) {
for (final int[] caps : TEST_CAPS) {
startVcnGatewayWithCapabilities(requestListener, caps);
@@ -187,7 +200,6 @@ public class VcnTest {
NetworkRequestListener requestListener,
Set<VcnGatewayConnection> expectedGatewaysTornDown) {
assertFalse(mVcn.isActive());
- assertTrue(mVcn.getVcnGatewayConnections().isEmpty());
for (final VcnGatewayConnection gatewayConnection : expectedGatewaysTornDown) {
verify(gatewayConnection).teardownAsynchronously();
}
@@ -238,6 +250,51 @@ public class VcnTest {
}
@Test
+ public void testGatewayQuitWhileInactive() {
+ final NetworkRequestListener requestListener = verifyAndGetRequestListener();
+ final Set<VcnGatewayConnection> gatewayConnections =
+ new ArraySet<>(startGatewaysAndGetGatewayConnections(requestListener));
+
+ mVcn.teardownAsynchronously();
+ mTestLooper.dispatchAll();
+
+ final VcnGatewayStatusCallback statusCallback = mGatewayStatusCallbackCaptor.getValue();
+ statusCallback.onQuit();
+ mTestLooper.dispatchAll();
+
+ // Verify that the VCN requests the networkRequests be resent
+ assertEquals(1, mVcn.getVcnGatewayConnections().size());
+ verify(mVcnNetworkProvider, never()).resendAllRequests(requestListener);
+ }
+
+ @Test
+ public void testUpdateConfigReevaluatesGatewayConnections() {
+ final NetworkRequestListener requestListener = verifyAndGetRequestListener();
+ startGatewaysAndGetGatewayConnections(requestListener);
+ assertEquals(2, mVcn.getVcnGatewayConnectionConfigMap().size());
+
+ // Create VcnConfig with only one VcnGatewayConnectionConfig so a gateway connection is torn
+ // down
+ final VcnGatewayConnectionConfig activeConfig =
+ VcnGatewayConnectionConfigTest.buildTestConfigWithExposedCaps(TEST_CAPS[0]);
+ final VcnGatewayConnectionConfig removedConfig =
+ VcnGatewayConnectionConfigTest.buildTestConfigWithExposedCaps(TEST_CAPS[1]);
+ final VcnConfig updatedConfig =
+ new VcnConfig.Builder(mContext).addGatewayConnectionConfig(activeConfig).build();
+
+ mVcn.updateConfig(updatedConfig);
+ mTestLooper.dispatchAll();
+
+ final VcnGatewayConnection activeGatewayConnection =
+ mVcn.getVcnGatewayConnectionConfigMap().get(activeConfig);
+ final VcnGatewayConnection removedGatewayConnection =
+ mVcn.getVcnGatewayConnectionConfigMap().get(removedConfig);
+ verify(activeGatewayConnection, never()).teardownAsynchronously();
+ verify(removedGatewayConnection).teardownAsynchronously();
+ verify(mVcnNetworkProvider).resendAllRequests(requestListener);
+ }
+
+ @Test
public void testUpdateConfigExitsSafeMode() {
final NetworkRequestListener requestListener = verifyAndGetRequestListener();
final Set<VcnGatewayConnection> gatewayConnections =
@@ -261,8 +318,8 @@ public class VcnTest {
verify(mVcnNetworkProvider, times(2)).registerListener(eq(requestListener));
assertTrue(mVcn.isActive());
for (final int[] caps : TEST_CAPS) {
- // Expect each gateway connection created on initial startup, and again with new configs
- verify(mDeps, times(2))
+ // Expect each gateway connection created only on initial startup
+ verify(mDeps)
.newVcnGatewayConnection(
eq(mVcnContext),
eq(TEST_SUB_GROUP),
@@ -271,4 +328,14 @@ public class VcnTest {
any());
}
}
+
+ @Test
+ public void testIgnoreNetworkRequestWhileInactive() {
+ mVcn.setIsActive(false /* isActive */);
+
+ final NetworkRequestListener requestListener = verifyAndGetRequestListener();
+ triggerVcnRequestListeners(requestListener);
+
+ verify(mDeps, never()).newVcnGatewayConnection(any(), any(), any(), any(), any());
+ }
}