diff options
115 files changed, 3508 insertions, 1297 deletions
diff --git a/Android.bp b/Android.bp index 470932378383..afd8bfd26ac4 100644 --- a/Android.bp +++ b/Android.bp @@ -64,278 +64,13 @@ license { } filegroup { - name: "framework-core-sources", - srcs: [ - "core/java/**/*.java", - "core/java/**/*.aidl", - ], - path: "core/java", -} - -// These are subset of framework-core-sources that are needed by the -// android.test.mock library. The implementation of android.test.mock references -// private members of various components to allow mocking of classes that cannot -// be mocked without access to those internal implementation details. -filegroup { - name: "framework-core-sources-for-test-mock", - srcs: [ - "core/java/android/accounts/AccountManagerCallback.java", - "core/java/android/accounts/AccountManagerFuture.java", - "core/java/android/accounts/AccountManager.java", - "core/java/android/accounts/AccountsException.java", - "core/java/android/accounts/AuthenticatorException.java", - "core/java/android/accounts/OperationCanceledException.java", - "core/java/android/annotation/AnimatorRes.java", - "core/java/android/annotation/AnimRes.java", - "core/java/android/annotation/AnyRes.java", - "core/java/android/annotation/ArrayRes.java", - "core/java/android/annotation/AttrRes.java", - "core/java/android/annotation/BoolRes.java", - "core/java/android/annotation/BroadcastBehavior.java", - "core/java/android/annotation/CallbackExecutor.java", - "core/java/android/annotation/CallSuper.java", - "core/java/android/annotation/CheckResult.java", - "core/java/android/annotation/ColorInt.java", - "core/java/android/annotation/ColorRes.java", - "core/java/android/annotation/DimenRes.java", - "core/java/android/annotation/DrawableRes.java", - "core/java/android/annotation/FontRes.java", - "core/java/android/annotation/FractionRes.java", - "core/java/android/annotation/IntDef.java", - "core/java/android/annotation/IntegerRes.java", - "core/java/android/annotation/IntRange.java", - "core/java/android/annotation/LayoutRes.java", - "core/java/android/annotation/NonNull.java", - "core/java/android/annotation/Nullable.java", - "core/java/android/annotation/PluralsRes.java", - "core/java/android/annotation/RawRes.java", - "core/java/android/annotation/RequiresPermission.java", - "core/java/android/annotation/SdkConstant.java", - "core/java/android/annotation/Size.java", - "core/java/android/annotation/StringDef.java", - "core/java/android/annotation/StringRes.java", - "core/java/android/annotation/StyleableRes.java", - "core/java/android/annotation/StyleRes.java", - "core/java/android/annotation/SuppressLint.java", - "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/XmlRes.java", - "core/java/android/app/Application.java", - "core/java/android/app/IApplicationThread.aidl", - "core/java/android/app/IServiceConnection.aidl", - "core/java/android/app/PackageDeleteObserver.java", - "core/java/android/content/ComponentCallbacks2.java", - "core/java/android/content/ComponentCallbacks.java", - "core/java/android/content/ContentInterface.java", - "core/java/android/content/ContentProvider.java", - "core/java/android/content/ContentProviderNative.java", - "core/java/android/content/ContentResolver.java", - "core/java/android/content/Context.java", - "core/java/android/content/ContextWrapper.java", - "core/java/android/content/DialogInterface.java", - "core/java/android/content/IContentProvider.java", - "core/java/android/content/Intent.java", - "core/java/android/content/IntentSender.java", - "core/java/android/content/OperationApplicationException.java", - "core/java/android/content/pm/ActivityInfo.java", - "core/java/android/content/pm/ApplicationInfo.java", - "core/java/android/content/pm/InstantAppInfo.java", - "core/java/android/content/pm/IPackageDataObserver.aidl", - "core/java/android/content/pm/KeySet.java", - "core/java/android/content/pm/PackageManager.java", - "core/java/android/content/pm/VerifierDeviceIdentity.java", - "core/java/android/content/res/Resources.java", - "core/java/android/database/CrossProcessCursor.java", - "core/java/android/database/CrossProcessCursorWrapper.java", - "core/java/android/database/Cursor.java", - "core/java/android/database/CursorWrapper.java", - "core/java/android/os/Binder.java", - "core/java/android/os/Bundle.java", - "core/java/android/os/IBinder.java", - "core/java/android/os/IInterface.java", - "core/java/android/os/Parcelable.java", - "core/java/android/os/ParcelFileDescriptor.java", - "core/java/android/os/RemoteException.java", - "core/java/android/os/storage/VolumeInfo.java", - "core/java/android/util/AndroidException.java", - "core/java/android/view/DisplayAdjustments.java", - "core/java/android/view/ViewDebug.java", - "core/java/com/android/internal/annotations/VisibleForTesting.java", - ], - path: "core/java", - visibility: ["//frameworks/base/test-mock"], -} - -filegroup { - name: "framework-drm-sources", - srcs: [ - "drm/java/**/*.java", - ], - path: "drm/java", -} - -filegroup { - name: "framework-graphics-sources", - srcs: [ - "graphics/java/**/*.java", - "graphics/java/**/*.aidl", - ], - path: "graphics/java", -} - -filegroup { - name: "framework-identity-sources", - srcs: [ - "identity/java/**/*.java", - ], - path: "identity/java", -} - -filegroup { - name: "framework-keystore-sources", - srcs: [ - "keystore/java/**/*.java", - "keystore/java/**/*.aidl", - ], - path: "keystore/java", -} - -filegroup { - name: "framework-location-sources", - srcs: [ - "location/java/**/*.java", - "location/java/**/*.aidl", - ], - path: "location/java", -} - -filegroup { - name: "framework-lowpan-sources", - srcs: [ - "lowpan/java/**/*.java", - "lowpan/java/**/*.aidl", - ], - path: "lowpan/java", -} - -filegroup { - name: "framework-media-sources", - srcs: [ - "media/java/**/*.java", - "media/java/**/*.aidl", - ], - path: "media/java", -} - -filegroup { - name: "framework-mca-effect-sources", - srcs: [ - "media/mca/effect/java/**/*.java", - ], - path: "media/mca/effect/java", -} - -filegroup { - name: "framework-mca-filterfw-sources", - srcs: [ - "media/mca/filterfw/java/**/*.java", - ], - path: "media/mca/filterfw/java", -} - -filegroup { - name: "framework-mca-filterpacks-sources", - srcs: [ - "media/mca/filterpacks/java/**/*.java", - ], - path: "media/mca/filterpacks/java", -} - -filegroup { - name: "framework-mime-sources", - srcs: [ - "mime/java/**/*.java", - ], - path: "mime/java", -} - -filegroup { - name: "framework-opengl-sources", - srcs: [ - "opengl/java/**/*.java", - ], - path: "opengl/java", -} - -filegroup { - name: "framework-rs-sources", - srcs: [ - "rs/java/**/*.java", - ], - path: "rs/java", -} - -filegroup { - name: "framework-sax-sources", - srcs: [ - "sax/java/**/*.java", - ], - path: "sax/java", -} - -filegroup { - name: "framework-telecomm-sources", - srcs: [ - "telecomm/java/**/*.java", - "telecomm/java/**/*.aidl", - ], - path: "telecomm/java", -} - -filegroup { - name: "framework-telephony-sources", - srcs: [ - "telephony/java/**/*.java", - "telephony/java/**/*.aidl", - ], - path: "telephony/java", -} - -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", - out: ["com/android/internal/telephony/TelephonyCommonStatsLog.java"], -} - -filegroup { - name: "framework-telephony-common-sources", - srcs: [ - "telephony/common/**/*.java", - ":statslog-telephony-common-java-gen", - ], -} - -filegroup { - name: "framework-mms-sources", - srcs: [ - "mms/java/**/*.java", - "mms/java/**/*.aidl", - ], - path: "mms/java", -} - -filegroup { name: "framework-non-updatable-sources", srcs: [ // Java/AIDL sources under frameworks/base ":framework-blobstore-sources", ":framework-core-sources", ":framework-drm-sources", - ":framework-graphics-sources", + ":framework-graphics-nonupdatable-sources", ":framework-jobscheduler-sources", // jobscheduler is not a module for R ":framework-keystore-sources", ":framework-identity-sources", @@ -383,6 +118,7 @@ filegroup { ":libbluetooth-binder-aidl", ":libcamera_client_aidl", ":libcamera_client_framework_aidl", + ":packagemanager_aidl", ":libupdate_engine_aidl", ":resourcemanager_aidl", ":storaged_aidl", @@ -398,22 +134,6 @@ filegroup { ], } -filegroup { - name: "framework-updatable-sources", - srcs: [ - ":framework-connectivity-sources", - ":framework-mediaprovider-sources", - ":framework-permission-sources", - ":framework-sdkextensions-sources", - ":framework-statsd-sources", - ":framework-tethering-srcs", - ":framework-wifi-updatable-sources", - ":ike-srcs", - ":updatable-media-srcs", - ], - visibility: ["//visibility:private"], -} - java_library { name: "framework-updatable-stubs-module_libs_api", static_libs: [ @@ -453,15 +173,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 { @@ -763,13 +474,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", @@ -778,10 +497,11 @@ 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", ], } @@ -795,7 +515,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", @@ -1206,36 +925,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). @@ -1357,6 +1046,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..d3bef7f9046b 100644 --- a/ApiDocs.bp +++ b/ApiDocs.bp @@ -58,16 +58,24 @@ framework_docs_only_libs = [ stubs_defaults { name: "framework-doc-stubs-default", srcs: [ - ":framework-mime-sources", - ":framework-non-updatable-sources", - ":framework-updatable-sources", - "core/java/**/*.logtags", - "test-base/src/**/*.java", - ":opt-telephony-srcs", - ":opt-net-voip-srcs", + ":framework-non-updatable-stub-sources", + + // Module sources ":art.module.public.api{.public.stubs.source}", ":conscrypt.module.public.api{.public.stubs.source}", + ":framework-connectivity-sources", + ":framework-mediaprovider-sources", + ":framework-permission-sources", + ":framework-sdkextensions-sources", + ":framework-statsd-sources", + ":framework-tethering-srcs", + ":framework-wifi-updatable-sources", ":i18n.module.public.api{.public.stubs.source}", + ":ike-srcs", + ":updatable-media-srcs", + + // No longer part of the stubs, but are included in the docs. + "test-base/src/**/*.java", "test-mock/src/**/*.java", "test-runner/src/**/*.java", ], 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/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/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 ef067858c530..bd6b5e877726 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -40412,6 +40412,7 @@ package android.telephony { public final class PreciseDataConnectionState implements android.os.Parcelable { method public int describeContents(); method @Nullable public android.telephony.data.ApnSetting getApnSetting(); + method public int getId(); method public int getLastCauseCode(); method @Nullable public android.net.LinkProperties getLinkProperties(); method public int getNetworkType(); diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt index ee53be559d3e..3b7a617f2e16 100644 --- a/core/api/module-lib-current.txt +++ b/core/api/module-lib-current.txt @@ -50,7 +50,6 @@ 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); diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 4676523bbd6c..2928a0c59e8a 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -155,6 +155,7 @@ 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"; @@ -6442,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 } @@ -6723,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 } @@ -9431,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"; } @@ -9785,7 +9795,6 @@ package android.telephony { method @Deprecated public int getDataConnectionApnTypeBitMask(); method @Deprecated public int getDataConnectionFailCause(); method @Deprecated public int getDataConnectionState(); - method public int getId(); } public final class PreciseDisconnectCause { @@ -12066,13 +12075,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 { @@ -12284,7 +12293,7 @@ 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.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); diff --git a/core/api/test-current.txt b/core/api/test-current.txt index 1d094c3d7f40..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 } diff --git a/core/java/Android.bp b/core/java/Android.bp index 2fdf9c146ff6..919f1e2e85fb 100644 --- a/core/java/Android.bp +++ b/core/java/Android.bp @@ -10,6 +10,15 @@ package { } filegroup { + name: "framework-core-sources", + srcs: [ + "**/*.java", + "**/*.aidl", + ], + visibility: ["//frameworks/base"], +} + +filegroup { name: "IKeyAttestationApplicationIdProvider.aidl", srcs: ["android/security/keymaster/IKeyAttestationApplicationIdProvider.aidl"], } @@ -23,3 +32,98 @@ filegroup { name: "ITracingServiceProxy.aidl", srcs: ["android/tracing/ITracingServiceProxy.aidl"], } + +// These are subset of framework-core-sources that are needed by the +// android.test.mock library. The implementation of android.test.mock references +// private members of various components to allow mocking of classes that cannot +// be mocked without access to those internal implementation details. +filegroup { + name: "framework-core-sources-for-test-mock", + srcs: [ + "android/accounts/AccountManagerCallback.java", + "android/accounts/AccountManagerFuture.java", + "android/accounts/AccountManager.java", + "android/accounts/AccountsException.java", + "android/accounts/AuthenticatorException.java", + "android/accounts/OperationCanceledException.java", + "android/annotation/AnimatorRes.java", + "android/annotation/AnimRes.java", + "android/annotation/AnyRes.java", + "android/annotation/ArrayRes.java", + "android/annotation/AttrRes.java", + "android/annotation/BoolRes.java", + "android/annotation/BroadcastBehavior.java", + "android/annotation/CallbackExecutor.java", + "android/annotation/CallSuper.java", + "android/annotation/CheckResult.java", + "android/annotation/ColorInt.java", + "android/annotation/ColorRes.java", + "android/annotation/DimenRes.java", + "android/annotation/DrawableRes.java", + "android/annotation/FontRes.java", + "android/annotation/FractionRes.java", + "android/annotation/IntDef.java", + "android/annotation/IntegerRes.java", + "android/annotation/IntRange.java", + "android/annotation/LayoutRes.java", + "android/annotation/NonNull.java", + "android/annotation/Nullable.java", + "android/annotation/PluralsRes.java", + "android/annotation/RawRes.java", + "android/annotation/RequiresPermission.java", + "android/annotation/SdkConstant.java", + "android/annotation/Size.java", + "android/annotation/StringDef.java", + "android/annotation/StringRes.java", + "android/annotation/StyleableRes.java", + "android/annotation/StyleRes.java", + "android/annotation/SuppressLint.java", + "android/annotation/SystemApi.java", + "android/annotation/SystemService.java", + "android/annotation/TestApi.java", + "android/annotation/UserIdInt.java", + "android/annotation/XmlRes.java", + "android/app/Application.java", + "android/app/IApplicationThread.aidl", + "android/app/IServiceConnection.aidl", + "android/app/PackageDeleteObserver.java", + "android/content/ComponentCallbacks2.java", + "android/content/ComponentCallbacks.java", + "android/content/ContentInterface.java", + "android/content/ContentProvider.java", + "android/content/ContentProviderNative.java", + "android/content/ContentResolver.java", + "android/content/Context.java", + "android/content/ContextWrapper.java", + "android/content/DialogInterface.java", + "android/content/IContentProvider.java", + "android/content/Intent.java", + "android/content/IntentSender.java", + "android/content/OperationApplicationException.java", + "android/content/pm/ActivityInfo.java", + "android/content/pm/ApplicationInfo.java", + "android/content/pm/InstantAppInfo.java", + "android/content/pm/IPackageDataObserver.aidl", + "android/content/pm/KeySet.java", + "android/content/pm/PackageManager.java", + "android/content/pm/VerifierDeviceIdentity.java", + "android/content/res/Resources.java", + "android/database/CrossProcessCursor.java", + "android/database/CrossProcessCursorWrapper.java", + "android/database/Cursor.java", + "android/database/CursorWrapper.java", + "android/os/Binder.java", + "android/os/Bundle.java", + "android/os/IBinder.java", + "android/os/IInterface.java", + "android/os/Parcelable.java", + "android/os/ParcelFileDescriptor.java", + "android/os/RemoteException.java", + "android/os/storage/VolumeInfo.java", + "android/util/AndroidException.java", + "android/view/DisplayAdjustments.java", + "android/view/ViewDebug.java", + "com/android/internal/annotations/VisibleForTesting.java", + ], + visibility: ["//frameworks/base/test-mock"], +} 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/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/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java index 40fbfbb51424..68606ec90dc9 100644 --- a/core/java/android/net/NetworkPolicyManager.java +++ b/core/java/android/net/NetworkPolicyManager.java @@ -18,7 +18,6 @@ package android.net; import static android.app.ActivityManager.procStateToString; import static android.content.pm.PackageManager.GET_SIGNATURES; -import static android.net.ConnectivityManager.BLOCKED_REASON_NONE; import android.annotation.IntDef; import android.annotation.NonNull; @@ -204,9 +203,6 @@ public class NetworkPolicyManager { }) public @interface SubscriptionOverrideMask {} - /** @hide */ - public static final int BLOCKED_METERED_REASON_MASK = 0xffff0000; - /** * Flag to indicate that app is not exempt from any network restrictions. * @@ -789,36 +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 ConnectivityManager#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(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 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/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/Build.java b/core/java/android/os/Build.java index 189a8ac55a10..03caafda2b13 100755 --- a/core/java/android/os/Build.java +++ b/core/java/android/os/Build.java @@ -115,15 +115,20 @@ public class Build { public static final String HARDWARE = getString("ro.hardware"); /** - * The SKU of the hardware (from the kernel command line). The SKU is reported by the bootloader - * to configure system software features. + * The SKU of the hardware (from the kernel command line). + * + * <p>The SKU is reported by the bootloader to configure system software features. + * If no value is supplied by the bootloader, this is reported as {@link #UNKNOWN}. + */ @NonNull public static final String SKU = getString("ro.boot.hardware.sku"); /** - * The SKU of the device as set by the original design manufacturer (ODM). This is a - * runtime-initialized property set during startup to configure device services. + * The SKU of the device as set by the original design manufacturer (ODM). + * + * <p>This is a runtime-initialized property set during startup to configure device + * services. If no value is set, this is reported as {@link #UNKNOWN}. * * <p>The ODM SKU may have multiple variants for the same system SKU in case a manufacturer * produces variants of the same design. For example, the same build may be released with 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/speech/OWNERS b/core/java/android/speech/OWNERS new file mode 100644 index 000000000000..32f482264103 --- /dev/null +++ b/core/java/android/speech/OWNERS @@ -0,0 +1,3 @@ +volnov@google.com +eugeniom@google.com +schfan@google.com diff --git a/core/java/android/speech/SpeechRecognizer.java b/core/java/android/speech/SpeechRecognizer.java index aea94bfb1bbb..b29598e1bb56 100644 --- a/core/java/android/speech/SpeechRecognizer.java +++ b/core/java/android/speech/SpeechRecognizer.java @@ -205,6 +205,17 @@ public class SpeechRecognizer { * command to the created {@code SpeechRecognizer}, otherwise no notifications will be * received. * + * <p>For apps targeting Android 11 (API level 30) interaction with a speech recognition + * service requires <queries> element to be added to the manifest file: + * <pre>{@code + * <queries> + * <intent> + * <action + * android:name="android.speech.RecognitionService" /> + * </intent> + * </queries> + * }</pre> + * * @param context in which to create {@code SpeechRecognizer} * @return a new {@code SpeechRecognizer} */ @@ -222,7 +233,18 @@ public class SpeechRecognizer { * {@link SpeechRecognizer} to. Normally you would not use this; use * {@link #createSpeechRecognizer(Context)} instead to use the system default recognition * service. - * + * + * <p>For apps targeting Android 11 (API level 30) interaction with a speech recognition + * service requires <queries> element to be added to the manifest file: + * <pre>{@code + * <queries> + * <intent> + * <action + * android:name="android.speech.RecognitionService" /> + * </intent> + * </queries> + * }</pre> + * * @param context in which to create {@code SpeechRecognizer} * @param serviceComponent the {@link ComponentName} of a specific service to direct this * {@code SpeechRecognizer} to diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index a785a1ab9f0e..51396dbb8204 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -4679,6 +4679,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te 0, Integer.MAX_VALUE, 0, Integer.MAX_VALUE); mTouchMode = TOUCH_MODE_FLING; mSuppressIdleStateChangeCall = false; + removeCallbacks(this); postOnAnimation(this); if (PROFILE_FLINGING) { 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/OWNERS b/core/jni/OWNERS index c0c4b7054674..07fb72905758 100644 --- a/core/jni/OWNERS +++ b/core/jni/OWNERS @@ -50,7 +50,6 @@ per-file fd_utils.* = file:/ZYGOTE_OWNERS per-file Android.bp = file:platform/build/soong:/OWNERS per-file android_animation_* = file:/core/java/android/animation/OWNERS per-file android_app_admin_* = file:/core/java/android/app/admin/OWNERS -per-file android_graphics_* = file:/graphics/java/android/graphics/OWNERS per-file android_hardware_Usb* = file:/services/usb/OWNERS per-file android_hardware_display_* = file:/core/java/android/hardware/display/OWNERS per-file android_hardware_input_* = file:/core/java/android/hardware/input/OWNERS @@ -63,3 +62,11 @@ per-file android_se_* = file:/core/java/android/se/OWNERS per-file android_security_* = file:/core/java/android/security/OWNERS per-file android_view_* = file:/core/java/android/view/OWNERS per-file com_android_internal_net_* = file:/services/core/java/com/android/server/net/OWNERS + +### Graphics ### +per-file android_graphics_* = file:/graphics/java/android/graphics/OWNERS +# These are highly common-use files +per-file Android.bp = file:/graphics/java/android/graphics/OWNERS +per-file AndroidRuntime.cpp = file:/graphics/java/android/graphics/OWNERS +# Although marked "view" this is mostly graphics stuff +per-file android_view_* = file:/graphics/java/android/graphics/OWNERS
\ No newline at end of file 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/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index f65d7a7540e4..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" /> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 8db991b3766d..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> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 46efd2ca5a75..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" /> 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..43fdedc41e9f 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" /> @@ -452,6 +454,10 @@ applications that come with the platform <permission name="android.permission.CAPTURE_AUDIO_HOTWORD" /> <permission name="android.permission.MODIFY_QUIET_MODE" /> <permission name="android.permission.MANAGE_APP_HIBERNATION"/> + <!-- Permission required for CTS test - ResourceObserverNativeTest --> + <permission name="android.permission.REGISTER_MEDIA_RESOURCE_OBSERVER" /> + <!-- Permission required for CTS test - CtsAlarmManagerTestCases --> + <permission name="android.permission.SCHEDULE_PRIORITIZED_ALARM" /> </privapp-permissions> <privapp-permissions package="com.android.statementservice"> diff --git a/data/fonts/fonts.xml b/data/fonts/fonts.xml index d2b47c6336c4..4c214b529b39 100644 --- a/data/fonts/fonts.xml +++ b/data/fonts/fonts.xml @@ -60,7 +60,7 @@ <alias name="sans-serif-condensed-medium" to="sans-serif-condensed" weight="500" /> <family name="serif"> - <font weight="400" style="normal">NotoSerif.ttf</font> + <font weight="400" style="normal">NotoSerif-Regular.ttf</font> <font weight="700" style="normal">NotoSerif-Bold.ttf</font> <font weight="400" style="italic">NotoSerif-Italic.ttf</font> <font weight="700" style="italic">NotoSerif-BoldItalic.ttf</font> @@ -112,33 +112,33 @@ <!-- fallback fonts --> <family lang="und-Arab" variant="elegant"> - <font weight="400" style="normal">NotoNaskhArabic.ttf</font> + <font weight="400" style="normal">NotoNaskhArabic-Regular.ttf</font> <font weight="700" style="normal">NotoNaskhArabic-Bold.ttf</font> </family> <family lang="und-Arab" variant="compact"> - <font weight="400" style="normal">NotoNaskhArabicUI.ttf</font> + <font weight="400" style="normal">NotoNaskhArabicUI-Regular.ttf</font> <font weight="700" style="normal">NotoNaskhArabicUI-Bold.ttf</font> </family> <family lang="und-Ethi"> - <font weight="400" style="normal">NotoSansEthiopic.ttf</font> + <font weight="400" style="normal">NotoSansEthiopic-Regular.ttf</font> <font weight="700" style="normal">NotoSansEthiopic-Bold.ttf</font> <font weight="400" style="normal" fallbackFor="serif">NotoSerifEthiopic-Regular.otf</font> <font weight="700" style="normal" fallbackFor="serif">NotoSerifEthiopic-Bold.otf</font> </family> <family lang="und-Hebr"> - <font weight="400" style="normal">NotoSansHebrew.ttf</font> + <font weight="400" style="normal">NotoSansHebrew-Regular.ttf</font> <font weight="700" style="normal">NotoSansHebrew-Bold.ttf</font> <font weight="400" style="normal" fallbackFor="serif">NotoSerifHebrew-Regular.ttf</font> <font weight="700" style="normal" fallbackFor="serif">NotoSerifHebrew-Bold.ttf</font> </family> <family lang="und-Thai" variant="elegant"> - <font weight="400" style="normal">NotoSansThai.ttf</font> + <font weight="400" style="normal">NotoSansThai-Regular.ttf</font> <font weight="700" style="normal">NotoSansThai-Bold.ttf</font> - <font weight="400" style="normal" fallbackFor="serif">NotoSerifThai.ttf</font> + <font weight="400" style="normal" fallbackFor="serif">NotoSerifThai-Regular.ttf</font> <font weight="700" style="normal" fallbackFor="serif">NotoSerifThai-Bold.ttf</font> </family> <family lang="und-Thai" variant="compact"> - <font weight="400" style="normal">NotoSansThaiUI.ttf</font> + <font weight="400" style="normal">NotoSansThaiUI-Regular.ttf</font> <font weight="700" style="normal">NotoSansThaiUI-Bold.ttf</font> </family> <family lang="und-Armn"> @@ -149,28 +149,28 @@ <font weight="700" style="normal" fallbackFor="serif">NotoSerifArmenian-Bold.otf</font> </family> <family lang="und-Geor,und-Geok"> - <font weight="400" style="normal">NotoSansGeorgian-Regular.ttf + <font weight="400" style="normal">NotoSansGeorgian-VF.ttf <axis tag="wght" stylevalue="400" /> </font> - <font weight="500" style="normal">NotoSansGeorgian-Regular.ttf + <font weight="500" style="normal">NotoSansGeorgian-VF.ttf <axis tag="wght" stylevalue="500" /> </font> - <font weight="600" style="normal">NotoSansGeorgian-Regular.ttf + <font weight="600" style="normal">NotoSansGeorgian-VF.ttf <axis tag="wght" stylevalue="600" /> </font> - <font weight="700" style="normal">NotoSansGeorgian-Regular.ttf + <font weight="700" style="normal">NotoSansGeorgian-VF.ttf <axis tag="wght" stylevalue="700" /> </font> - <font weight="400" style="normal" fallbackFor="serif">NotoSerifGeorgian-Regular.ttf + <font weight="400" style="normal" fallbackFor="serif">NotoSerifGeorgian-VF.ttf <axis tag="wght" stylevalue="400" /> </font> - <font weight="500" style="normal" fallbackFor="serif">NotoSerifGeorgian-Regular.ttf + <font weight="500" style="normal" fallbackFor="serif">NotoSerifGeorgian-VF.ttf <axis tag="wght" stylevalue="500" /> </font> - <font weight="600" style="normal" fallbackFor="serif">NotoSerifGeorgian-Regular.ttf + <font weight="600" style="normal" fallbackFor="serif">NotoSerifGeorgian-VF.ttf <axis tag="wght" stylevalue="600" /> </font> - <font weight="700" style="normal" fallbackFor="serif">NotoSerifGeorgian-Regular.ttf + <font weight="700" style="normal" fallbackFor="serif">NotoSerifGeorgian-VF.ttf <axis tag="wght" stylevalue="700" /> </font> </family> @@ -178,7 +178,7 @@ <font weight="400" style="normal">NotoSansDevanagari-Regular.otf</font> <font weight="500" style="normal">NotoSansDevanagari-Medium.otf</font> <font weight="700" style="normal">NotoSansDevanagari-Bold.otf</font> - <font weight="400" style="normal" fallbackFor="serif">NotoSerifDevanagari.ttf</font> + <font weight="400" style="normal" fallbackFor="serif">NotoSerifDevanagari-Regular.ttf</font> <font weight="700" style="normal" fallbackFor="serif">NotoSerifDevanagari-Bold.ttf</font> </family> <family lang="und-Deva" variant="compact"> @@ -191,23 +191,23 @@ danda characters. --> <family lang="und-Gujr" variant="elegant"> - <font weight="400" style="normal">NotoSansGujarati.ttf</font> + <font weight="400" style="normal">NotoSansGujarati-Regular.ttf</font> <font weight="700" style="normal">NotoSansGujarati-Bold.ttf</font> - <font weight="400" style="normal" fallbackFor="serif">NotoSerifGujarati.ttf</font> + <font weight="400" style="normal" fallbackFor="serif">NotoSerifGujarati-Regular.ttf</font> <font weight="700" style="normal" fallbackFor="serif">NotoSerifGujarati-Bold.ttf</font> </family> <family lang="und-Gujr" variant="compact"> - <font weight="400" style="normal">NotoSansGujaratiUI.ttf</font> + <font weight="400" style="normal">NotoSansGujaratiUI-Regular.ttf</font> <font weight="700" style="normal">NotoSansGujaratiUI-Bold.ttf</font> </family> <family lang="und-Guru" variant="elegant"> - <font weight="400" style="normal">NotoSansGurmukhi.ttf</font> + <font weight="400" style="normal">NotoSansGurmukhi-Regular.ttf</font> <font weight="700" style="normal">NotoSansGurmukhi-Bold.ttf</font> <font weight="400" style="normal" fallbackFor="serif">NotoSerifGurmukhi-Regular.otf</font> <font weight="700" style="normal" fallbackFor="serif">NotoSerifGurmukhi-Bold.otf</font> </family> <family lang="und-Guru" variant="compact"> - <font weight="400" style="normal">NotoSansGurmukhiUI.ttf</font> + <font weight="400" style="normal">NotoSansGurmukhiUI-Regular.ttf</font> <font weight="700" style="normal">NotoSansGurmukhiUI-Bold.ttf</font> </family> <family lang="und-Taml" variant="elegant"> @@ -226,7 +226,7 @@ <font weight="400" style="normal">NotoSansMalayalam-Regular.otf</font> <font weight="500" style="normal">NotoSansMalayalam-Medium.otf</font> <font weight="700" style="normal">NotoSansMalayalam-Bold.otf</font> - <font weight="400" style="normal" fallbackFor="serif">NotoSerifMalayalam.ttf</font> + <font weight="400" style="normal" fallbackFor="serif">NotoSerifMalayalam-Regular.ttf</font> <font weight="700" style="normal" fallbackFor="serif">NotoSerifMalayalam-Bold.ttf</font> </family> <family lang="und-Mlym" variant="compact"> @@ -238,7 +238,7 @@ <font weight="400" style="normal">NotoSansBengali-Regular.otf</font> <font weight="500" style="normal">NotoSansBengali-Medium.otf</font> <font weight="700" style="normal">NotoSansBengali-Bold.otf</font> - <font weight="400" style="normal" fallbackFor="serif">NotoSerifBengali.ttf</font> + <font weight="400" style="normal" fallbackFor="serif">NotoSerifBengali-Regular.ttf</font> <font weight="700" style="normal" fallbackFor="serif">NotoSerifBengali-Bold.ttf</font> </family> <family lang="und-Beng" variant="compact"> @@ -247,31 +247,31 @@ <font weight="700" style="normal">NotoSansBengaliUI-Bold.otf</font> </family> <family lang="und-Telu" variant="elegant"> - <font weight="400" style="normal">NotoSansTelugu.ttf</font> + <font weight="400" style="normal">NotoSansTelugu-Regular.ttf</font> <font weight="700" style="normal">NotoSansTelugu-Bold.ttf</font> - <font weight="400" style="normal" fallbackFor="serif">NotoSerifTelugu.ttf</font> + <font weight="400" style="normal" fallbackFor="serif">NotoSerifTelugu-Regular.ttf</font> <font weight="700" style="normal" fallbackFor="serif">NotoSerifTelugu-Bold.ttf</font> </family> <family lang="und-Telu" variant="compact"> - <font weight="400" style="normal">NotoSansTeluguUI.ttf</font> + <font weight="400" style="normal">NotoSansTeluguUI-Regular.ttf</font> <font weight="700" style="normal">NotoSansTeluguUI-Bold.ttf</font> </family> <family lang="und-Knda" variant="elegant"> - <font weight="400" style="normal">NotoSansKannada.ttf</font> + <font weight="400" style="normal">NotoSansKannada-Regular.ttf</font> <font weight="700" style="normal">NotoSansKannada-Bold.ttf</font> - <font weight="400" style="normal" fallbackFor="serif">NotoSerifKannada.ttf</font> + <font weight="400" style="normal" fallbackFor="serif">NotoSerifKannada-Regular.ttf</font> <font weight="700" style="normal" fallbackFor="serif">NotoSerifKannada-Bold.ttf</font> </family> <family lang="und-Knda" variant="compact"> - <font weight="400" style="normal">NotoSansKannadaUI.ttf</font> + <font weight="400" style="normal">NotoSansKannadaUI-Regular.ttf</font> <font weight="700" style="normal">NotoSansKannadaUI-Bold.ttf</font> </family> <family lang="und-Orya" variant="elegant"> - <font weight="400" style="normal">NotoSansOriya.ttf</font> + <font weight="400" style="normal">NotoSansOriya-Regular.ttf</font> <font weight="700" style="normal">NotoSansOriya-Bold.ttf</font> </family> <family lang="und-Orya" variant="compact"> - <font weight="400" style="normal">NotoSansOriyaUI.ttf</font> + <font weight="400" style="normal">NotoSansOriyaUI-Regular.ttf</font> <font weight="700" style="normal">NotoSansOriyaUI-Bold.ttf</font> </family> @@ -288,39 +288,39 @@ <font weight="700" style="normal">NotoSansSinhalaUI-Bold.otf</font> </family> <family lang="und-Khmr" variant="elegant"> - <font weight="100" style="normal">NotoSansKhmer-Regular.ttf + <font weight="100" style="normal">NotoSansKhmer-VF.ttf <axis tag="wdth" stylevalue="100.0" /> <axis tag="wght" stylevalue="26.0" /> </font> - <font weight="200" style="normal">NotoSansKhmer-Regular.ttf + <font weight="200" style="normal">NotoSansKhmer-VF.ttf <axis tag="wdth" stylevalue="100.0" /> <axis tag="wght" stylevalue="39.0" /> </font> - <font weight="300" style="normal">NotoSansKhmer-Regular.ttf + <font weight="300" style="normal">NotoSansKhmer-VF.ttf <axis tag="wdth" stylevalue="100.0" /> <axis tag="wght" stylevalue="58.0" /> </font> - <font weight="400" style="normal">NotoSansKhmer-Regular.ttf + <font weight="400" style="normal">NotoSansKhmer-VF.ttf <axis tag="wdth" stylevalue="100.0" /> <axis tag="wght" stylevalue="90.0" /> </font> - <font weight="500" style="normal">NotoSansKhmer-Regular.ttf + <font weight="500" style="normal">NotoSansKhmer-VF.ttf <axis tag="wdth" stylevalue="100.0" /> <axis tag="wght" stylevalue="108.0" /> </font> - <font weight="600" style="normal">NotoSansKhmer-Regular.ttf + <font weight="600" style="normal">NotoSansKhmer-VF.ttf <axis tag="wdth" stylevalue="100.0" /> <axis tag="wght" stylevalue="128.0" /> </font> - <font weight="700" style="normal">NotoSansKhmer-Regular.ttf + <font weight="700" style="normal">NotoSansKhmer-VF.ttf <axis tag="wdth" stylevalue="100.0" /> <axis tag="wght" stylevalue="151.0" /> </font> - <font weight="800" style="normal">NotoSansKhmer-Regular.ttf + <font weight="800" style="normal">NotoSansKhmer-VF.ttf <axis tag="wdth" stylevalue="100.0" /> <axis tag="wght" stylevalue="169.0" /> </font> - <font weight="900" style="normal">NotoSansKhmer-Regular.ttf + <font weight="900" style="normal">NotoSansKhmer-VF.ttf <axis tag="wdth" stylevalue="100.0" /> <axis tag="wght" stylevalue="190.0" /> </font> @@ -328,17 +328,17 @@ <font weight="700" style="normal" fallbackFor="serif">NotoSerifKhmer-Bold.otf</font> </family> <family lang="und-Khmr" variant="compact"> - <font weight="400" style="normal">NotoSansKhmerUI.ttf</font> + <font weight="400" style="normal">NotoSansKhmerUI-Regular.ttf</font> <font weight="700" style="normal">NotoSansKhmerUI-Bold.ttf</font> </family> <family lang="und-Laoo" variant="elegant"> - <font weight="400" style="normal">NotoSansLao.ttf</font> + <font weight="400" style="normal">NotoSansLao-Regular.ttf</font> <font weight="700" style="normal">NotoSansLao-Bold.ttf</font> - <font weight="400" style="normal" fallbackFor="serif">NotoSerifLao.ttf</font> + <font weight="400" style="normal" fallbackFor="serif">NotoSerifLao-Regular.ttf</font> <font weight="700" style="normal" fallbackFor="serif">NotoSerifLao-Bold.ttf</font> </family> <family lang="und-Laoo" variant="compact"> - <font weight="400" style="normal">NotoSansLaoUI.ttf</font> + <font weight="400" style="normal">NotoSansLaoUI-Regular.ttf</font> <font weight="700" style="normal">NotoSansLaoUI-Bold.ttf</font> </family> <family lang="und-Mymr" variant="elegant"> @@ -354,56 +354,56 @@ <font weight="700" style="normal">NotoSansMyanmarUI-Bold.otf</font> </family> <family lang="und-Thaa"> - <font weight="400" style="normal">NotoSansThaana.ttf</font> + <font weight="400" style="normal">NotoSansThaana-Regular.ttf</font> <font weight="700" style="normal">NotoSansThaana-Bold.ttf</font> </family> <family lang="und-Cham"> - <font weight="400" style="normal">NotoSansCham.ttf</font> + <font weight="400" style="normal">NotoSansCham-Regular.ttf</font> <font weight="700" style="normal">NotoSansCham-Bold.ttf</font> </family> <family lang="und-Ahom"> <font weight="400" style="normal">NotoSansAhom-Regular.otf</font> </family> <family lang="und-Adlm"> - <font weight="400" style="normal">NotoSansAdlam-Regular.ttf + <font weight="400" style="normal">NotoSansAdlam-VF.ttf <axis tag="wght" stylevalue="400" /> </font> - <font weight="500" style="normal">NotoSansAdlam-Regular.ttf + <font weight="500" style="normal">NotoSansAdlam-VF.ttf <axis tag="wght" stylevalue="500" /> </font> - <font weight="600" style="normal">NotoSansAdlam-Regular.ttf + <font weight="600" style="normal">NotoSansAdlam-VF.ttf <axis tag="wght" stylevalue="600" /> </font> - <font weight="700" style="normal">NotoSansAdlam-Regular.ttf + <font weight="700" style="normal">NotoSansAdlam-VF.ttf <axis tag="wght" stylevalue="700" /> </font> </family> <family lang="und-Avst"> - <font weight="400" style="normal">NotoSansAvestan.ttf</font> + <font weight="400" style="normal">NotoSansAvestan-Regular.ttf</font> </family> <family lang="und-Bali"> - <font weight="400" style="normal">NotoSansBalinese.ttf</font> + <font weight="400" style="normal">NotoSansBalinese-Regular.ttf</font> </family> <family lang="und-Bamu"> - <font weight="400" style="normal">NotoSansBamum.ttf</font> + <font weight="400" style="normal">NotoSansBamum-Regular.ttf</font> </family> <family lang="und-Batk"> - <font weight="400" style="normal">NotoSansBatak.ttf</font> + <font weight="400" style="normal">NotoSansBatak-Regular.ttf</font> </family> <family lang="und-Brah"> - <font weight="400" style="normal">NotoSansBrahmi.ttf</font> + <font weight="400" style="normal">NotoSansBrahmi-Regular.ttf</font> </family> <family lang="und-Bugi"> - <font weight="400" style="normal">NotoSansBuginese.ttf</font> + <font weight="400" style="normal">NotoSansBuginese-Regular.ttf</font> </family> <family lang="und-Buhd"> - <font weight="400" style="normal">NotoSansBuhid.ttf</font> + <font weight="400" style="normal">NotoSansBuhid-Regular.ttf</font> </family> <family lang="und-Cans"> - <font weight="400" style="normal">NotoSansCanadianAboriginal.ttf</font> + <font weight="400" style="normal">NotoSansCanadianAboriginal-Regular.ttf</font> </family> <family lang="und-Cari"> - <font weight="400" style="normal">NotoSansCarian.ttf</font> + <font weight="400" style="normal">NotoSansCarian-Regular.ttf</font> </family> <family lang="und-Cakm"> <font weight="400" style="normal">NotoSansChakma-Regular.otf</font> @@ -412,184 +412,184 @@ <font weight="400" style="normal">NotoSansCherokee-Regular.ttf</font> </family> <family lang="und-Copt"> - <font weight="400" style="normal">NotoSansCoptic.ttf</font> + <font weight="400" style="normal">NotoSansCoptic-Regular.ttf</font> </family> <family lang="und-Xsux"> - <font weight="400" style="normal">NotoSansCuneiform.ttf</font> + <font weight="400" style="normal">NotoSansCuneiform-Regular.ttf</font> </family> <family lang="und-Cprt"> - <font weight="400" style="normal">NotoSansCypriot.ttf</font> + <font weight="400" style="normal">NotoSansCypriot-Regular.ttf</font> </family> <family lang="und-Dsrt"> - <font weight="400" style="normal">NotoSansDeseret.ttf</font> + <font weight="400" style="normal">NotoSansDeseret-Regular.ttf</font> </family> <family lang="und-Egyp"> - <font weight="400" style="normal">NotoSansEgyptianHieroglyphs.ttf</font> + <font weight="400" style="normal">NotoSansEgyptianHieroglyphs-Regular.ttf</font> </family> <family lang="und-Elba"> <font weight="400" style="normal">NotoSansElbasan-Regular.otf</font> </family> <family lang="und-Glag"> - <font weight="400" style="normal">NotoSansGlagolitic.ttf</font> + <font weight="400" style="normal">NotoSansGlagolitic-Regular.ttf</font> </family> <family lang="und-Goth"> - <font weight="400" style="normal">NotoSansGothic.ttf</font> + <font weight="400" style="normal">NotoSansGothic-Regular.ttf</font> </family> <family lang="und-Hano"> - <font weight="400" style="normal">NotoSansHanunoo.ttf</font> + <font weight="400" style="normal">NotoSansHanunoo-Regular.ttf</font> </family> <family lang="und-Armi"> - <font weight="400" style="normal">NotoSansImperialAramaic.ttf</font> + <font weight="400" style="normal">NotoSansImperialAramaic-Regular.ttf</font> </family> <family lang="und-Phli"> - <font weight="400" style="normal">NotoSansInscriptionalPahlavi.ttf</font> + <font weight="400" style="normal">NotoSansInscriptionalPahlavi-Regular.ttf</font> </family> <family lang="und-Prti"> - <font weight="400" style="normal">NotoSansInscriptionalParthian.ttf</font> + <font weight="400" style="normal">NotoSansInscriptionalParthian-Regular.ttf</font> </family> <family lang="und-Java"> <font weight="400" style="normal">NotoSansJavanese-Regular.ttf</font> </family> <family lang="und-Kthi"> - <font weight="400" style="normal">NotoSansKaithi.ttf</font> + <font weight="400" style="normal">NotoSansKaithi-Regular.ttf</font> </family> <family lang="und-Kali"> - <font weight="400" style="normal">NotoSansKayahLi.ttf</font> + <font weight="400" style="normal">NotoSansKayahLi-Regular.ttf</font> </family> <family lang="und-Khar"> - <font weight="400" style="normal">NotoSansKharoshthi.ttf</font> + <font weight="400" style="normal">NotoSansKharoshthi-Regular.ttf</font> </family> <family lang="und-Lepc"> - <font weight="400" style="normal">NotoSansLepcha.ttf</font> + <font weight="400" style="normal">NotoSansLepcha-Regular.ttf</font> </family> <family lang="und-Limb"> - <font weight="400" style="normal">NotoSansLimbu.ttf</font> + <font weight="400" style="normal">NotoSansLimbu-Regular.ttf</font> </family> <family lang="und-Linb"> - <font weight="400" style="normal">NotoSansLinearB.ttf</font> + <font weight="400" style="normal">NotoSansLinearB-Regular.ttf</font> </family> <family lang="und-Lisu"> - <font weight="400" style="normal">NotoSansLisu.ttf</font> + <font weight="400" style="normal">NotoSansLisu-Regular.ttf</font> </family> <family lang="und-Lyci"> - <font weight="400" style="normal">NotoSansLycian.ttf</font> + <font weight="400" style="normal">NotoSansLycian-Regular.ttf</font> </family> <family lang="und-Lydi"> - <font weight="400" style="normal">NotoSansLydian.ttf</font> + <font weight="400" style="normal">NotoSansLydian-Regular.ttf</font> </family> <family lang="und-Mand"> - <font weight="400" style="normal">NotoSansMandaic.ttf</font> + <font weight="400" style="normal">NotoSansMandaic-Regular.ttf</font> </family> <family lang="und-Mtei"> - <font weight="400" style="normal">NotoSansMeeteiMayek.ttf</font> + <font weight="400" style="normal">NotoSansMeeteiMayek-Regular.ttf</font> </family> <family lang="und-Talu"> - <font weight="400" style="normal">NotoSansNewTaiLue.ttf</font> + <font weight="400" style="normal">NotoSansNewTaiLue-Regular.ttf</font> </family> <family lang="und-Nkoo"> - <font weight="400" style="normal">NotoSansNKo.ttf</font> + <font weight="400" style="normal">NotoSansNKo-Regular.ttf</font> </family> <family lang="und-Ogam"> - <font weight="400" style="normal">NotoSansOgham.ttf</font> + <font weight="400" style="normal">NotoSansOgham-Regular.ttf</font> </family> <family lang="und-Olck"> - <font weight="400" style="normal">NotoSansOlChiki.ttf</font> + <font weight="400" style="normal">NotoSansOlChiki-Regular.ttf</font> </family> <family lang="und-Ital"> - <font weight="400" style="normal">NotoSansOldItalic.ttf</font> + <font weight="400" style="normal">NotoSansOldItalic-Regular.ttf</font> </family> <family lang="und-Xpeo"> - <font weight="400" style="normal">NotoSansOldPersian.ttf</font> + <font weight="400" style="normal">NotoSansOldPersian-Regular.ttf</font> </family> <family lang="und-Sarb"> - <font weight="400" style="normal">NotoSansOldSouthArabian.ttf</font> + <font weight="400" style="normal">NotoSansOldSouthArabian-Regular.ttf</font> </family> <family lang="und-Orkh"> - <font weight="400" style="normal">NotoSansOldTurkic.ttf</font> + <font weight="400" style="normal">NotoSansOldTurkic-Regular.ttf</font> </family> <family lang="und-Osge"> <font weight="400" style="normal">NotoSansOsage-Regular.ttf</font> </family> <family lang="und-Osma"> - <font weight="400" style="normal">NotoSansOsmanya.ttf</font> + <font weight="400" style="normal">NotoSansOsmanya-Regular.ttf</font> </family> <family lang="und-Phnx"> - <font weight="400" style="normal">NotoSansPhoenician.ttf</font> + <font weight="400" style="normal">NotoSansPhoenician-Regular.ttf</font> </family> <family lang="und-Rjng"> - <font weight="400" style="normal">NotoSansRejang.ttf</font> + <font weight="400" style="normal">NotoSansRejang-Regular.ttf</font> </family> <family lang="und-Runr"> - <font weight="400" style="normal">NotoSansRunic.ttf</font> + <font weight="400" style="normal">NotoSansRunic-Regular.ttf</font> </family> <family lang="und-Samr"> - <font weight="400" style="normal">NotoSansSamaritan.ttf</font> + <font weight="400" style="normal">NotoSansSamaritan-Regular.ttf</font> </family> <family lang="und-Saur"> - <font weight="400" style="normal">NotoSansSaurashtra.ttf</font> + <font weight="400" style="normal">NotoSansSaurashtra-Regular.ttf</font> </family> <family lang="und-Shaw"> - <font weight="400" style="normal">NotoSansShavian.ttf</font> + <font weight="400" style="normal">NotoSansShavian-Regular.ttf</font> </family> <family lang="und-Sund"> - <font weight="400" style="normal">NotoSansSundanese.ttf</font> + <font weight="400" style="normal">NotoSansSundanese-Regular.ttf</font> </family> <family lang="und-Sylo"> - <font weight="400" style="normal">NotoSansSylotiNagri.ttf</font> + <font weight="400" style="normal">NotoSansSylotiNagri-Regular.ttf</font> </family> <!-- Esrangela should precede Eastern and Western Syriac, since it's our default form. --> <family lang="und-Syre"> - <font weight="400" style="normal">NotoSansSyriacEstrangela.ttf</font> + <font weight="400" style="normal">NotoSansSyriacEstrangela-Regular.ttf</font> </family> <family lang="und-Syrn"> - <font weight="400" style="normal">NotoSansSyriacEastern.ttf</font> + <font weight="400" style="normal">NotoSansSyriacEastern-Regular.ttf</font> </family> <family lang="und-Syrj"> - <font weight="400" style="normal">NotoSansSyriacWestern.ttf</font> + <font weight="400" style="normal">NotoSansSyriacWestern-Regular.ttf</font> </family> <family lang="und-Tglg"> - <font weight="400" style="normal">NotoSansTagalog.ttf</font> + <font weight="400" style="normal">NotoSansTagalog-Regular.ttf</font> </family> <family lang="und-Tagb"> - <font weight="400" style="normal">NotoSansTagbanwa.ttf</font> + <font weight="400" style="normal">NotoSansTagbanwa-Regular.ttf</font> </family> <family lang="und-Lana"> - <font weight="400" style="normal">NotoSansTaiTham.ttf</font> + <font weight="400" style="normal">NotoSansTaiTham-Regular.ttf</font> </family> <family lang="und-Tavt"> - <font weight="400" style="normal">NotoSansTaiViet.ttf</font> + <font weight="400" style="normal">NotoSansTaiViet-Regular.ttf</font> </family> <family lang="und-Tibt"> - <font weight="400" style="normal">NotoSansTibetan.ttf</font> + <font weight="400" style="normal">NotoSansTibetan-Regular.ttf</font> <font weight="700" style="normal">NotoSansTibetan-Bold.ttf</font> </family> <family lang="und-Tfng"> <font weight="400" style="normal">NotoSansTifinagh-Regular.otf</font> </family> <family lang="und-Ugar"> - <font weight="400" style="normal">NotoSansUgaritic.ttf</font> + <font weight="400" style="normal">NotoSansUgaritic-Regular.ttf</font> </family> <family lang="und-Vaii"> - <font weight="400" style="normal">NotoSansVai.ttf</font> + <font weight="400" style="normal">NotoSansVai-Regular.ttf</font> </family> <family> <font weight="400" style="normal">NotoSansSymbols-Regular-Subsetted.ttf</font> </family> <family lang="zh-Hans"> - <font weight="400" style="normal" index="2">NotoSansCJKjp-Regular.otc</font> - <font weight="400" style="normal" index="2" fallbackFor="serif">NotoSerifCJKjp-Regular.otc</font> + <font weight="400" style="normal" index="2">NotoSansCJK-Regular.ttc</font> + <font weight="400" style="normal" index="2" fallbackFor="serif">NotoSerifCJK-Regular.ttc</font> </family> <family lang="zh-Hant,zh-Bopo"> - <font weight="400" style="normal" index="3">NotoSansCJKjp-Regular.otc</font> - <font weight="400" style="normal" index="3" fallbackFor="serif">NotoSerifCJKjp-Regular.otc</font> + <font weight="400" style="normal" index="3">NotoSansCJK-Regular.ttc</font> + <font weight="400" style="normal" index="3" fallbackFor="serif">NotoSerifCJK-Regular.ttc</font> </family> <family lang="ja"> - <font weight="400" style="normal" index="0">NotoSansCJKjp-Regular.otc</font> - <font weight="400" style="normal" index="0" fallbackFor="serif">NotoSerifCJKjp-Regular.otc</font> + <font weight="400" style="normal" index="0">NotoSansCJK-Regular.ttc</font> + <font weight="400" style="normal" index="0" fallbackFor="serif">NotoSerifCJK-Regular.ttc</font> </family> <family lang="ko"> - <font weight="400" style="normal" index="1">NotoSansCJKjp-Regular.otc</font> - <font weight="400" style="normal" index="1" fallbackFor="serif">NotoSerifCJKjp-Regular.otc</font> + <font weight="400" style="normal" index="1">NotoSansCJK-Regular.ttc</font> + <font weight="400" style="normal" index="1" fallbackFor="serif">NotoSerifCJK-Regular.ttc</font> </family> <family lang="und-Zsye"> <font weight="400" style="normal">NotoColorEmoji.ttf</font> @@ -602,16 +602,16 @@ override the East Asian punctuation for Chinese. --> <family lang="und-Tale"> - <font weight="400" style="normal">NotoSansTaiLe.ttf</font> + <font weight="400" style="normal">NotoSansTaiLe-Regular.ttf</font> </family> <family lang="und-Yiii"> - <font weight="400" style="normal">NotoSansYi.ttf</font> + <font weight="400" style="normal">NotoSansYi-Regular.ttf</font> </family> <family lang="und-Mong"> - <font weight="400" style="normal">NotoSansMongolian.ttf</font> + <font weight="400" style="normal">NotoSansMongolian-Regular.ttf</font> </family> <family lang="und-Phag"> - <font weight="400" style="normal">NotoSansPhagsPa.ttf</font> + <font weight="400" style="normal">NotoSansPhagsPa-Regular.ttf</font> </family> <family lang="und-Hluw"> <font weight="400" style="normal">NotoSansAnatolianHieroglyphs-Regular.otf</font> diff --git a/drm/java/Android.bp b/drm/java/Android.bp new file mode 100644 index 000000000000..21fc018f7f4a --- /dev/null +++ b/drm/java/Android.bp @@ -0,0 +1,14 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], +} + +filegroup { + name: "framework-drm-sources", + srcs: ["**/*.java"], + visibility: ["//frameworks/base"], +} diff --git a/graphics/java/Android.bp b/graphics/java/Android.bp new file mode 100644 index 000000000000..63d1f6d6f2d6 --- /dev/null +++ b/graphics/java/Android.bp @@ -0,0 +1,17 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], +} + +filegroup { + name: "framework-graphics-nonupdatable-sources", + srcs: [ + "**/*.java", + "**/*.aidl", + ], + visibility: ["//frameworks/base"], +} diff --git a/identity/Android.bp b/identity/Android.bp new file mode 100644 index 000000000000..826d6f806573 --- /dev/null +++ b/identity/Android.bp @@ -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 { + default_applicable_licenses: ["frameworks_base_identity_license"], +} + +// Added automatically by a large-scale-change +// See: http://go/android-license-faq +license { + name: "frameworks_base_identity_license", + visibility: [":__subpackages__"], + license_kinds: [ + "SPDX-license-identifier-Apache-2.0", + ], + license_text: [ + "NOTICE", + ], +} diff --git a/identity/java/Android.bp b/identity/java/Android.bp new file mode 100644 index 000000000000..a193d9764c7a --- /dev/null +++ b/identity/java/Android.bp @@ -0,0 +1,14 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_identity_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_identity_license"], +} + +filegroup { + name: "framework-identity-sources", + srcs: ["**/*.java"], + visibility: ["//frameworks/base"], +} diff --git a/identity/java/android/security/identity/TEST_MAPPING b/identity/java/android/security/identity/TEST_MAPPING new file mode 100644 index 000000000000..87707a848efd --- /dev/null +++ b/identity/java/android/security/identity/TEST_MAPPING @@ -0,0 +1,7 @@ +{ + "presubmit": [ + { + "name": "CtsIdentityTestCases" + } + ] +} diff --git a/keystore/java/Android.bp b/keystore/java/Android.bp new file mode 100644 index 000000000000..21edff1e1c96 --- /dev/null +++ b/keystore/java/Android.bp @@ -0,0 +1,17 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_keystore_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_keystore_license"], +} + +filegroup { + name: "framework-keystore-sources", + srcs: [ + "**/*.java", + "**/*.aidl", + ], + visibility: ["//frameworks/base"], +} diff --git a/keystore/java/android/security/KeyStore2.java b/keystore/java/android/security/KeyStore2.java index 75e248e06b2b..df579bba9dc2 100644 --- a/keystore/java/android/security/KeyStore2.java +++ b/keystore/java/android/security/KeyStore2.java @@ -125,6 +125,8 @@ public class KeyStore2 { } } + private static final String KEYSTORE2_SERVICE_NAME = + "android.system.keystore2.IKeystoreService/default"; private KeyStore2() { mBinder = null; @@ -137,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/location/java/Android.bp b/location/java/Android.bp new file mode 100644 index 000000000000..543f2b1ab4a8 --- /dev/null +++ b/location/java/Android.bp @@ -0,0 +1,17 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], +} + +filegroup { + name: "framework-location-sources", + srcs: [ + "**/*.java", + "**/*.aidl", + ], + visibility: ["//frameworks/base"], +} diff --git a/lowpan/java/Android.bp b/lowpan/java/Android.bp new file mode 100644 index 000000000000..58513d70042c --- /dev/null +++ b/lowpan/java/Android.bp @@ -0,0 +1,17 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], +} + +filegroup { + name: "framework-lowpan-sources", + srcs: [ + "**/*.java", + "**/*.aidl", + ], + visibility: ["//frameworks/base"], +} diff --git a/media/java/Android.bp b/media/java/Android.bp index aea63a073e95..eeaf6e9015ac 100644 --- a/media/java/Android.bp +++ b/media/java/Android.bp @@ -8,6 +8,18 @@ package { } filegroup { + name: "framework-media-sources", + srcs: [ + "**/*.java", + "**/*.aidl", + ], + exclude_srcs: [ + ":framework-media-tv-tunerresourcemanager-sources-aidl", + ], + visibility: ["//frameworks/base"], +} + +filegroup { name: "IMidiDeviceServer.aidl", srcs: ["android/media/midi/IMidiDeviceServer.aidl"], } diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java index 7062f83fe575..5633236a122e 100644 --- a/media/java/android/media/MediaCodec.java +++ b/media/java/android/media/MediaCodec.java @@ -4412,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; } diff --git a/media/java/android/media/tv/tunerresourcemanager/Android.bp b/media/java/android/media/tv/tunerresourcemanager/Android.bp index 66c7bd4a1f2b..e365ee11067d 100644 --- a/media/java/android/media/tv/tunerresourcemanager/Android.bp +++ b/media/java/android/media/tv/tunerresourcemanager/Android.bp @@ -6,6 +6,12 @@ package { // SPDX-license-identifier-Apache-2.0 default_applicable_licenses: ["frameworks_base_license"], } +filegroup { + // NOTE: This is purposefully left empty, and exists only so that it can be + // referenced in frameworks/base/Android.bp. + name: "framework-media-tv-tunerresourcemanager-sources-aidl", + srcs: [], +} filegroup { name: "framework-media-tv-tunerresourcemanager-sources", diff --git a/media/java/android/mtp/MtpDatabase.java b/media/java/android/mtp/MtpDatabase.java index ed56b4398c22..9fe700a41ab2 100755 --- a/media/java/android/mtp/MtpDatabase.java +++ b/media/java/android/mtp/MtpDatabase.java @@ -821,8 +821,10 @@ public class MtpDatabase implements AutoCloseable { ByteArrayOutputStream byteStream = new ByteArrayOutputStream(); bitmap.compress(Bitmap.CompressFormat.JPEG, 100, byteStream); - if (byteStream.size() > MAX_THUMB_SIZE) + if (byteStream.size() > MAX_THUMB_SIZE) { + Log.w(TAG, "getThumbnailProcess: size=" + byteStream.size()); return null; + } byte[] byteArray = byteStream.toByteArray(); @@ -852,7 +854,15 @@ public class MtpDatabase implements AutoCloseable { outLongs[0] = thumbOffsetAndSize != null ? thumbOffsetAndSize[1] : 0; outLongs[1] = exif.getAttributeInt(ExifInterface.TAG_PIXEL_X_DIMENSION, 0); outLongs[2] = exif.getAttributeInt(ExifInterface.TAG_PIXEL_Y_DIMENSION, 0); - return true; + if (exif.getThumbnailRange() != null) { + if ((outLongs[0] == 0) || (outLongs[1] == 0) || (outLongs[2] == 0)) { + Log.d(TAG, "getThumbnailInfo: check thumb info:" + + thumbOffsetAndSize[0] + "," + thumbOffsetAndSize[1] + + "," + outLongs[1] + "," + outLongs[2]); + } + + return true; + } } catch (IOException e) { // ignore and fall through } @@ -885,7 +895,9 @@ public class MtpDatabase implements AutoCloseable { case MtpConstants.FORMAT_JFIF: try { ExifInterface exif = new ExifInterface(path); - return exif.getThumbnail(); + + if (exif.getThumbnailRange() != null) + return exif.getThumbnail(); } catch (IOException e) { // ignore and fall through } diff --git a/media/mca/effect/java/Android.bp b/media/mca/effect/java/Android.bp new file mode 100644 index 000000000000..70d999f76483 --- /dev/null +++ b/media/mca/effect/java/Android.bp @@ -0,0 +1,14 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], +} + +filegroup { + name: "framework-mca-effect-sources", + srcs: ["**/*.java"], + visibility: ["//frameworks/base"], +} diff --git a/media/mca/filterfw/java/Android.bp b/media/mca/filterfw/java/Android.bp new file mode 100644 index 000000000000..77afcff27f56 --- /dev/null +++ b/media/mca/filterfw/java/Android.bp @@ -0,0 +1,14 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], +} + +filegroup { + name: "framework-mca-filterfw-sources", + srcs: ["**/*.java"], + visibility: ["//frameworks/base"], +} diff --git a/media/mca/filterpacks/java/Android.bp b/media/mca/filterpacks/java/Android.bp new file mode 100644 index 000000000000..f370b21589c5 --- /dev/null +++ b/media/mca/filterpacks/java/Android.bp @@ -0,0 +1,14 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], +} + +filegroup { + name: "framework-mca-filterpacks-sources", + srcs: ["**/*.java"], + visibility: ["//frameworks/base"], +} diff --git a/media/tests/MtpTests/res/raw/test_bad_thumb.jpg b/media/tests/MtpTests/res/raw/test_bad_thumb.jpg Binary files differindex e69de29bb2d1..78ac703850a1 100644 --- a/media/tests/MtpTests/res/raw/test_bad_thumb.jpg +++ b/media/tests/MtpTests/res/raw/test_bad_thumb.jpg diff --git a/media/tests/MtpTests/src/android/mtp/MtpDatabaseTest.java b/media/tests/MtpTests/src/android/mtp/MtpDatabaseTest.java index e2e8ff4946e0..0bf99cfd9dd1 100644 --- a/media/tests/MtpTests/src/android/mtp/MtpDatabaseTest.java +++ b/media/tests/MtpTests/src/android/mtp/MtpDatabaseTest.java @@ -271,9 +271,10 @@ public class MtpDatabaseTest { Log.d(TAG, "testMtpDatabaseThumbnail: Test bad JPG"); - testThumbnail(handleJpgBadThumb, jpgfileBadThumb, false); +// Now we support to generate thumbnail if embedded thumbnail is corrupted or not existed + testThumbnail(handleJpgBadThumb, jpgfileBadThumb, true); - testThumbnail(handleJpgNoThumb, jpgFileNoThumb, false); + testThumbnail(handleJpgNoThumb, jpgFileNoThumb, true); testThumbnail(handleJpgBad, jpgfileBad, false); diff --git a/mime/java/Android.bp b/mime/java/Android.bp new file mode 100644 index 000000000000..07cada8e1372 --- /dev/null +++ b/mime/java/Android.bp @@ -0,0 +1,14 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], +} + +filegroup { + name: "framework-mime-sources", + srcs: ["**/*.java"], + visibility: ["//frameworks/base"], +} diff --git a/mms/java/Android.bp b/mms/java/Android.bp new file mode 100644 index 000000000000..4d51439392fa --- /dev/null +++ b/mms/java/Android.bp @@ -0,0 +1,17 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], +} + +filegroup { + name: "framework-mms-sources", + srcs: [ + "**/*.java", + "**/*.aidl", + ], + visibility: ["//frameworks/base"], +} diff --git a/opengl/java/Android.bp b/opengl/java/Android.bp new file mode 100644 index 000000000000..6dbae421e059 --- /dev/null +++ b/opengl/java/Android.bp @@ -0,0 +1,14 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], +} + +filegroup { + name: "framework-opengl-sources", + srcs: ["**/*.java"], + visibility: ["//frameworks/base"], +} diff --git a/packages/Connectivity/framework/api/current.txt b/packages/Connectivity/framework/api/current.txt index ad44b27f6d0b..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); diff --git a/packages/Connectivity/framework/api/module-lib-current.txt b/packages/Connectivity/framework/api/module-lib-current.txt index ac69a3e79591..cd96a1b481b6 100644 --- a/packages/Connectivity/framework/api/module-lib-current.txt +++ b/packages/Connectivity/framework/api/module-lib-current.txt @@ -20,6 +20,7 @@ package android.net { 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); @@ -27,10 +28,12 @@ package android.net { 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"; @@ -40,6 +43,56 @@ 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(); @@ -67,6 +120,7 @@ package android.net { } public class NetworkRequest implements android.os.Parcelable { + method @NonNull public int[] getUnwantedCapabilities(); method public boolean hasUnwantedCapability(int); } diff --git a/packages/Connectivity/framework/api/system-current.txt b/packages/Connectivity/framework/api/system-current.txt index 8e6e846240a4..95ad694293f2 100644 --- a/packages/Connectivity/framework/api/system-current.txt +++ b/packages/Connectivity/framework/api/system-current.txt @@ -217,7 +217,9 @@ package android.net { 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); @@ -235,6 +237,8 @@ package android.net { 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 @@ -255,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); @@ -404,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 bc668f3f0a39..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; @@ -872,6 +874,17 @@ public class ConnectivityManager { 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. * @@ -908,12 +921,21 @@ public class ConnectivityManager { 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; @@ -1168,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 @@ -3442,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)) { @@ -3455,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. } /** @@ -3619,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; } @@ -3733,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: { @@ -3767,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); } } } @@ -5371,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/INetworkAgent.aidl b/packages/Connectivity/framework/src/android/net/INetworkAgent.aidl index 078acbd8fe57..d941d4b95b56 100644 --- a/packages/Connectivity/framework/src/android/net/INetworkAgent.aidl +++ b/packages/Connectivity/framework/src/android/net/INetworkAgent.aidl @@ -47,4 +47,5 @@ oneway interface INetworkAgent { 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 cbd6193744b9..26cb1ed6b4b4 100644 --- a/packages/Connectivity/framework/src/android/net/INetworkAgentRegistry.aidl +++ b/packages/Connectivity/framework/src/android/net/INetworkAgentRegistry.aidl @@ -41,4 +41,5 @@ oneway interface INetworkAgentRegistry { 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/NetworkAgent.java b/packages/Connectivity/framework/src/android/net/NetworkAgent.java index aef1a31b7227..c57da53f289d 100644 --- a/packages/Connectivity/framework/src/android/net/NetworkAgent.java +++ b/packages/Connectivity/framework/src/android/net/NetworkAgent.java @@ -185,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. @@ -197,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}. @@ -370,10 +383,17 @@ public abstract class NetworkAgent { */ 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()); @@ -574,6 +594,10 @@ public abstract class NetworkAgent { onNetworkCreated(); break; } + case CMD_NETWORK_DESTROYED: { + onNetworkDestroyed(); + break; + } } } } @@ -719,6 +743,11 @@ public abstract class NetworkAgent { public void onNetworkCreated() { mHandler.sendMessage(mHandler.obtainMessage(CMD_NETWORK_CREATED)); } + + @Override + public void onNetworkDestroyed() { + mHandler.sendMessage(mHandler.obtainMessage(CMD_NETWORK_DESTROYED)); + } } /** @@ -835,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, @@ -846,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); @@ -979,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(); } @@ -1031,6 +1085,12 @@ public abstract class NetworkAgent { */ 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. * diff --git a/packages/Connectivity/framework/src/android/net/NetworkAgentConfig.java b/packages/Connectivity/framework/src/android/net/NetworkAgentConfig.java index 0bd2371bfca8..3f058d8cbf12 100644 --- a/packages/Connectivity/framework/src/android/net/NetworkAgentConfig.java +++ b/packages/Connectivity/framework/src/android/net/NetworkAgentConfig.java @@ -175,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. * @@ -200,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> @@ -235,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; } } @@ -300,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() { @@ -313,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() { @@ -334,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. @@ -345,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) { @@ -435,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); } @@ -452,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/NetworkRequest.java b/packages/Connectivity/framework/src/android/net/NetworkRequest.java index bcbc04f72efc..38691ef5cb39 100644 --- a/packages/Connectivity/framework/src/android/net/NetworkRequest.java +++ b/packages/Connectivity/framework/src/android/net/NetworkRequest.java @@ -699,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/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/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..904148f0415b 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" /> @@ -369,6 +374,15 @@ <uses-permission android:name="android.permission.BIND_RESUME_ON_REBOOT_SERVICE" /> <uses-permission android:name="android.permission.MANAGE_APP_HIBERNATION"/> + <!-- Permission required for CTS test - ResourceObserverNativeTest --> + <uses-permission android:name="android.permission.REGISTER_MEDIA_RESOURCE_OBSERVER" /> + + <!-- Permission required for CTS test - android.widget.cts.ToastTest --> + <uses-permission android:name="android.permission.UNLIMITED_TOASTS" /> + + <!-- Permission required for CTS test - CtsAlarmManagerTestCases --> + <uses-permission android:name="android.permission.SCHEDULE_PRIORITIZED_ALARM" /> + <application android:label="@string/app_label" android:theme="@android:style/Theme.DeviceDefault.DayNight" android:defaultToDeviceProtectedStorage="true" 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/rs/java/Android.bp b/rs/java/Android.bp new file mode 100644 index 000000000000..1c2b575e7c8d --- /dev/null +++ b/rs/java/Android.bp @@ -0,0 +1,14 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], +} + +filegroup { + name: "framework-rs-sources", + srcs: ["**/*.java"], + visibility: ["//frameworks/base"], +} diff --git a/sax/java/Android.bp b/sax/java/Android.bp new file mode 100644 index 000000000000..0ed69e4bfb8e --- /dev/null +++ b/sax/java/Android.bp @@ -0,0 +1,14 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], +} + +filegroup { + name: "framework-sax-sources", + srcs: ["**/*.java"], + visibility: ["//frameworks/base"], +} 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/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index b7371897d07a..70c9fe7f3ac9 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -30,6 +30,8 @@ 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; @@ -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,6 +1205,7 @@ 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(); @@ -1548,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.mAsUid, requestId, net.getNetId())); + "%s %d(%d) on netId %d: %s", action, nri.mAsUid, requestId, net.getNetId(), + blockedReasonsToString(blocked))); } /** @@ -2338,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) { @@ -3119,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); + } + } } } @@ -3689,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). @@ -3701,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) { @@ -4001,7 +4034,7 @@ public class ConnectivityService extends IConnectivityManager.Stub } } } - mNetworkRequestCounter.decrementCount(nri.mUid); + decrementRequestCount(nri); mNetworkRequestInfoLogs.log("RELEASE " + nri); if (null != nri.getActiveRequest()) { @@ -4112,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(); @@ -4839,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 @@ -4859,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); @@ -5424,7 +5507,7 @@ public class ConnectivityService extends IConnectivityManager.Stub mPid = getCallingPid(); mUid = mDeps.getCallingUid(); mAsUid = asUid; - mNetworkRequestCounter.incrementCountOrThrow(mUid); + incrementRequestCountOrThrow(this); /** * Location sensitive data not included in pending intent. Only included in * {@link NetworkCallback}. @@ -5456,15 +5539,10 @@ public class ConnectivityService extends IConnectivityManager.Stub mUid = mDeps.getCallingUid(); mAsUid = asUid; mPendingIntent = null; - mNetworkRequestCounter.incrementCountOrThrow(mUid); + incrementRequestCountOrThrow(this); mCallbackFlags = callbackFlags; mCallingAttributionTag = callingAttributionTag; - - try { - mBinder.linkToDeath(this, 0); - } catch (RemoteException e) { - binderDied(); - } + linkDeathRecipient(); } NetworkRequestInfo(@NonNull final NetworkRequestInfo nri, @@ -5499,9 +5577,10 @@ public class ConnectivityService extends IConnectivityManager.Stub mUid = nri.mUid; mAsUid = nri.mAsUid; mPendingIntent = nri.mPendingIntent; - mNetworkRequestCounter.incrementCountOrThrow(mUid); + incrementRequestCountOrThrow(this); mCallbackFlags = nri.mCallbackFlags; mCallingAttributionTag = nri.mCallingAttributionTag; + linkDeathRecipient(); } NetworkRequestInfo(int asUid, @NonNull final NetworkRequest r) { @@ -5530,8 +5609,18 @@ public class ConnectivityService extends IConnectivityManager.Stub return Collections.unmodifiableList(tempRequests); } + void linkDeathRecipient() { + if (null != mBinder) { + try { + mBinder.linkToDeath(this, 0); + } catch (RemoteException e) { + binderDied(); + } + } + } + void unlinkDeathRecipient() { - if (mBinder != null) { + if (null != mBinder) { mBinder.unlinkToDeath(this, 0); } } @@ -6213,8 +6302,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 @@ -7308,7 +7397,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; } @@ -8052,12 +8141,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.mAsUid, mVpnBlockedUidRanges); - blocked |= NetworkPolicyManager.isUidBlocked( - mUidBlockedReasons.get(nri.mAsUid, 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. @@ -8066,6 +8154,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. * @@ -8073,7 +8176,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, @@ -8082,22 +8188,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.mAsUid, oldBlockedUidRanges); - newVpnBlocked = (oldBlockedUidRanges != 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.mAsUid, 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); } } } @@ -8107,25 +8209,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.mAsUid == uid) { - callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_BLK_CHANGED, arg); + callCallbackForRequest(nri, nai, ConnectivityManager.CALLBACK_BLK_CHANGED, + newBlockedState); } } } @@ -8673,7 +8773,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; } @@ -8739,7 +8839,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); } 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 a95589b5ace3..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; } @@ -1879,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( @@ -2553,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 4622e98bbbb2..8eefbfc606de 100644 --- a/services/core/java/com/android/server/VcnManagementService.java +++ b/services/core/java/com/android/server/VcnManagementService.java @@ -36,7 +36,6 @@ import android.content.IntentFilter; import android.net.ConnectivityManager; import android.net.LinkProperties; import android.net.NetworkCapabilities; -import android.net.TelephonyNetworkSpecifier; import android.net.vcn.IVcnManagementService; import android.net.vcn.IVcnStatusCallback; import android.net.vcn.IVcnUnderlyingNetworkPolicyListener; @@ -717,19 +716,29 @@ public class VcnManagementService extends IVcnManagementService.Stub { }); } - private int getSubIdForNetworkCapabilities(@NonNull NetworkCapabilities networkCapabilities) { - if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) - && networkCapabilities.getNetworkSpecifier() instanceof TelephonyNetworkSpecifier) { - TelephonyNetworkSpecifier telephonyNetworkSpecifier = - (TelephonyNetworkSpecifier) networkCapabilities.getNetworkSpecifier(); - return telephonyNetworkSpecifier.getSubscriptionId(); - } else if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) - && networkCapabilities.getTransportInfo() instanceof WifiInfo) { - WifiInfo wifiInfo = (WifiInfo) networkCapabilities.getTransportInfo(); - return mDeps.getSubIdForWifiInfo(wifiInfo); + private ParcelUuid getSubGroupForNetworkCapabilities( + @NonNull NetworkCapabilities networkCapabilities) { + ParcelUuid subGrp = null; + final TelephonySubscriptionSnapshot snapshot; + + // Always access mLastSnapshot under lock. Technically this can be treated as a volatile + // but for consistency and safety, always access under lock. + synchronized (mLock) { + snapshot = mLastSnapshot; + } + + // If multiple subscription IDs exist, they MUST all point to the same subscription + // group. Otherwise undefined behavior may occur. + for (int subId : networkCapabilities.getSubIds()) { + // Verify that all subscriptions point to the same group + if (subGrp != null && !subGrp.equals(snapshot.getGroupForSubId(subId))) { + Slog.wtf(TAG, "Got multiple subscription groups for a single network"); + } + + subGrp = snapshot.getGroupForSubId(subId); } - return SubscriptionManager.INVALID_SUBSCRIPTION_ID; + return subGrp; } /** @@ -754,23 +763,19 @@ public class VcnManagementService extends IVcnManagementService.Stub { // mutates final NetworkCapabilities ncCopy = new NetworkCapabilities(networkCapabilities); - final int subId = getSubIdForNetworkCapabilities(ncCopy); + final ParcelUuid subGrp = getSubGroupForNetworkCapabilities(ncCopy); boolean isVcnManagedNetwork = false; boolean isRestrictedCarrierWifi = false; - if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) { - synchronized (mLock) { - ParcelUuid subGroup = mLastSnapshot.getGroupForSubId(subId); - - final Vcn vcn = mVcns.get(subGroup); - if (vcn != null) { - if (vcn.isActive()) { - isVcnManagedNetwork = true; - } + synchronized (mLock) { + final Vcn vcn = mVcns.get(subGrp); + if (vcn != null) { + if (vcn.isActive()) { + isVcnManagedNetwork = true; + } - if (ncCopy.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) { - // Carrier WiFi always restricted if VCN exists (even in safe mode). - isRestrictedCarrierWifi = true; - } + if (ncCopy.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) { + // Carrier WiFi always restricted if VCN exists (even in safe mode). + isRestrictedCarrierWifi = true; } } } diff --git a/services/core/java/com/android/server/clipboard/ClipboardService.java b/services/core/java/com/android/server/clipboard/ClipboardService.java index 6aec9fcf9a24..72160c203595 100644 --- a/services/core/java/com/android/server/clipboard/ClipboardService.java +++ b/services/core/java/com/android/server/clipboard/ClipboardService.java @@ -52,6 +52,10 @@ import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; +import android.system.ErrnoException; +import android.system.Os; +import android.system.OsConstants; +import android.system.VmSocketAddress; import android.text.TextUtils; import android.util.Slog; import android.util.SparseArray; @@ -63,8 +67,11 @@ import com.android.server.contentcapture.ContentCaptureManagerInternal; import com.android.server.uri.UriGrantsManagerInternal; import com.android.server.wm.WindowManagerInternal; -import java.io.IOException; -import java.io.RandomAccessFile; +import java.io.FileDescriptor; +import java.io.InterruptedIOException; +import java.net.SocketException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; import java.util.Arrays; import java.util.HashSet; import java.util.List; @@ -76,10 +83,10 @@ class HostClipboardMonitor implements Runnable { void onHostClipboardUpdated(String contents); } - private RandomAccessFile mPipe = null; + private FileDescriptor mPipe = null; private HostClipboardCallback mHostClipboardCallback; private static final String PIPE_NAME = "pipe:clipboard"; - private static final String PIPE_DEVICE = "/dev/qemu_pipe"; + private static final int HOST_PORT = 5000; private static byte[] createOpenHandshake() { // String.getBytes doesn't include the null terminator, @@ -93,40 +100,57 @@ class HostClipboardMonitor implements Runnable { private boolean openPipe() { try { - final RandomAccessFile pipe = new RandomAccessFile(PIPE_DEVICE, "rw"); + final FileDescriptor fd = Os.socket(OsConstants.AF_VSOCK, OsConstants.SOCK_STREAM, 0); + try { - pipe.write(createOpenHandshake()); - mPipe = pipe; + Os.connect(fd, new VmSocketAddress(HOST_PORT, OsConstants.VMADDR_CID_HOST)); + + final byte[] handshake = createOpenHandshake(); + Os.write(fd, handshake, 0, handshake.length); + mPipe = fd; return true; - } catch (IOException ignore) { - pipe.close(); + } catch (ErrnoException | SocketException | InterruptedIOException e) { + Os.close(fd); } - } catch (IOException ignore) { + } catch (ErrnoException e) { } + return false; } private void closePipe() { try { - final RandomAccessFile pipe = mPipe; + final FileDescriptor fd = mPipe; mPipe = null; - if (pipe != null) { - pipe.close(); + if (fd != null) { + Os.close(fd); } - } catch (IOException ignore) { + } catch (ErrnoException 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 byte[] receiveMessage() throws ErrnoException, InterruptedIOException { + final byte[] lengthBits = new byte[4]; + Os.read(mPipe, lengthBits, 0, lengthBits.length); + + final ByteBuffer bb = ByteBuffer.wrap(lengthBits); + bb.order(ByteOrder.LITTLE_ENDIAN); + final int msgLen = bb.getInt(); + + final byte[] msg = new byte[msgLen]; + Os.read(mPipe, msg, 0, msg.length); + + return msg; } - private void sendMessage(byte[] message) throws IOException { - mPipe.writeInt(Integer.reverseBytes(message.length)); - mPipe.write(message); + private void sendMessage(byte[] msg) throws ErrnoException, InterruptedIOException { + final byte[] lengthBits = new byte[4]; + final ByteBuffer bb = ByteBuffer.wrap(lengthBits); + bb.order(ByteOrder.LITTLE_ENDIAN); + bb.putInt(msg.length); + + Os.write(mPipe, lengthBits, 0, lengthBits.length); + Os.write(mPipe, msg, 0, msg.length); } public HostClipboardMonitor(HostClipboardCallback cb) { @@ -135,7 +159,7 @@ class HostClipboardMonitor implements Runnable { @Override public void run() { - while(!Thread.interrupted()) { + while (!Thread.interrupted()) { try { // There's no guarantee that QEMU pipes will be ready at the moment // this method is invoked. We simply try to get the pipe open and @@ -147,9 +171,10 @@ class HostClipboardMonitor implements Runnable { final byte[] receivedData = receiveMessage(); mHostClipboardCallback.onHostClipboardUpdated( new String(receivedData)); - } catch (IOException e) { + } catch (ErrnoException | InterruptedIOException e) { closePipe(); - } catch (InterruptedException e) {} + } catch (InterruptedException e) { + } } } @@ -158,7 +183,7 @@ class HostClipboardMonitor implements Runnable { if (mPipe != null) { sendMessage(content.getBytes()); } - } catch(IOException e) { + } catch (ErrnoException | InterruptedIOException e) { Slog.e("HostClipboardMonitor", "Failed to set host clipboard " + e.getMessage()); } 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 496335399320..ee32fbf00dfe 100644 --- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java +++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java @@ -201,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; @@ -588,6 +591,17 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> { } } + /** + * 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; @@ -664,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/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/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/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 f16496c2e5e4..c12785805a2e 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java @@ -40,6 +40,7 @@ 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; @@ -74,7 +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_MASK; import static android.net.NetworkPolicyManager.EXTRA_NETWORK_TEMPLATE; import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT; import static android.net.NetworkPolicyManager.MASK_ALL_NETWORKS; @@ -423,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. @@ -2035,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); } } @@ -2090,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); } } @@ -2102,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; @@ -4972,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) { @@ -5043,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: { @@ -5203,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) { @@ -5219,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) { @@ -5728,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(); } } 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 fe43c311da6f..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; @@ -100,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; @@ -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) { @@ -1377,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 @@ -1674,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)); } } @@ -2071,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/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 6ad43ce6c6ae..0e4a2ee076c2 100644 --- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java +++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java @@ -258,23 +258,23 @@ 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. // OTAPreopt doesn't have stats so don't report in that case. - if (pkg.getBaseCodePath().equals(path) && packageStats != null) { + 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, + path); } finally { Trace.traceEnd(Trace.TRACE_TAG_PACKAGE_MANAGER); } @@ -489,9 +489,9 @@ public class PackageDexOptimizer { String classLoaderContext = null; if (dexUseInfo.isUnsupportedClassLoaderContext() || dexUseInfo.isVariableClassLoaderContext()) { - // If we have an unknown (not yet set), or a variable class loader chain. Just extract + // If we have an unknown (not yet set), or a variable class loader chain. Just verify // the dex file. - compilerFilter = "extract"; + compilerFilter = "verify"; } else { classLoaderContext = dexUseInfo.getClassLoaderContext(); } 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..13798ba1b723 100644 --- a/services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java +++ b/services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java @@ -32,6 +32,8 @@ import java.io.IOException; import java.util.HashMap; import java.util.Iterator; import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import java.util.zip.ZipEntry; /** Utils class to report ART metrics to statsd. */ @@ -39,6 +41,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 +125,35 @@ 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, + String apkPath) { int dexMetadataType = getDexMetadataType(dexMetadataPath); logger.write( sessionId, @@ -140,7 +162,19 @@ public class ArtStatsLogUtils { compilerFilter, ArtStatsLog.ART_DATUM_REPORTED__KIND__ART_DATUM_DEX2OAT_RESULT_CODE, result, - dexMetadataType); + dexMetadataType, + apkType, + isa); + logger.write( + sessionId, + uid, + compilationReason, + compilerFilter, + ArtStatsLog.ART_DATUM_REPORTED__KIND__ART_DATUM_DEX2OAT_DEX_CODE_BYTES, + getDexBytes(apkPath), + dexMetadataType, + apkType, + isa); logger.write( sessionId, uid, @@ -148,7 +182,47 @@ 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 long getDexBytes(String apkPath) { + StrictJarFile jarFile = null; + long dexBytes = 0; + try { + jarFile = new StrictJarFile(apkPath, + /*verify=*/ false, + /*signatureSchemeRollbackProtectionsEnforced=*/ false); + Iterator<ZipEntry> it = jarFile.iterator(); + Pattern p = Pattern.compile("classes(\\d)*[.]dex"); + Matcher m = p.matcher(""); + while (it.hasNext()) { + ZipEntry entry = it.next(); + m.reset(entry.getName()); + if (m.matches()) { + dexBytes += entry.getSize(); + } + } + return dexBytes; + } catch (IOException ignore) { + Slog.e(TAG, "Error when parsing APK " + apkPath); + return -1L; + } finally { + try { + if (jarFile != null) { + jarFile.close(); + } + } catch (IOException ignore) { + } + } } private static int getDexMetadataType(String dexMetadataPath) { @@ -207,7 +281,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 +296,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/speech/OWNERS b/services/core/java/com/android/server/speech/OWNERS new file mode 100644 index 000000000000..b187b87b476e --- /dev/null +++ b/services/core/java/com/android/server/speech/OWNERS @@ -0,0 +1 @@ +include /core/java/android/speech/OWNERS 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/vcn/UnderlyingNetworkTracker.java b/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java index 8dcc547508ec..069c5c3fc714 100644 --- a/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java +++ b/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java @@ -27,15 +27,14 @@ import android.net.NetworkRequest; import android.net.TelephonyNetworkSpecifier; import android.os.Handler; import android.os.ParcelUuid; -import android.util.ArrayMap; -import android.util.ArraySet; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting.Visibility; import com.android.server.vcn.TelephonySubscriptionTracker.TelephonySubscriptionSnapshot; -import java.util.Map; +import java.util.ArrayList; +import java.util.List; import java.util.Objects; import java.util.Set; @@ -59,9 +58,9 @@ public class UnderlyingNetworkTracker { @NonNull private final Handler mHandler; @NonNull private final ConnectivityManager mConnectivityManager; - @NonNull private final Map<Integer, NetworkCallback> mCellBringupCallbacks = new ArrayMap<>(); - @NonNull private final NetworkCallback mWifiBringupCallback = new NetworkBringupCallback(); - @NonNull private final NetworkCallback mRouteSelectionCallback = new RouteSelectionCallback(); + @NonNull private final List<NetworkCallback> mCellBringupCallbacks = new ArrayList<>(); + @Nullable private NetworkCallback mWifiBringupCallback; + @Nullable private NetworkCallback mRouteSelectionCallback; @NonNull private TelephonySubscriptionSnapshot mLastSnapshot; private boolean mIsQuitting = false; @@ -105,36 +104,59 @@ public class UnderlyingNetworkTracker { mConnectivityManager = mVcnContext.getContext().getSystemService(ConnectivityManager.class); - registerNetworkRequests(); + registerOrUpdateNetworkRequests(); } - private void registerNetworkRequests() { - // register bringup requests for underlying Networks - mConnectivityManager.requestBackgroundNetwork( - getWifiNetworkRequest(), mHandler, mWifiBringupCallback); - updateSubIdsAndCellularRequests(); - - // Register Network-selection request used to decide selected underlying Network. All - // underlying networks must be VCN managed in order to be used. - mConnectivityManager.requestBackgroundNetwork( - getBaseNetworkRequest(true /* requireVcnManaged */).build(), - mHandler, - mRouteSelectionCallback); + private void registerOrUpdateNetworkRequests() { + NetworkCallback oldRouteSelectionCallback = mRouteSelectionCallback; + NetworkCallback oldWifiCallback = mWifiBringupCallback; + List<NetworkCallback> oldCellCallbacks = new ArrayList<>(mCellBringupCallbacks); + mCellBringupCallbacks.clear(); + + // Register new callbacks. Make-before-break; always register new callbacks before removal + // of old callbacks + if (!mIsQuitting) { + mRouteSelectionCallback = new RouteSelectionCallback(); + mConnectivityManager.requestBackgroundNetwork( + getBaseNetworkRequestBuilder().build(), mHandler, mRouteSelectionCallback); + + mWifiBringupCallback = new NetworkBringupCallback(); + mConnectivityManager.requestBackgroundNetwork( + getWifiNetworkRequest(), mHandler, mWifiBringupCallback); + + for (final int subId : mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup)) { + final NetworkBringupCallback cb = new NetworkBringupCallback(); + mCellBringupCallbacks.add(cb); + + mConnectivityManager.requestBackgroundNetwork( + getCellNetworkRequestForSubId(subId), mHandler, cb); + } + } else { + mRouteSelectionCallback = null; + mWifiBringupCallback = null; + // mCellBringupCallbacks already cleared above. + } + + // Unregister old callbacks (as necessary) + if (oldRouteSelectionCallback != null) { + mConnectivityManager.unregisterNetworkCallback(oldRouteSelectionCallback); + } + if (oldWifiCallback != null) { + mConnectivityManager.unregisterNetworkCallback(oldWifiCallback); + } + for (NetworkCallback cellBringupCallback : oldCellCallbacks) { + mConnectivityManager.unregisterNetworkCallback(cellBringupCallback); + } } private NetworkRequest getWifiNetworkRequest() { - // Request exclusively VCN managed networks to ensure that we only ever keep carrier wifi - // alive. - return getBaseNetworkRequest(true /* requireVcnManaged */) + return getBaseNetworkRequestBuilder() .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) .build(); } private NetworkRequest getCellNetworkRequestForSubId(int subId) { - // Do not request NOT_VCN_MANAGED to ensure that the TelephonyNetworkFactory has a - // fulfillable request to bring up underlying cellular Networks even if the VCN is already - // connected. - return getBaseNetworkRequest(false /* requireVcnManaged */) + return getBaseNetworkRequestBuilder() .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) .setNetworkSpecifier(new TelephonyNetworkSpecifier(subId)) .build(); @@ -143,67 +165,19 @@ public class UnderlyingNetworkTracker { /** * Builds and returns a NetworkRequest builder common to all Underlying Network requests * - * <p>A NetworkRequest may either (1) Require the presence of a capability by using - * addCapability(), (2) require the absence of a capability using unwanted capabilities, or (3) - * allow any state. Underlying networks are never desired to have the NOT_VCN_MANAGED - * capability, and only cases (2) and (3) are used. - * - * @param requireVcnManaged whether the underlying network is required to be VCN managed to - * match this request. If {@code true}, the NOT_VCN_MANAGED capability will be set as - * unwanted. Else, the NOT_VCN_MANAGED capability will be removed, and any state is - * acceptable. + * <p>This request is guaranteed to select carrier-owned, non-VCN underlying networks by virtue + * of a populated set of subIds as expressed in NetworkCapabilities#getSubIds(). Only carrier + * owned networks may be selected, as the request specifies only subIds in the VCN's + * subscription group, while the VCN networks are excluded by virtue of not having subIds set on + * the VCN-exposed networks. */ - private NetworkRequest.Builder getBaseNetworkRequest(boolean requireVcnManaged) { - NetworkRequest.Builder requestBase = - new NetworkRequest.Builder() - .removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED) - .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) - .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED); - - for (int capability : mRequiredUnderlyingNetworkCapabilities) { - requestBase.addCapability(capability); - } - - if (requireVcnManaged) { - requestBase.addUnwantedCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED); - } - - return requestBase; - } - - /** - * Update the current subIds and Cellular bringup requests for this UnderlyingNetworkTracker. - */ - private void updateSubIdsAndCellularRequests() { - mVcnContext.ensureRunningOnLooperThread(); - - // Don't bother re-filing NetworkRequests if this Tracker has been torn down. - if (mIsQuitting) { - return; - } - - final Set<Integer> subIdsInSubGroup = mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup); - - // new subIds to track = (updated list of subIds) - (currently tracked subIds) - final Set<Integer> subIdsToRegister = new ArraySet<>(subIdsInSubGroup); - subIdsToRegister.removeAll(mCellBringupCallbacks.keySet()); - - // subIds to stop tracking = (currently tracked subIds) - (updated list of subIds) - final Set<Integer> subIdsToUnregister = new ArraySet<>(mCellBringupCallbacks.keySet()); - subIdsToUnregister.removeAll(subIdsInSubGroup); - - for (final int subId : subIdsToRegister) { - final NetworkBringupCallback cb = new NetworkBringupCallback(); - mCellBringupCallbacks.put(subId, cb); - - mConnectivityManager.requestBackgroundNetwork( - getCellNetworkRequestForSubId(subId), mHandler, cb); - } - - for (final int subId : subIdsToUnregister) { - final NetworkCallback cb = mCellBringupCallbacks.remove(subId); - mConnectivityManager.unregisterNetworkCallback(cb); - } + private NetworkRequest.Builder getBaseNetworkRequestBuilder() { + return new NetworkRequest.Builder() + .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) + .removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED) + .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) + .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED) + .setSubIds(mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup)); } /** @@ -217,22 +191,16 @@ public class UnderlyingNetworkTracker { Objects.requireNonNull(snapshot, "Missing snapshot"); mLastSnapshot = snapshot; - updateSubIdsAndCellularRequests(); + registerOrUpdateNetworkRequests(); } /** Tears down this Tracker, and releases all underlying network requests. */ public void teardown() { mVcnContext.ensureRunningOnLooperThread(); - - mConnectivityManager.unregisterNetworkCallback(mWifiBringupCallback); - mConnectivityManager.unregisterNetworkCallback(mRouteSelectionCallback); - - for (final NetworkCallback cb : mCellBringupCallbacks.values()) { - mConnectivityManager.unregisterNetworkCallback(cb); - } - mCellBringupCallbacks.clear(); - mIsQuitting = true; + + // Will unregister all existing callbacks, but not register new ones due to quitting flag. + registerOrUpdateNetworkRequests(); } /** Returns whether the currently selected Network matches the given network. */ @@ -290,25 +258,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 +315,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/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java index 29aedcea0cd2..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; @@ -301,10 +303,18 @@ public final class ProfcollectForwardingService extends SystemService { new Thread(() -> { try { - String reportPath = mIProfcollect.report(); + 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") @@ -316,9 +326,27 @@ public final class ProfcollectForwardingService extends SystemService { 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/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..7d6f4acfb7a0 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,19 @@ 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, + apk.toString()); // 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 +133,19 @@ 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, + apk.toString()); // 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 +165,19 @@ 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, + apk.toString()); // 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 +195,19 @@ 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, + apk.toString()); // 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 +226,36 @@ 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, + apk.toString()); // 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 +264,19 @@ 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, + COMPILATION_REASON, + COMPILER_FILTER, + ArtStatsLog.ART_DATUM_REPORTED__KIND__ART_DATUM_DEX2OAT_DEX_CODE_BYTES, + DEX_CONTENT.length, + dexMetadataType, + ArtStatsLog.ART_DATUM_REPORTED__APK_TYPE__ART_APK_TYPE_BASE, + INSTRUCTION_SET); inorder.verify(mockLogger).write( SESSION_ID, UID, @@ -247,7 +284,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/telecomm/java/Android.bp b/telecomm/java/Android.bp new file mode 100644 index 000000000000..3bd595352a55 --- /dev/null +++ b/telecomm/java/Android.bp @@ -0,0 +1,17 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], +} + +filegroup { + name: "framework-telecomm-sources", + srcs: [ + "**/*.java", + "**/*.aidl", + ], + visibility: ["//frameworks/base"], +} diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java index 973b20ad0713..ae5db3dfd4e4 100644 --- a/telecomm/java/android/telecom/Connection.java +++ b/telecomm/java/android/telecom/Connection.java @@ -1153,6 +1153,10 @@ public abstract class Connection extends Conferenceable { builder.append(isLong ? " PROPERTY_IS_ADHOC_CONFERENCE" : " adhoc_conf"); } + if ((properties & PROPERTY_IS_DOWNGRADED_CONFERENCE) == PROPERTY_IS_DOWNGRADED_CONFERENCE) { + builder.append(isLong ? " PROPERTY_IS_DOWNGRADED_CONFERENCE" : " dngrd_conf"); + } + builder.append("]"); return builder.toString(); } diff --git a/telephony/common/Android.bp b/telephony/common/Android.bp new file mode 100644 index 000000000000..201ab530fe86 --- /dev/null +++ b/telephony/common/Android.bp @@ -0,0 +1,29 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + default_applicable_licenses: ["frameworks_base_license"], +} + +filegroup { + name: "framework-telephony-common-sources", + srcs: [ + "**/*.java", + ":statslog-telephony-common-java-gen", + ], + visibility: [ + "//frameworks/base", + "//frameworks/base/tests/TelephonyCommonTests", + ], +} + +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", + out: ["com/android/internal/telephony/TelephonyCommonStatsLog.java"], + visibility: ["//visibility:private"], +} diff --git a/telephony/java/Android.bp b/telephony/java/Android.bp new file mode 100644 index 000000000000..3941b300206f --- /dev/null +++ b/telephony/java/Android.bp @@ -0,0 +1,18 @@ +package { + // See: http://go/android-license-faq + // A large-scale-change added 'default_applicable_licenses' to import + // all of the 'license_kinds' from "frameworks_base_license" + // to get the below license kinds: + // SPDX-license-identifier-Apache-2.0 + // SPDX-license-identifier-BSD + default_applicable_licenses: ["frameworks_base_license"], +} + +filegroup { + name: "framework-telephony-sources", + srcs: [ + "**/*.java", + "**/*.aidl", + ], + visibility: ["//frameworks/base"], +} diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index 0ba96a947a73..f027cd15e399 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 { @@ -4286,6 +4351,15 @@ public class CarrierConfigManager { */ public static final String KEY_HIDE_ENABLE_2G = "hide_enable_2g_bool"; + /** + * Determine whether or not to display no data notification when data setup is permanently + * failed. + * + * @hide + */ + public static final String KEY_DISPLAY_NO_DATA_NOTIFICATION_ON_PERMANENT_FAILURE_BOOL = + "display_no_data_notification_on_permanent_failure_bool"; + /** The default value for every variable. */ private final static PersistableBundle sDefaults; @@ -4823,6 +4897,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, @@ -4844,6 +4925,7 @@ public class CarrierConfigManager { new String[]{"ia", "default", "ims", "mms", "dun", "emergency"}); sDefaults.putBoolean(KEY_STORE_SIM_PIN_FOR_UNATTENDED_REBOOT_BOOL, true); sDefaults.putBoolean(KEY_HIDE_ENABLE_2G, false); + sDefaults.putBoolean(KEY_DISPLAY_NO_DATA_NOTIFICATION_ON_PERMANENT_FAILURE_BOOL, false); } /** diff --git a/telephony/java/android/telephony/PreciseDataConnectionState.java b/telephony/java/android/telephony/PreciseDataConnectionState.java index 9ea624b60988..ce2f3f924554 100644 --- a/telephony/java/android/telephony/PreciseDataConnectionState.java +++ b/telephony/java/android/telephony/PreciseDataConnectionState.java @@ -166,14 +166,12 @@ public final class PreciseDataConnectionState implements Parcelable { /** * @return The unique id of the data connection * - * Note this is the id assigned in {@link DataCallResponse}. + * Note this is the id assigned by the data service. * The id remains the same for data connection handover between * {@link AccessNetworkConstants#TRANSPORT_TYPE_WLAN} and * {@link AccessNetworkConstants#TRANSPORT_TYPE_WWAN} * - * @hide */ - @SystemApi public int getId() { return mId; } diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 7c39cf0b47a6..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); + } + })); } } diff --git a/telephony/java/android/telephony/ims/feature/RcsFeature.java b/telephony/java/android/telephony/ims/feature/RcsFeature.java index 6315b242184a..b384e50d9f03 100644 --- a/telephony/java/android/telephony/ims/feature/RcsFeature.java +++ b/telephony/java/android/telephony/ims/feature/RcsFeature.java @@ -391,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) { @@ -399,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/RcsCapabilityExchangeImplBase.java b/telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java index 25b9446152ac..a117adcfb99a 100644 --- a/telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java +++ b/telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java @@ -356,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) { @@ -371,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 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/integration/AndroidManifest.xml b/tests/net/integration/AndroidManifest.xml index f5a4234ede9e..db1850031ff5 100644 --- a/tests/net/integration/AndroidManifest.xml +++ b/tests/net/integration/AndroidManifest.xml @@ -37,6 +37,7 @@ <uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE"/> <!-- Reading DeviceConfig flags --> <uses-permission android:name="android.permission.READ_DEVICE_CONFIG"/> + <uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM"/> <application android:debuggable="true"> <uses-library android:name="android.test.runner"/> diff --git a/tests/net/java/android/net/ConnectivityManagerTest.java b/tests/net/java/android/net/ConnectivityManagerTest.java index 36f205b72a62..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; diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index 8938c1d08512..ad934204c4bd 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; @@ -31,6 +32,7 @@ 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; @@ -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; + } } /** @@ -1373,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); @@ -1571,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)); @@ -2438,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 */); } @@ -2447,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 */); } @@ -2455,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 */); } @@ -2799,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) @@ -3439,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() @@ -3474,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() @@ -3909,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); @@ -4069,8 +4199,7 @@ public class ConnectivityServiceTest { () -> 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); @@ -5391,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(); @@ -5443,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); @@ -5469,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); @@ -6461,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(); @@ -6954,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) @@ -7041,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) @@ -7277,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(); @@ -7284,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); @@ -7296,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); @@ -7314,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); @@ -7323,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); @@ -7332,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); @@ -7339,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); @@ -7346,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); @@ -7359,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); @@ -7491,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() @@ -7728,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(); @@ -7918,12 +8133,12 @@ public class ConnectivityServiceTest { assertExtraInfoFromCmPresent(mWiFiNetworkAgent); b1 = expectConnectivityAction(TYPE_WIFI, DetailedState.DISCONNECTED); + b2 = expectConnectivityAction(TYPE_VPN, DetailedState.DISCONNECTED); mWiFiNetworkAgent.disconnect(); callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent); systemDefaultCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent); b1.expectBroadcast(); callback.expectCapabilitiesThat(mMockVpn, nc -> !nc.hasTransport(TRANSPORT_WIFI)); - b2 = expectConnectivityAction(TYPE_VPN, DetailedState.DISCONNECTED); mMockVpn.expectStopVpnRunnerPrivileged(); callback.expectCallback(CallbackEntry.LOST, mMockVpn); b2.expectBroadcast(); @@ -8859,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, @@ -9116,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()) @@ -10435,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(); @@ -10446,8 +10659,7 @@ public class ConnectivityServiceTest { registerDefaultNetworkCallbackAsUid(mProfileDefaultNetworkCallback, TEST_WORK_PROFILE_APP_UID); // TODO: test using ConnectivityManager#registerDefaultNetworkCallbackAsUid as well. - mServiceContext.setPermission( - Manifest.permission.NETWORK_SETTINGS, PERMISSION_DENIED); + mServiceContext.setPermission(NETWORK_SETTINGS, PERMISSION_DENIED); } private void unregisterDefaultNetworkCallbacks() { @@ -10602,7 +10814,7 @@ public class ConnectivityServiceTest { defaultNetworkCallback.assertNoCallback(); final TestNetworkCallback otherUidDefaultCallback = new TestNetworkCallback(); - withPermission(Manifest.permission.NETWORK_SETTINGS, () -> + withPermission(NETWORK_SETTINGS, () -> mCm.registerDefaultNetworkCallbackAsUid(TEST_PACKAGE_UID, otherUidDefaultCallback, new Handler(ConnectivityThread.getInstanceLooper()))); @@ -10650,7 +10862,7 @@ public class ConnectivityServiceTest { defaultNetworkCallback.assertNoCallback(); final TestNetworkCallback otherUidDefaultCallback = new TestNetworkCallback(); - withPermission(Manifest.permission.NETWORK_SETTINGS, () -> + withPermission(NETWORK_SETTINGS, () -> mCm.registerDefaultNetworkCallbackAsUid(TEST_PACKAGE_UID, otherUidDefaultCallback, new Handler(ConnectivityThread.getInstanceLooper()))); @@ -10692,7 +10904,7 @@ public class ConnectivityServiceTest { defaultNetworkCallback.assertNoCallback(); final TestNetworkCallback otherUidDefaultCallback = new TestNetworkCallback(); - withPermission(Manifest.permission.NETWORK_SETTINGS, () -> + withPermission(NETWORK_SETTINGS, () -> mCm.registerDefaultNetworkCallbackAsUid(TEST_PACKAGE_UID, otherUidDefaultCallback, new Handler(ConnectivityThread.getInstanceLooper()))); 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/com/android/server/VcnManagementServiceTest.java b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java index f15d4204d125..c88b0c154712 100644 --- a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java +++ b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java @@ -34,8 +34,8 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.any; import static org.mockito.Mockito.argThat; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doNothing; @@ -45,7 +45,6 @@ import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; import android.annotation.NonNull; import android.app.AppOpsManager; @@ -63,7 +62,6 @@ import android.net.vcn.VcnConfig; import android.net.vcn.VcnConfigTest; import android.net.vcn.VcnManager; import android.net.vcn.VcnUnderlyingNetworkPolicy; -import android.net.wifi.WifiInfo; import android.os.IBinder; import android.os.ParcelUuid; import android.os.PersistableBundle; @@ -708,22 +706,12 @@ public class VcnManagementServiceTest { int subId, ParcelUuid subGrp, boolean isVcnActive, int transport) { setupSubscriptionAndStartVcn(subId, subGrp, isVcnActive); - final NetworkCapabilities.Builder ncBuilder = new NetworkCapabilities.Builder(); - ncBuilder.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED); - if (transport == TRANSPORT_CELLULAR) { - ncBuilder - .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) - .setNetworkSpecifier(new TelephonyNetworkSpecifier(TEST_SUBSCRIPTION_ID)); - } else if (transport == TRANSPORT_WIFI) { - WifiInfo wifiInfo = mock(WifiInfo.class); - when(wifiInfo.makeCopy(anyLong())).thenReturn(wifiInfo); - when(mMockDeps.getSubIdForWifiInfo(eq(wifiInfo))).thenReturn(TEST_SUBSCRIPTION_ID); - - ncBuilder - .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) - .setTransportInfo(wifiInfo); - } else { - throw new IllegalArgumentException("Unknown transport"); + final NetworkCapabilities.Builder ncBuilder = + new NetworkCapabilities.Builder() + .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED) + .addTransportType(transport); + if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) { + ncBuilder.setSubIds(Collections.singleton(subId)); } return mVcnMgmtSvc.getUnderlyingNetworkPolicy(ncBuilder.build(), new LinkProperties()); diff --git a/tests/vcn/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java b/tests/vcn/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java index 1ef1a61f17ea..ed2e4d9b9946 100644 --- a/tests/vcn/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java +++ b/tests/vcn/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java @@ -146,40 +146,34 @@ public class UnderlyingNetworkTrackerTest { @Test public void testNetworkCallbacksRegisteredOnStartup() { - // verify NetworkCallbacks registered when instantiated - verify(mConnectivityManager) - .requestBackgroundNetwork( - eq(getWifiRequest()), - any(), - any(NetworkBringupCallback.class)); - verifyBackgroundCellRequests(mSubscriptionSnapshot, SUB_GROUP, INITIAL_SUB_IDS); + verifyNetworkRequestsRegistered(INITIAL_SUB_IDS); + } + private void verifyNetworkRequestsRegistered(Set<Integer> expectedSubIds) { verify(mConnectivityManager) .requestBackgroundNetwork( - eq(getRouteSelectionRequest()), + eq(getWifiRequest(expectedSubIds)), any(), - any(RouteSelectionCallback.class)); - } - - private void verifyBackgroundCellRequests( - TelephonySubscriptionSnapshot snapshot, - ParcelUuid subGroup, - Set<Integer> expectedSubIds) { - verify(snapshot).getAllSubIdsInGroup(eq(subGroup)); - + any(NetworkBringupCallback.class)); for (final int subId : expectedSubIds) { verify(mConnectivityManager) .requestBackgroundNetwork( - eq(getCellRequestForSubId(subId)), + eq(getCellRequestForSubId(subId, expectedSubIds)), any(), any(NetworkBringupCallback.class)); } + + verify(mConnectivityManager) + .requestBackgroundNetwork( + eq(getRouteSelectionRequest(expectedSubIds)), + any(), + any(RouteSelectionCallback.class)); } @Test public void testUpdateSubscriptionSnapshot() { // Verify initial cell background requests filed - verifyBackgroundCellRequests(mSubscriptionSnapshot, SUB_GROUP, INITIAL_SUB_IDS); + verifyNetworkRequestsRegistered(INITIAL_SUB_IDS); TelephonySubscriptionSnapshot subscriptionUpdate = mock(TelephonySubscriptionSnapshot.class); @@ -187,40 +181,38 @@ public class UnderlyingNetworkTrackerTest { mUnderlyingNetworkTracker.updateSubscriptionSnapshot(subscriptionUpdate); - // verify that initially-filed bringup requests are unregistered - verify(mConnectivityManager, times(INITIAL_SUB_IDS.size())) + // verify that initially-filed bringup requests are unregistered (cell + wifi) + verify(mConnectivityManager, times(INITIAL_SUB_IDS.size() + 1)) .unregisterNetworkCallback(any(NetworkBringupCallback.class)); - verifyBackgroundCellRequests(subscriptionUpdate, SUB_GROUP, UPDATED_SUB_IDS); + verify(mConnectivityManager).unregisterNetworkCallback(any(RouteSelectionCallback.class)); + verifyNetworkRequestsRegistered(UPDATED_SUB_IDS); } - private NetworkRequest getWifiRequest() { - return getExpectedRequestBase(true) + private NetworkRequest getWifiRequest(Set<Integer> netCapsSubIds) { + return getExpectedRequestBase(netCapsSubIds) .addTransportType(NetworkCapabilities.TRANSPORT_WIFI) .build(); } - private NetworkRequest getCellRequestForSubId(int subId) { - return getExpectedRequestBase(false) + private NetworkRequest getCellRequestForSubId(int subId, Set<Integer> netCapsSubIds) { + return getExpectedRequestBase(netCapsSubIds) .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR) .setNetworkSpecifier(new TelephonyNetworkSpecifier(subId)) .build(); } - private NetworkRequest getRouteSelectionRequest() { - return getExpectedRequestBase(true).build(); + private NetworkRequest getRouteSelectionRequest(Set<Integer> netCapsSubIds) { + return getExpectedRequestBase(netCapsSubIds).build(); } - private NetworkRequest.Builder getExpectedRequestBase(boolean requireVcnManaged) { + private NetworkRequest.Builder getExpectedRequestBase(Set<Integer> subIds) { final NetworkRequest.Builder builder = new NetworkRequest.Builder() .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) .removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED) .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) - .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED); - - if (requireVcnManaged) { - builder.addUnwantedCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED); - } + .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED) + .setSubIds(subIds); return builder; } @@ -274,7 +266,7 @@ public class UnderlyingNetworkTrackerTest { NetworkCapabilities networkCapabilities) { verify(mConnectivityManager) .requestBackgroundNetwork( - eq(getRouteSelectionRequest()), + eq(getRouteSelectionRequest(INITIAL_SUB_IDS)), any(), mRouteSelectionCallbackCaptor.capture()); @@ -328,7 +320,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 +328,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 +340,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 +348,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/tools/fonts/fontchain_linter.py b/tools/fonts/fontchain_linter.py index 7de706502618..a4a315b7e371 100755 --- a/tools/fonts/fontchain_linter.py +++ b/tools/fonts/fontchain_linter.py @@ -11,12 +11,6 @@ from fontTools import ttLib EMOJI_VS = 0xFE0F -#TODO(179952916): Rename CutiveMono and DancingScript -CANONICAL_NAME_EXCEPTION_LIST = [ - 'CutiveMono.ttf', - 'DancingScript-Regular.ttf', -] - LANG_TO_SCRIPT = { 'as': 'Beng', 'be': 'Cyrl', @@ -664,53 +658,6 @@ def check_cjk_punctuation(): assert_font_supports_none_of_chars(record.font, cjk_punctuation, name) -def getPostScriptName(font): - ttf = open_font(font) - nameTable = ttf['name'] - for name in nameTable.names: - if name.nameID == 6 and name.platformID == 3 and name.platEncID == 1 and name.langID == 0x0409: - return str(name) - - -def getSuffix(font): - file_path, index = font - with open(path.join(_fonts_dir, file_path), 'rb') as f: - tag = f.read(4) - isCollection = tag == b'ttcf' - - ttf = open_font(font) - isType1 = ('CFF ' in ttf or 'CFF2' in ttf) - - if isType1: - if isCollection: - return '.otc' - else: - return '.otf' - else: - if isCollection: - return '.ttc' - else: - return '.ttf' - - -def check_canonical_name(): - for record in _all_fonts: - file_name, index = record.font - if file_name in CANONICAL_NAME_EXCEPTION_LIST: - continue - - if index and index != 0: - continue - - psName = getPostScriptName(record.font) - assert psName, 'PostScript must be defined' - - suffix = getSuffix(record.font) - canonicalName = '%s%s' % (psName, suffix) - - assert file_name == canonicalName, ( - '%s is not a canonical name. Must be %s' % (file_name, canonicalName)) - def main(): global _fonts_dir target_out = sys.argv[1] @@ -728,8 +675,6 @@ def main(): check_cjk_punctuation() - check_canonical_name() - check_emoji = sys.argv[2] if check_emoji == 'true': ucd_path = sys.argv[3] |