Merge "Grant OVERRIDE_COMPAT_CHANGE_CONFIG_ON_RELEASE_BUILD to Shell"
diff --git a/Android.bp b/Android.bp
index 4709323..0b0a9b7 100644
--- a/Android.bp
+++ b/Android.bp
@@ -64,278 +64,13 @@
}
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",
@@ -377,12 +112,12 @@
":gsiservice_aidl",
":incidentcompanion_aidl",
":installd_aidl",
- ":keystore_aidl",
":libaudioclient_aidl",
":libbinder_aidl",
":libbluetooth-binder-aidl",
":libcamera_client_aidl",
":libcamera_client_framework_aidl",
+ ":packagemanager_aidl",
":libupdate_engine_aidl",
":resourcemanager_aidl",
":storaged_aidl",
@@ -398,22 +133,6 @@
],
}
-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 +172,6 @@
],
}
-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 {
@@ -586,8 +296,6 @@
":framework-connectivity-sources",
"core/java/**/*.logtags",
],
- // See comment on framework-atb-backward-compatibility module below
- exclude_srcs: ["core/java/android/content/pm/AndroidTestBaseUpdater.java"],
aidl: {
generate_get_transaction_name: true,
},
@@ -668,20 +376,6 @@
src: ":framework-minus-apex",
}
-// A temporary build target that is conditionally included on the bootclasspath if
-// android.test.base library has been removed and which provides support for
-// maintaining backwards compatibility for APKs that target pre-P and depend on
-// android.test.base classes. This is used iff REMOVE_ATB_FROM_BCP=true is
-// specified on the build command line.
-java_library {
- name: "framework-atb-backward-compatibility",
- installable: true,
- libs: ["app-compat-annotations"],
- srcs: [
- "core/java/android/content/pm/AndroidTestBaseUpdater.java",
- ],
-}
-
genrule {
name: "statslog-framework-java-gen",
tools: ["stats-log-api-gen"],
@@ -763,13 +457,21 @@
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 +480,11 @@
"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 +498,6 @@
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",
@@ -821,7 +523,6 @@
"core/java/com/android/internal/util/RingBufferIndices.java",
"core/java/com/android/internal/util/State.java",
"core/java/com/android/internal/util/StateMachine.java",
- "core/java/com/android/internal/util/TrafficStatsConstants.java",
"core/java/com/android/internal/util/WakeupMessage.java",
"core/java/com/android/internal/util/TokenBucket.java",
],
@@ -847,7 +548,6 @@
"core/java/com/android/internal/util/MessageUtils.java",
"core/java/com/android/internal/util/State.java",
"core/java/com/android/internal/util/StateMachine.java",
- "core/java/com/android/internal/util/TrafficStatsConstants.java",
"core/java/com/android/internal/util/WakeupMessage.java",
],
}
@@ -1069,6 +769,14 @@
path: "core/java",
}
+filegroup {
+ name: "activity_manager_procstate_aidl",
+ srcs: [
+ // internal only
+ ],
+ path: "core/java",
+}
+
aidl_interface {
name: "libincremental_aidl",
unstable: true,
@@ -1148,38 +856,6 @@
},
}
-// TODO(b/77285514): remove this once the last few hidl interfaces have been
-// updated to use hwbinder.stubs.
-java_library {
- name: "hwbinder",
- sdk_version: "core_platform",
-
- srcs: [
- "core/java/android/os/HidlSupport.java",
- "core/java/android/annotation/IntDef.java",
- "core/java/android/annotation/IntRange.java",
- "core/java/android/annotation/NonNull.java",
- "core/java/android/annotation/Nullable.java",
- "core/java/android/annotation/SystemApi.java",
- "core/java/android/annotation/TestApi.java",
- "core/java/android/os/HidlMemory.java",
- "core/java/android/os/HwBinder.java",
- "core/java/android/os/HwBlob.java",
- "core/java/android/os/HwParcel.java",
- "core/java/android/os/IHwBinder.java",
- "core/java/android/os/IHwInterface.java",
- "core/java/android/os/DeadObjectException.java",
- "core/java/android/os/DeadSystemException.java",
- "core/java/android/os/NativeHandle.java",
- "core/java/android/os/RemoteException.java",
- "core/java/android/util/AndroidException.java",
- ],
- libs: ["unsupportedappusage"],
-
- dxflags: ["--core-library"],
- installable: false,
-}
-
python_defaults {
name: "base_default",
version: {
@@ -1206,36 +882,6 @@
],
}
-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 +1003,19 @@
"--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 ada80bb..d3bef7f 100644
--- a/ApiDocs.bp
+++ b/ApiDocs.bp
@@ -58,16 +58,24 @@
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 fd614a7e3..1644a55 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -42,13 +42,7 @@
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 @@
"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 @@
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 2f5f555..26010ef6 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 @@
/**
* 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 @@
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 4f472df..5487e87 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 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 @@
}
}
+ 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 @@
}
// 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 {
@@ -684,13 +693,6 @@
StateControllerProto.ConnectivityController.REQUESTED_STANDBY_EXCEPTION_UIDS,
mRequestedWhitelistJobs.keyAt(i));
}
- for (int i = 0; i < mAvailableNetworks.size(); i++) {
- Network network = mAvailableNetworks.keyAt(i);
- if (network != null) {
- network.dumpDebug(proto,
- StateControllerProto.ConnectivityController.AVAILABLE_NETWORKS);
- }
- }
for (int i = 0; i < mTrackedJobs.size(); i++) {
final ArraySet<JobStatus> jobs = mTrackedJobs.valueAt(i);
for (int j = 0; j < jobs.size(); j++) {
@@ -704,12 +706,6 @@
StateControllerProto.ConnectivityController.TrackedJob.INFO);
proto.write(StateControllerProto.ConnectivityController.TrackedJob.SOURCE_UID,
js.getSourceUid());
- NetworkRequest rn = js.getJob().getRequiredNetwork();
- if (rn != null) {
- rn.dumpDebug(proto,
- StateControllerProto.ConnectivityController.TrackedJob
- .REQUIRED_NETWORK);
- }
proto.end(jsToken);
}
}
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
index ea8e7bc..a346812 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/JobStatus.java
@@ -1911,9 +1911,6 @@
if (uriPerms != null) {
uriPerms.dump(proto, JobStatusDumpProto.JobInfo.GRANTED_URI_PERMISSIONS);
}
- if (job.getRequiredNetwork() != null) {
- job.getRequiredNetwork().dumpDebug(proto, JobStatusDumpProto.JobInfo.REQUIRED_NETWORK);
- }
if (mTotalNetworkDownloadBytes != JobInfo.NETWORK_BYTES_UNKNOWN) {
proto.write(JobStatusDumpProto.JobInfo.TOTAL_NETWORK_DOWNLOAD_BYTES,
mTotalNetworkDownloadBytes);
@@ -2002,10 +1999,6 @@
}
}
- if (network != null) {
- network.dumpDebug(proto, JobStatusDumpProto.NETWORK);
- }
-
if (pendingWork != null) {
for (int i = 0; i < pendingWork.size(); i++) {
dumpJobWorkItem(proto, JobStatusDumpProto.PENDING_WORK, pendingWork.get(i));
diff --git a/apex/media/framework/Android.bp b/apex/media/framework/Android.bp
index 3dd0da7..0501a45 100644
--- a/apex/media/framework/Android.bp
+++ b/apex/media/framework/Android.bp
@@ -41,9 +41,7 @@
installable: true,
sdk_version: "module_current",
- libs: [
- "framework_media_annotation",
- ],
+ libs: ["framework-annotations-lib"],
static_libs: [
"exoplayer2-extractor"
],
@@ -107,20 +105,9 @@
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/api/dump_api_shas.sh b/api/dump_api_shas.sh
new file mode 100755
index 0000000..c023b31
--- /dev/null
+++ b/api/dump_api_shas.sh
@@ -0,0 +1,56 @@
+#!/bin/bash -e
+# This script dumps the git SHAs of all commits inside api tracking directories.
+# It can used by tools wanting to track API changes, and the primary original
+# purpose is to verify verify all API change SHAs have been tracked by the
+# server-side API-council tools.
+#
+# The only argument is used to specify a git commit range to filter by.
+#
+# Example invocation (API changes between O and P):
+# frameworks/base/api/dump_api_shas.sh origin/oreo-dev..origin/pie-dev
+
+set -o pipefail
+
+eecho() { echo $@ >&2 ; }
+
+if [[ $1 == *..* ]]; then
+ exclude=${1/..*}
+ include=${1/*..}
+else
+ eecho No range or invalid range specified, defaulting to all commits from HEAD.
+ exclude=
+ include=HEAD
+fi
+
+eecho -n building queryview...
+{ source build/envsetup.sh && lunch aosp_arm && m queryview; } >/dev/null 2>&1 \
+ || { eecho failed; exit 1; }
+eecho "done"
+
+# This finds the directories where the dependant java_sdk_libs are defined
+bpdirs=$(
+ bazel query --config=queryview --output=package \
+ 'kind(java_sdk_library, deps(//frameworks/base/api/..., 1))' 2>/dev/null
+ echo frameworks/base/core/api # Not a java_sdk_library.
+ echo frameworks/base/services/api # Not a java_sdk_library.
+)
+
+# Find relevant api subdirectories
+apidirs=$(
+ find $bpdirs -type f -name '*current.txt' -path '*/api/*' \
+ | xargs realpath --relative-to=$(pwd) | xargs dirname | sort | uniq
+)
+
+# Dump sorted SHAs of commits in these directories
+{ for d in $apidirs; do
+ ( cd $d
+ eecho inspecting $d
+ exclude_arg=$(test -n "$exclude" && {
+ git rev-parse -q --verify $exclude > /dev/null && echo "--not $exclude" \
+ || eecho "$d has no revision $exclude, including all commits"; } || true)
+ for f in $(find . -name '*current.txt'); do
+ git --no-pager log --pretty=format:%H --no-merges --follow $include $exclude_arg -- $f
+ echo # No trailing newline with --no-pager
+ done
+ )
+done; } | sort | uniq
diff --git a/boot/Android.bp b/boot/Android.bp
index 4f7c44e..71edea2 100644
--- a/boot/Android.bp
+++ b/boot/Android.bp
@@ -23,7 +23,24 @@
default_applicable_licenses: ["frameworks_base_license"],
}
-boot_image {
- name: "framework-boot-image",
- image_name: "boot",
+// This module provides access to information Soong has related to the
+// whole platform bootclasspath. Currently, that information is provided solely
+// through configuration but additional information will be added here.
+//
+// This will provide support for the following:
+// * Hidden API processing for those parts of the bootclasspath that are not
+// part of an APEX.
+// * Compatibility checking to ensure that the hidden API bits encoded into the
+// dex files by the modularized hidden API processing is compatible with the
+// runtimes of earlier releases which expect the bits to have been computed
+// over the entirety of the bootclasspath in one go not separately.
+// * Dexpreopting apps and other libraries not on the platform bootclasspath.
+// * Generating and installing the appropriate files to the device which will
+// allow it to generate the bootclasspath related environment variables
+// dynamically.
+//
+// This module needs to be present in the build for the above processing to be
+// done correctly.
+platform_bootclasspath {
+ name: "platform-bootclasspath",
}
diff --git a/boot/OWNERS b/boot/OWNERS
new file mode 100644
index 0000000..0648888
--- /dev/null
+++ b/boot/OWNERS
@@ -0,0 +1,2 @@
+# soong-team@ as the platform_bootclasspath module is tightly coupled with Soong
+file:platform/build/soong:/OWNERS
diff --git a/boot/hiddenapi/OWNERS b/boot/hiddenapi/OWNERS
new file mode 100644
index 0000000..5d869fc
--- /dev/null
+++ b/boot/hiddenapi/OWNERS
@@ -0,0 +1,7 @@
+# compat-team@ for changes to hiddenapi files
+andreionea@google.com
+mathewi@google.com
+satayev@google.com
+
+# Escalations:
+per-file hiddenapi-* = bdc@google.com, narayan@google.com
diff --git a/config/hiddenapi-force-blocked.txt b/boot/hiddenapi/hiddenapi-force-blocked.txt
similarity index 100%
rename from config/hiddenapi-force-blocked.txt
rename to boot/hiddenapi/hiddenapi-force-blocked.txt
diff --git a/config/hiddenapi-max-target-o.txt b/boot/hiddenapi/hiddenapi-max-target-o.txt
similarity index 100%
rename from config/hiddenapi-max-target-o.txt
rename to boot/hiddenapi/hiddenapi-max-target-o.txt
diff --git a/config/hiddenapi-max-target-p.txt b/boot/hiddenapi/hiddenapi-max-target-p.txt
similarity index 100%
rename from config/hiddenapi-max-target-p.txt
rename to boot/hiddenapi/hiddenapi-max-target-p.txt
diff --git a/config/hiddenapi-max-target-q.txt b/boot/hiddenapi/hiddenapi-max-target-q.txt
similarity index 100%
rename from config/hiddenapi-max-target-q.txt
rename to boot/hiddenapi/hiddenapi-max-target-q.txt
diff --git a/config/hiddenapi-max-target-r-loprio.txt b/boot/hiddenapi/hiddenapi-max-target-r-loprio.txt
similarity index 100%
rename from config/hiddenapi-max-target-r-loprio.txt
rename to boot/hiddenapi/hiddenapi-max-target-r-loprio.txt
diff --git a/config/hiddenapi-unsupported-packages.txt b/boot/hiddenapi/hiddenapi-unsupported-packages.txt
similarity index 100%
rename from config/hiddenapi-unsupported-packages.txt
rename to boot/hiddenapi/hiddenapi-unsupported-packages.txt
diff --git a/config/hiddenapi-unsupported.txt b/boot/hiddenapi/hiddenapi-unsupported.txt
similarity index 99%
rename from config/hiddenapi-unsupported.txt
rename to boot/hiddenapi/hiddenapi-unsupported.txt
index 8a377ac..48a9782 100644
--- a/config/hiddenapi-unsupported.txt
+++ b/boot/hiddenapi/hiddenapi-unsupported.txt
@@ -209,7 +209,6 @@
Landroid/os/storage/IStorageManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/os/storage/IStorageManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/os/storage/IStorageManager;
Landroid/security/IKeyChainService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/security/IKeyChainService;
-Landroid/security/keystore/IKeystoreService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/security/keystore/IKeystoreService;
Landroid/service/dreams/IDreamManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/service/dreams/IDreamManager;
Landroid/service/notification/INotificationListener$Stub;-><init>()V
Landroid/service/persistentdata/IPersistentDataBlockService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/service/persistentdata/IPersistentDataBlockService;
diff --git a/core/api/current.txt b/core/api/current.txt
index 6b137ea..5a2b8bd 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -12139,6 +12139,7 @@
field public static final String FEATURE_FINGERPRINT = "android.hardware.fingerprint";
field public static final String FEATURE_FREEFORM_WINDOW_MANAGEMENT = "android.software.freeform_window_management";
field public static final String FEATURE_GAMEPAD = "android.hardware.gamepad";
+ field public static final String FEATURE_HARDWARE_KEYSTORE = "android.hardware.hardware_keystore";
field public static final String FEATURE_HIFI_SENSORS = "android.hardware.sensor.hifi_sensors";
field public static final String FEATURE_HOME_SCREEN = "android.software.home_screen";
field public static final String FEATURE_IDENTITY_CREDENTIAL_HARDWARE = "android.hardware.identity_credential";
@@ -25702,12 +25703,13 @@
public final class VcnGatewayConnectionConfig {
method @NonNull public int[] getExposedCapabilities();
+ method @NonNull public String getGatewayConnectionName();
method @IntRange(from=android.net.vcn.VcnGatewayConnectionConfig.MIN_MTU_V6) public int getMaxMtu();
method @NonNull public long[] getRetryInterval();
}
public static final class VcnGatewayConnectionConfig.Builder {
- ctor public VcnGatewayConnectionConfig.Builder(@NonNull android.net.vcn.VcnControlPlaneConfig);
+ ctor public VcnGatewayConnectionConfig.Builder(@NonNull String, @NonNull android.net.vcn.VcnControlPlaneConfig);
method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder addExposedCapability(int);
method @NonNull public android.net.vcn.VcnGatewayConnectionConfig build();
method @NonNull public android.net.vcn.VcnGatewayConnectionConfig.Builder removeExposedCapability(int);
@@ -25731,7 +25733,7 @@
public abstract static class VcnManager.VcnStatusCallback {
ctor public VcnManager.VcnStatusCallback();
- method public abstract void onGatewayConnectionError(@NonNull int[], int, @Nullable Throwable);
+ method public abstract void onGatewayConnectionError(@NonNull String, int, @Nullable Throwable);
method public abstract void onStatusChanged(int);
}
@@ -33996,8 +33998,8 @@
public static final class SimPhonebookContract.SimRecords {
method @NonNull public static android.net.Uri getContentUri(int, int);
- method @WorkerThread public static int getEncodedNameLength(@NonNull android.content.ContentResolver, @NonNull String);
- method @NonNull public static android.net.Uri getItemUri(int, int, int);
+ method @IntRange(from=0) @WorkerThread public static int getEncodedNameLength(@NonNull android.content.ContentResolver, @NonNull String);
+ method @NonNull public static android.net.Uri getItemUri(int, int, @IntRange(from=1) int);
field public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/sim-contact_v2";
field public static final String CONTENT_TYPE = "vnd.android.cursor.dir/sim-contact_v2";
field public static final String ELEMENTARY_FILE_TYPE = "elementary_file_type";
@@ -40411,6 +40413,7 @@
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();
@@ -41366,6 +41369,7 @@
field public static final int PROTOCOL_NON_IP = 4; // 0x4
field public static final int PROTOCOL_PPP = 3; // 0x3
field public static final int PROTOCOL_UNSTRUCTURED = 5; // 0x5
+ field public static final int TYPE_BIP = 8192; // 0x2000
field public static final int TYPE_CBS = 128; // 0x80
field public static final int TYPE_DEFAULT = 17; // 0x11
field public static final int TYPE_DUN = 8; // 0x8
@@ -41377,6 +41381,7 @@
field public static final int TYPE_MCX = 1024; // 0x400
field public static final int TYPE_MMS = 2; // 0x2
field public static final int TYPE_SUPL = 4; // 0x4
+ field public static final int TYPE_VSIM = 4096; // 0x1000
field public static final int TYPE_XCAP = 2048; // 0x800
}
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index ee53be5..e9dba8e 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -23,13 +23,10 @@
package android.content {
public abstract class Context {
+ field public static final String PAC_PROXY_SERVICE = "pac_proxy";
field public static final String TEST_NETWORK_SERVICE = "test_network";
}
- public class Intent implements java.lang.Cloneable android.os.Parcelable {
- field public static final String ACTION_CLEAR_DNS_CACHE = "android.intent.action.CLEAR_DNS_CACHE";
- }
-
}
package android.net {
@@ -50,7 +47,6 @@
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 4676523..f31cd63 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -155,6 +155,7 @@
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 @@
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,14 +6726,20 @@
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.NFC_SET_CONTROLLER_ALWAYS_ON) public void registerControllerAlwaysOnStateCallback(@NonNull java.util.concurrent.Executor, @NonNull android.nfc.NfcAdapter.ControllerAlwaysOnStateCallback);
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);
+ method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public void unregisterControllerAlwaysOnStateCallback(@NonNull android.nfc.NfcAdapter.ControllerAlwaysOnStateCallback);
field public static final int FLAG_NDEF_PUSH_NO_CONFIRM = 1; // 0x1
}
+ public static interface NfcAdapter.ControllerAlwaysOnStateCallback {
+ method public void onStateChanged(boolean);
+ }
+
public static interface NfcAdapter.NfcUnlockHandler {
method public boolean onUnlockAttempted(android.nfc.Tag);
}
@@ -9431,7 +9440,14 @@
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 +9801,6 @@
method @Deprecated public int getDataConnectionApnTypeBitMask();
method @Deprecated public int getDataConnectionFailCause();
method @Deprecated public int getDataConnectionState();
- method public int getId();
}
public final class PreciseDisconnectCause {
@@ -10542,6 +10557,7 @@
method public static int getApnTypeInt(@NonNull String);
method @NonNull public static String getApnTypeString(int);
field public static final String TYPE_ALL_STRING = "*";
+ field public static final String TYPE_BIP_STRING = "bip";
field public static final String TYPE_CBS_STRING = "cbs";
field public static final String TYPE_DEFAULT_STRING = "default";
field public static final String TYPE_DUN_STRING = "dun";
@@ -10553,6 +10569,7 @@
field public static final String TYPE_MCX_STRING = "mcx";
field public static final String TYPE_MMS_STRING = "mms";
field public static final String TYPE_SUPL_STRING = "supl";
+ field public static final String TYPE_VSIM_STRING = "vsim";
field public static final String TYPE_XCAP_STRING = "xcap";
}
@@ -11974,10 +11991,11 @@
method public int describeContents();
method @Nullable public String getCallIdParameter();
method @NonNull public byte[] getContent();
- method @NonNull public byte[] getEncodedMessage();
+ method @Deprecated @NonNull public byte[] getEncodedMessage();
method @NonNull public String getHeaderSection();
method @NonNull public String getStartLine();
- method @Nullable public String getViaBranchParameter();
+ method @NonNull public String getViaBranchParameter();
+ method @NonNull public byte[] toEncodedMessage();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.SipMessage> CREATOR;
}
@@ -12066,13 +12084,13 @@
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 +12302,7 @@
}
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);
@@ -12481,7 +12499,7 @@
public final class DistanceMeasurement implements android.os.Parcelable {
method public int describeContents();
method @FloatRange(from=0.0, to=1.0) public double getConfidenceLevel();
- method public double getErrorMeters();
+ method @FloatRange(from=0.0) public double getErrorMeters();
method public double getMeters();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.uwb.DistanceMeasurement> CREATOR;
@@ -12490,8 +12508,8 @@
public static final class DistanceMeasurement.Builder {
ctor public DistanceMeasurement.Builder();
method @NonNull public android.uwb.DistanceMeasurement build();
- method @NonNull public android.uwb.DistanceMeasurement.Builder setConfidenceLevel(double);
- method @NonNull public android.uwb.DistanceMeasurement.Builder setErrorMeters(double);
+ method @NonNull public android.uwb.DistanceMeasurement.Builder setConfidenceLevel(@FloatRange(from=0.0, to=1.0) double);
+ method @NonNull public android.uwb.DistanceMeasurement.Builder setErrorMeters(@FloatRange(from=0.0) double);
method @NonNull public android.uwb.DistanceMeasurement.Builder setMeters(double);
}
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 1d094c3..0c57f4e 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -9,8 +9,10 @@
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 @@
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 @@
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 2fdf9c1..919f1e2 100644
--- a/core/java/Android.bp
+++ b/core/java/Android.bp
@@ -10,6 +10,15 @@
}
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 @@
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 556fdb4..a070246 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.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 @@
* </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/Context.java b/core/java/android/content/Context.java
index fe9ed27..4293ab0 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -4026,6 +4026,7 @@
* @see android.net.PacProxyManager
* @hide
*/
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static final String PAC_PROXY_SERVICE = "pac_proxy";
/**
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 4d68e90..0fad63f 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2324,14 +2324,6 @@
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_TIMEZONE_CHANGED = "android.intent.action.TIMEZONE_CHANGED";
/**
- * Clear DNS Cache Action: This is broadcast when networks have changed and old
- * DNS entries should be tossed.
- * @hide
- */
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
- public static final String ACTION_CLEAR_DNS_CACHE = "android.intent.action.CLEAR_DNS_CACHE";
- /**
* Alarm Changed Action: This is broadcast when the AlarmClock
* application's alarm is set or unset. It is used by the
* AlarmClock application and the StatusBar service.
diff --git a/core/java/android/content/OWNERS b/core/java/android/content/OWNERS
index 01b554a..1735aa2 100644
--- a/core/java/android/content/OWNERS
+++ b/core/java/android/content/OWNERS
@@ -5,6 +5,7 @@
per-file IntentFilter.java = patb@google.com
per-file Intent.java = toddke@google.com
per-file Intent.java = patb@google.com
+per-file Intent.java = file:/services/core/java/com/android/server/wm/OWNERS
per-file AutofillOptions* = file:/core/java/android/service/autofill/OWNERS
per-file ContentCaptureOptions* = file:/core/java/android/service/contentcapture/OWNERS
per-file LocusId* = file:/core/java/android/service/contentcapture/OWNERS
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 6ec1169..ad9e31b 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -2167,7 +2167,10 @@
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 @@
return (flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0;
}
- /** @hide */
+ /**
+ * True if the application is pre-installed on the vendor partition of the system image.
+ * @hide
+ */
@SystemApi
public boolean isVendor() {
return (privateFlags & ApplicationInfo.PRIVATE_FLAG_VENDOR) != 0;
}
- /** @hide */
+ /**
+ * True if the application is pre-installed on the product partition of the system image.
+ * @hide
+ */
@SystemApi
public boolean isProduct() {
return (privateFlags & ApplicationInfo.PRIVATE_FLAG_PRODUCT) != 0;
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 7e17256..23f5e3a 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -3167,8 +3167,57 @@
public static final String FEATURE_VR_HEADTRACKING = "android.hardware.vr.headtracking";
/**
- * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}:
- * The device has a StrongBox hardware-backed Keystore.
+ * Feature for {@link #getSystemAvailableFeatures} and
+ * {@link #hasSystemFeature(String, int)}: If this feature is supported, the device implements
+ * the Android Keystore backed by an isolated execution environment. The version indicates
+ * which features are implemented in the isolated execution environment:
+ * <ul>
+ * <li>100: Hardware support for ECDH (see {@link javax.crypto.KeyAgreement}) and support
+ * for app-generated attestation keys (see {@link
+ * android.security.keystore.KeyGenParameterSpec.Builder#setAttestKeyAlias(String)}).
+ * <li>41: Hardware enforcement of device-unlocked keys (see {@link
+ * android.security.keystore.KeyGenParameterSpec.Builder#setUnlockedDeviceRequired(boolean)}).
+ * <li>40: Support for wrapped key import (see {@link
+ * android.security.keystore.WrappedKeyEntry}), optional support for ID attestation (see {@link
+ * android.security.keystore.KeyGenParameterSpec.Builder#setDevicePropertiesAttestationIncluded(boolean)}),
+ * attestation (see {@link
+ * android.security.keystore.KeyGenParameterSpec.Builder#setAttestationChallenge(byte[])}),
+ * AES, HMAC, ECDSA and RSA support where the secret or private key never leaves secure
+ * hardware, and support for requiring user authentication before a key can be used.
+ * </ul>
+ * This feature version is guaranteed to be set for all devices launching with Android 12 and
+ * may be set on devices launching with an earlier version. If the feature version is set, it
+ * will at least have the value 40. If it's not set the device may have a version of
+ * hardware-backed keystore but it may not support all features listed above.
+ */
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_HARDWARE_KEYSTORE = "android.hardware.hardware_keystore";
+
+ /**
+ * Feature for {@link #getSystemAvailableFeatures}, {@link #hasSystemFeature(String)}, and
+ * {@link #hasSystemFeature(String, int)}: If this feature is supported, the device implements
+ * the Android Keystore backed by a dedicated secure processor referred to as
+ * <a href="https://source.android.com/security/best-practices/hardware#strongbox-keymaster">
+ * StrongBox</a>. If this feature has a version, the version number indicates which features are
+ * implemented in StrongBox:
+ * <ul>
+ * <li>100: Hardware support for ECDH (see {@link javax.crypto.KeyAgreement}) and support
+ * for app-generated attestation keys (see {@link
+ * android.security.keystore.KeyGenParameterSpec.Builder#setAttestKeyAlias(String)}).
+ * <li>41: Hardware enforcement of device-unlocked keys (see {@link
+ * android.security.keystore.KeyGenParameterSpec.Builder#setUnlockedDeviceRequired(boolean)}).
+ * <li>40: Support for wrapped key import (see {@link
+ * android.security.keystore.WrappedKeyEntry}), optional support for ID attestation (see {@link
+ * android.security.keystore.KeyGenParameterSpec.Builder#setDevicePropertiesAttestationIncluded(boolean)}),
+ * attestation (see {@link
+ * android.security.keystore.KeyGenParameterSpec.Builder#setAttestationChallenge(byte[])}),
+ * AES, HMAC, ECDSA and RSA support where the secret or private key never leaves secure
+ * hardware, and support for requiring user authentication before a key can be used.
+ * </ul>
+ * If a device has StrongBox, this feature version number is guaranteed to be set for all
+ * devices launching with Android 12 and may be set on devices launching with an earlier
+ * version. If the feature version is set, it will at least have the value 40. If it's not
+ * set the device may have StrongBox but it may not support all features listed above.
*/
@SdkConstant(SdkConstantType.FEATURE)
public static final String FEATURE_STRONGBOX_KEYSTORE =
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index 933dee3..609da31 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -1363,6 +1363,8 @@
// devices going offline (in real world scenarios, these permissions aren't
// changeable). Future calls to getCameraIdList() will reflect the changes in
// the camera id list after getCameraIdListNoLazy() is called.
+ // We need to remove the torch ids which may have been associated with the
+ // devices removed as well. This is the same situation.
cameraStatuses = mCameraService.addListener(testListener);
mCameraService.removeListener(testListener);
for (CameraStatus c : cameraStatuses) {
@@ -1381,6 +1383,7 @@
}
for (String id : deviceIdsToRemove) {
onStatusChangedLocked(ICameraServiceListener.STATUS_NOT_PRESENT, id);
+ mTorchStatus.remove(id);
}
} catch (ServiceSpecificException e) {
// Unexpected failure
diff --git a/core/java/android/hardware/hdmi/HdmiPlaybackClient.java b/core/java/android/hardware/hdmi/HdmiPlaybackClient.java
index f13326b..d06bc1d 100644
--- a/core/java/android/hardware/hdmi/HdmiPlaybackClient.java
+++ b/core/java/android/hardware/hdmi/HdmiPlaybackClient.java
@@ -84,7 +84,6 @@
* of the result
*/
public void oneTouchPlay(OneTouchPlayCallback callback) {
- // TODO: Use PendingResult.
try {
mService.oneTouchPlay(getCallbackWrapper(callback));
} catch (RemoteException e) {
diff --git a/core/java/android/net/INetworkPolicyManager.aidl b/core/java/android/net/INetworkPolicyManager.aidl
index 171c6a2..f50aa99 100644
--- a/core/java/android/net/INetworkPolicyManager.aidl
+++ b/core/java/android/net/INetworkPolicyManager.aidl
@@ -78,5 +78,4 @@
boolean isUidNetworkingBlocked(int uid, boolean meteredNetwork);
boolean isUidRestrictedOnMeteredNetworks(int uid);
- boolean checkUidNetworkingBlocked(int uid, int uidRules, boolean isNetworkMetered, boolean isBackgroundRestricted);
}
diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java
index b037261..1eef7d9 100644
--- a/core/java/android/net/NetworkIdentity.java
+++ b/core/java/android/net/NetworkIdentity.java
@@ -198,15 +198,11 @@
final int oemManaged = getOemBitfield(snapshot.networkCapabilities);
if (legacyType == TYPE_WIFI) {
- if (snapshot.networkCapabilities.getSsid() != null) {
- networkId = snapshot.networkCapabilities.getSsid();
- if (networkId == null) {
- // TODO: Figure out if this code path never runs. If so, remove them.
- final WifiManager wifi = (WifiManager) context.getSystemService(
- Context.WIFI_SERVICE);
- final WifiInfo info = wifi.getConnectionInfo();
- networkId = info != null ? info.getSSID() : null;
- }
+ networkId = snapshot.networkCapabilities.getSsid();
+ if (networkId == null) {
+ final WifiManager wifi = context.getSystemService(WifiManager.class);
+ final WifiInfo info = wifi.getConnectionInfo();
+ networkId = info != null ? info.getSSID() : null;
}
}
diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java
index 40fbfbb..b074fad 100644
--- a/core/java/android/net/NetworkPolicyManager.java
+++ b/core/java/android/net/NetworkPolicyManager.java
@@ -18,7 +18,6 @@
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 @interface SubscriptionOverrideMask {}
- /** @hide */
- public static final int BLOCKED_METERED_REASON_MASK = 0xffff0000;
-
/**
* Flag to indicate that app is not exempt from any network restrictions.
*
@@ -568,31 +564,6 @@
}
/**
- * Figure out if networking is blocked for a given set of conditions.
- *
- * This is used by ConnectivityService via passing stale copies of conditions, so it must not
- * take any locks.
- *
- * @param uid The target uid.
- * @param uidRules The uid rules which are obtained from NetworkPolicyManagerService.
- * @param isNetworkMetered True if the network is metered.
- * @param isBackgroundRestricted True if data saver is enabled.
- *
- * @return true if networking is blocked for the UID under the specified conditions.
- *
- * @hide
- */
- public boolean checkUidNetworkingBlocked(int uid, int uidRules,
- boolean isNetworkMetered, boolean isBackgroundRestricted) {
- try {
- return mService.checkUidNetworkingBlocked(uid, uidRules, isNetworkMetered,
- isBackgroundRestricted);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
* Check that the given uid is restricted from doing networking on metered networks.
*
* @param uid The target uid.
@@ -789,36 +760,6 @@
}
/**
- * 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
@@ -831,6 +772,12 @@
return DebugUtils.flagsToString(NetworkPolicyManager.class, "BLOCKED_", blockedReasons);
}
+ /** @hide */
+ @NonNull
+ public static String allowedReasonsToString(int allowedReasons) {
+ return DebugUtils.flagsToString(NetworkPolicyManager.class, "ALLOWED_", allowedReasons);
+ }
+
/**
* Register a {@link NetworkPolicyCallback} to listen for changes to network blocked status
* of apps.
diff --git a/core/java/android/net/netstats/provider/INetworkStatsProvider.aidl b/core/java/android/net/netstats/provider/INetworkStatsProvider.aidl
index 4078b24..74c3ba4 100644
--- a/core/java/android/net/netstats/provider/INetworkStatsProvider.aidl
+++ b/core/java/android/net/netstats/provider/INetworkStatsProvider.aidl
@@ -23,6 +23,6 @@
*/
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 bd336dd..7eaa01e 100644
--- a/core/java/android/net/netstats/provider/INetworkStatsProviderCallback.aidl
+++ b/core/java/android/net/netstats/provider/INetworkStatsProviderCallback.aidl
@@ -26,6 +26,6 @@
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 7639d22..23fc069 100644
--- a/core/java/android/net/netstats/provider/NetworkStatsProvider.java
+++ b/core/java/android/net/netstats/provider/NetworkStatsProvider.java
@@ -29,7 +29,8 @@
@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 @@
}
@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 @@
}
/**
- * 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 void onSetLimit(@NonNull String iface, long quotaBytes);
/**
+ * Called by {@code NetworkStatsService} when setting the interface quotas for the specified
+ * upstream interface. If a provider implements {@link #onSetWarningAndLimit}, the system
+ * will not call {@link #onSetLimit}. When this method is called, the implementation
+ * should behave as follows:
+ * 1. If {@code warningBytes} is reached on {@code iface}, block all further traffic on
+ * {@code iface} and call {@link NetworkStatsProvider@notifyWarningReached()}.
+ * 2. If {@code limitBytes} is reached on {@code iface}, block all further traffic on
+ * {@code iface} and call {@link NetworkStatsProvider#notifyLimitReached()}.
+ *
+ * @param iface the interface requiring the operation.
+ * @param warningBytes the warning defined as the number of bytes, starting from zero and
+ * counting from now. A value of {@link #QUOTA_UNLIMITED} indicates
+ * there is no warning.
+ * @param limitBytes the limit defined as the number of bytes, starting from zero and counting
+ * from now. A value of {@link #QUOTA_UNLIMITED} indicates there is no limit.
+ */
+ public void onSetWarningAndLimit(@NonNull String iface, long warningBytes, long limitBytes) {
+ // Backward compatibility for those who didn't override this function.
+ onSetLimit(iface, limitBytes);
+ }
+
+ /**
* Called by {@code NetworkStatsService} when setting the alert bytes. Custom implementations
* MUST call {@link NetworkStatsProvider#notifyAlertReached()} when {@code quotaBytes} bytes
* have been reached. Unlike {@link #onSetLimit(String, long)}, the custom implementation should
diff --git a/core/java/android/net/vcn/IVcnStatusCallback.aidl b/core/java/android/net/vcn/IVcnStatusCallback.aidl
index 236ae8b..11bc443 100644
--- a/core/java/android/net/vcn/IVcnStatusCallback.aidl
+++ b/core/java/android/net/vcn/IVcnStatusCallback.aidl
@@ -20,7 +20,7 @@
oneway interface IVcnStatusCallback {
void onVcnStatusChanged(int statusCode);
void onGatewayConnectionError(
- in int[] gatewayNetworkCapabilities,
+ in String gatewayConnectionName,
int errorCode,
in String exceptionClass,
in String exceptionMessage);
diff --git a/core/java/android/net/vcn/VcnConfig.java b/core/java/android/net/vcn/VcnConfig.java
index 52cc218..d41c0b4 100644
--- a/core/java/android/net/vcn/VcnConfig.java
+++ b/core/java/android/net/vcn/VcnConfig.java
@@ -183,12 +183,25 @@
*
* @param gatewayConnectionConfig the configuration for an individual gateway connection
* @return this {@link Builder} instance, for chaining
+ * @throws IllegalArgumentException if a VcnGatewayConnectionConfig has already been set for
+ * this {@link VcnConfig} with the same GatewayConnection name (as returned via {@link
+ * VcnGatewayConnectionConfig#getGatewayConnectionName()}).
*/
@NonNull
public Builder addGatewayConnectionConfig(
@NonNull VcnGatewayConnectionConfig gatewayConnectionConfig) {
Objects.requireNonNull(gatewayConnectionConfig, "gatewayConnectionConfig was null");
+ for (final VcnGatewayConnectionConfig vcnGatewayConnectionConfig :
+ mGatewayConnectionConfigs) {
+ if (vcnGatewayConnectionConfig
+ .getGatewayConnectionName()
+ .equals(gatewayConnectionConfig.getGatewayConnectionName())) {
+ throw new IllegalArgumentException(
+ "GatewayConnection for specified name already exists");
+ }
+ }
+
mGatewayConnectionConfigs.add(gatewayConnectionConfig);
return this;
}
diff --git a/core/java/android/net/vcn/VcnGatewayConnectionConfig.java b/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
index d4e8e2d..75db382 100644
--- a/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
+++ b/core/java/android/net/vcn/VcnGatewayConnectionConfig.java
@@ -148,6 +148,8 @@
TimeUnit.MINUTES.toMillis(5),
TimeUnit.MINUTES.toMillis(15)
};
+ private static final String GATEWAY_CONNECTION_NAME_KEY = "mGatewayConnectionName";
+ @NonNull private final String mGatewayConnectionName;
private static final String CTRL_PLANE_CONFIG_KEY = "mCtrlPlaneConfig";
@NonNull private VcnControlPlaneConfig mCtrlPlaneConfig;
@@ -166,11 +168,13 @@
/** Builds a VcnGatewayConnectionConfig with the specified parameters. */
private VcnGatewayConnectionConfig(
+ @NonNull String gatewayConnectionName,
@NonNull VcnControlPlaneConfig ctrlPlaneConfig,
@NonNull Set<Integer> exposedCapabilities,
@NonNull Set<Integer> underlyingCapabilities,
@NonNull long[] retryIntervalsMs,
@IntRange(from = MIN_MTU_V6) int maxMtu) {
+ mGatewayConnectionName = gatewayConnectionName;
mCtrlPlaneConfig = ctrlPlaneConfig;
mExposedCapabilities = new TreeSet(exposedCapabilities);
mUnderlyingCapabilities = new TreeSet(underlyingCapabilities);
@@ -192,6 +196,7 @@
final PersistableBundle underlyingCapsBundle =
in.getPersistableBundle(UNDERLYING_CAPABILITIES_KEY);
+ mGatewayConnectionName = in.getString(GATEWAY_CONNECTION_NAME_KEY);
mCtrlPlaneConfig = VcnControlPlaneConfig.fromPersistableBundle(ctrlPlaneConfigBundle);
mExposedCapabilities = new TreeSet<>(PersistableBundleUtils.toList(
exposedCapsBundle, PersistableBundleUtils.INTEGER_DESERIALIZER));
@@ -204,6 +209,7 @@
}
private void validate() {
+ Objects.requireNonNull(mGatewayConnectionName, "gatewayConnectionName was null");
Objects.requireNonNull(mCtrlPlaneConfig, "control plane config was null");
Preconditions.checkArgument(
@@ -242,6 +248,20 @@
}
/**
+ * Returns the configured Gateway Connection name.
+ *
+ * <p>This name is used by the configuring apps to distinguish between
+ * VcnGatewayConnectionConfigs configured on a single {@link VcnConfig}. This will be used as
+ * the identifier in VcnStatusCallback invocations.
+ *
+ * @see VcnManager.VcnStatusCallback#onGatewayConnectionError
+ */
+ @NonNull
+ public String getGatewayConnectionName() {
+ return mGatewayConnectionName;
+ }
+
+ /**
* Returns control plane configuration.
*
* @hide
@@ -364,6 +384,7 @@
new ArrayList<>(mUnderlyingCapabilities),
PersistableBundleUtils.INTEGER_SERIALIZER);
+ result.putString(GATEWAY_CONNECTION_NAME_KEY, mGatewayConnectionName);
result.putPersistableBundle(CTRL_PLANE_CONFIG_KEY, ctrlPlaneConfigBundle);
result.putPersistableBundle(EXPOSED_CAPABILITIES_KEY, exposedCapsBundle);
result.putPersistableBundle(UNDERLYING_CAPABILITIES_KEY, underlyingCapsBundle);
@@ -376,6 +397,7 @@
@Override
public int hashCode() {
return Objects.hash(
+ mGatewayConnectionName,
mExposedCapabilities,
mUnderlyingCapabilities,
Arrays.hashCode(mRetryIntervalsMs),
@@ -389,7 +411,8 @@
}
final VcnGatewayConnectionConfig rhs = (VcnGatewayConnectionConfig) other;
- return mExposedCapabilities.equals(rhs.mExposedCapabilities)
+ return mGatewayConnectionName.equals(rhs.mGatewayConnectionName)
+ && mExposedCapabilities.equals(rhs.mExposedCapabilities)
&& mUnderlyingCapabilities.equals(rhs.mUnderlyingCapabilities)
&& Arrays.equals(mRetryIntervalsMs, rhs.mRetryIntervalsMs)
&& mMaxMtu == rhs.mMaxMtu;
@@ -399,6 +422,7 @@
* This class is used to incrementally build {@link VcnGatewayConnectionConfig} objects.
*/
public static final class Builder {
+ @NonNull private final String mGatewayConnectionName;
@NonNull private final VcnControlPlaneConfig mCtrlPlaneConfig;
@NonNull private final Set<Integer> mExposedCapabilities = new ArraySet();
@NonNull private final Set<Integer> mUnderlyingCapabilities = new ArraySet();
@@ -412,12 +436,22 @@
/**
* Construct a Builder object.
*
+ * @param gatewayConnectionName the String GatewayConnection name for this
+ * VcnGatewayConnectionConfig. Each VcnGatewayConnectionConfig within a {@link
+ * VcnConfig} must be given a unique name. This name is used by the caller to
+ * distinguish between VcnGatewayConnectionConfigs configured on a single {@link
+ * VcnConfig}. This will be used as the identifier in VcnStatusCallback invocations.
* @param ctrlPlaneConfig the control plane configuration
* @see VcnControlPlaneConfig
+ * @see VcnManager.VcnStatusCallback#onGatewayConnectionError
*/
- public Builder(@NonNull VcnControlPlaneConfig ctrlPlaneConfig) {
+ public Builder(
+ @NonNull String gatewayConnectionName,
+ @NonNull VcnControlPlaneConfig ctrlPlaneConfig) {
+ Objects.requireNonNull(gatewayConnectionName, "gatewayConnectionName was null");
Objects.requireNonNull(ctrlPlaneConfig, "ctrlPlaneConfig was null");
+ mGatewayConnectionName = gatewayConnectionName;
mCtrlPlaneConfig = ctrlPlaneConfig;
}
@@ -562,6 +596,7 @@
@NonNull
public VcnGatewayConnectionConfig build() {
return new VcnGatewayConnectionConfig(
+ mGatewayConnectionName,
mCtrlPlaneConfig,
mExposedCapabilities,
mUnderlyingCapabilities,
diff --git a/core/java/android/net/vcn/VcnManager.java b/core/java/android/net/vcn/VcnManager.java
index abd41da..344b20c 100644
--- a/core/java/android/net/vcn/VcnManager.java
+++ b/core/java/android/net/vcn/VcnManager.java
@@ -437,7 +437,7 @@
* Invoked when status of the VCN for this callback's subscription group changes.
*
* @param statusCode the code for the status change encountered by this {@link
- * VcnStatusCallback}'s subscription group.
+ * VcnStatusCallback}'s subscription group. This value will be one of VCN_STATUS_CODE_*.
*/
public abstract void onStatusChanged(@VcnStatusCode int statusCode);
@@ -445,18 +445,17 @@
* Invoked when a VCN Gateway Connection corresponding to this callback's subscription group
* encounters an error.
*
- * @param networkCapabilities an array of NetworkCapabilities.NET_CAPABILITY_* capabilities
- * for the Gateway Connection that encountered the error, for identification purposes.
- * These will be a sorted list with no duplicates and will match {@link
- * VcnGatewayConnectionConfig#getExposedCapabilities()} for one of the {@link
- * VcnGatewayConnectionConfig}s set in the {@link VcnConfig} for this subscription
- * group.
- * @param errorCode the code to indicate the error that occurred
+ * @param gatewayConnectionName the String GatewayConnection name for the GatewayConnection
+ * encountering an error. This will match the name for exactly one {@link
+ * VcnGatewayConnectionConfig} for the {@link VcnConfig} configured for this callback's
+ * subscription group
+ * @param errorCode the code to indicate the error that occurred. This value will be one of
+ * VCN_ERROR_CODE_*.
* @param detail Throwable to provide additional information about the error, or {@code
* null} if none
*/
public abstract void onGatewayConnectionError(
- @NonNull int[] networkCapabilities,
+ @NonNull String gatewayConnectionName,
@VcnErrorCode int errorCode,
@Nullable Throwable detail);
}
@@ -586,7 +585,7 @@
// TODO(b/180521637): use ServiceSpecificException for safer Exception 'parceling'
@Override
public void onGatewayConnectionError(
- @NonNull int[] networkCapabilities,
+ @NonNull String gatewayConnectionName,
@VcnErrorCode int errorCode,
@Nullable String exceptionClass,
@Nullable String exceptionMessage) {
@@ -597,7 +596,7 @@
mExecutor.execute(
() ->
mCallback.onGatewayConnectionError(
- networkCapabilities, errorCode, cause)));
+ gatewayConnectionName, errorCode, cause)));
}
private static Throwable createThrowableByClassName(
diff --git a/core/java/android/nfc/INfcAdapter.aidl b/core/java/android/nfc/INfcAdapter.aidl
index bc3d5c4..d5cc01a 100644
--- a/core/java/android/nfc/INfcAdapter.aidl
+++ b/core/java/android/nfc/INfcAdapter.aidl
@@ -24,6 +24,7 @@
import android.nfc.TechListParcel;
import android.nfc.IAppCallback;
import android.nfc.INfcAdapterExtras;
+import android.nfc.INfcControllerAlwaysOnStateCallback;
import android.nfc.INfcTag;
import android.nfc.INfcCardEmulation;
import android.nfc.INfcFCardEmulation;
@@ -72,7 +73,9 @@
boolean deviceSupportsNfcSecure();
boolean setNfcSecure(boolean enable);
- boolean setAlwaysOn(boolean value);
- boolean isAlwaysOnEnabled();
- boolean isAlwaysOnSupported();
+ boolean setControllerAlwaysOn(boolean value);
+ boolean isControllerAlwaysOn();
+ boolean isControllerAlwaysOnSupported();
+ void registerControllerAlwaysOnStateCallback(in INfcControllerAlwaysOnStateCallback callback);
+ void unregisterControllerAlwaysOnStateCallback(in INfcControllerAlwaysOnStateCallback callback);
}
diff --git a/core/java/android/nfc/INfcControllerAlwaysOnStateCallback.aidl b/core/java/android/nfc/INfcControllerAlwaysOnStateCallback.aidl
new file mode 100644
index 0000000..1e4fdd7
--- /dev/null
+++ b/core/java/android/nfc/INfcControllerAlwaysOnStateCallback.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.nfc;
+
+/**
+ * @hide
+ */
+oneway interface INfcControllerAlwaysOnStateCallback {
+ /**
+ * Called whenever the controller always on state changes
+ *
+ * @param isEnabled true if the state is enabled, false otherwise
+ */
+ void onControllerAlwaysOnStateChanged(boolean isEnabled);
+}
diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java
index e85eb93..bbf802c 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -16,6 +16,7 @@
package android.nfc;
+import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
@@ -47,6 +48,7 @@
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
+import java.util.concurrent.Executor;
/**
* Represents the local NFC adapter.
@@ -65,6 +67,8 @@
public final class NfcAdapter {
static final String TAG = "NFC";
+ private final NfcControllerAlwaysOnStateListener mControllerAlwaysOnStateListener;
+
/**
* Intent to start an activity when a tag with NDEF payload is discovered.
*
@@ -350,22 +354,6 @@
"android.nfc.extra.HANDOVER_TRANSFER_STATUS";
/** @hide */
- public static final String ACTION_ALWAYS_ON_STATE_CHANGED =
- "android.nfc.action.ALWAYS_ON_STATE_CHANGED";
-
- /**
- * Used as an int extra field in {@link #ACTION_ALWAYS_ON_STATE_CHANGED}
- * intents to request the current power state. Possible values are:
- * {@link #STATE_OFF},
- * {@link #STATE_TURNING_ON},
- * {@link #STATE_ON},
- * {@link #STATE_TURNING_OFF},
- * @hide
- */
- public static final String EXTRA_ALWAYS_ON_STATE =
- "android.nfc.extra.ALWAYS_ON_STATE";
-
- /** @hide */
public static final int HANDOVER_TRANSFER_STATUS_SUCCESS = 0;
/** @hide */
public static final int HANDOVER_TRANSFER_STATUS_FAILURE = 1;
@@ -430,6 +418,22 @@
}
/**
+ * A callback to be invoked when NFC controller always on state changes.
+ * <p>Register your {@code ControllerAlwaysOnStateCallback} implementation with {@link
+ * NfcAdapter#registerControllerAlwaysOnStateCallback} and disable it with {@link
+ * NfcAdapter#unregisterControllerAlwaysOnStateCallback}.
+ * @see #registerControllerAlwaysOnStateCallback
+ * @hide
+ */
+ @SystemApi
+ public interface ControllerAlwaysOnStateCallback {
+ /**
+ * Called on NFC controller always on state changes
+ */
+ void onStateChanged(boolean isEnabled);
+ }
+
+ /**
* A callback to be invoked when the system successfully delivers your {@link NdefMessage}
* to another device.
* @see #setOnNdefPushCompleteCallback
@@ -744,6 +748,7 @@
mNfcUnlockHandlers = new HashMap<NfcUnlockHandler, INfcUnlockHandler>();
mTagRemovedListener = null;
mLock = new Object();
+ mControllerAlwaysOnStateListener = new NfcControllerAlwaysOnStateListener(getService());
}
/**
@@ -2239,14 +2244,16 @@
/**
* Sets NFC controller always on feature.
* <p>This API is for the NFCC internal state management. It allows to discriminate
- * the controller function from the NFC function by keeping the NFC Controller on without
+ * the controller function from the NFC function by keeping the NFC controller on without
* any NFC RF enabled if necessary.
- * <p>This call is asynchronous. Listen for {@link #ACTION_ALWAYS_ON_STATE_CHANGED}
- * broadcasts to find out when the operation is complete.
- * <p>If this returns true, then either NFCC is already on, or
- * a {@link #ACTION_ALWAYS_ON_STATE_CHANGED} broadcast will be sent to indicate
- * a state transition.
- * If this returns false, then there is some problem that prevents an attempt to turn NFCC on.
+ * <p>This call is asynchronous. Register a callback {@link #ControllerAlwaysOnStateCallback}
+ * by {@link #registerControllerAlwaysOnStateCallback} to find out when the operation is
+ * complete.
+ * <p>If this returns true, then either NFCC always on state has been set based on the value,
+ * or a {@link ControllerAlwaysOnStateCallback#onStateChanged(boolean)} will be invoked to
+ * indicate the state change.
+ * If this returns false, then there is some problem that prevents an attempt to turn NFCC
+ * always on.
* @param value if true the NFCC will be kept on (with no RF enabled if NFC adapter is
* disabled), if false the NFCC will follow completely the Nfc adapter state.
* @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
@@ -2254,13 +2261,13 @@
* @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 +2276,7 @@
return false;
}
try {
- return sService.setAlwaysOn(value);
+ return sService.setControllerAlwaysOn(value);
} catch (RemoteException ee) {
Log.e(TAG, "Failed to recover NFC Service.");
}
@@ -2284,12 +2291,11 @@
* @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
* @hide
*/
-
@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 +2304,7 @@
return false;
}
try {
- return sService.isAlwaysOnEnabled();
+ return sService.isControllerAlwaysOn();
} catch (RemoteException ee) {
Log.e(TAG, "Failed to recover NFC Service.");
}
@@ -2313,15 +2319,14 @@
* @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
* @hide
*/
-
@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,11 +2335,46 @@
return false;
}
try {
- return sService.isAlwaysOnSupported();
+ return sService.isControllerAlwaysOnSupported();
} catch (RemoteException ee) {
Log.e(TAG, "Failed to recover NFC Service.");
}
return false;
}
}
+
+ /**
+ * Register a {@link ControllerAlwaysOnStateCallback} to listen for NFC controller always on
+ * state changes
+ * <p>The provided callback will be invoked by the given {@link Executor}.
+ *
+ * @param executor an {@link Executor} to execute given callback
+ * @param callback user implementation of the {@link ControllerAlwaysOnStateCallback}
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON)
+ public void registerControllerAlwaysOnStateCallback(
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull ControllerAlwaysOnStateCallback callback) {
+ mControllerAlwaysOnStateListener.register(executor, callback);
+ }
+
+ /**
+ * Unregister the specified {@link ControllerAlwaysOnStateCallback}
+ * <p>The same {@link ControllerAlwaysOnStateCallback} object used when calling
+ * {@link #registerControllerAlwaysOnStateCallback(Executor, ControllerAlwaysOnStateCallback)}
+ * must be used.
+ *
+ * <p>Callbacks are automatically unregistered when application process goes away
+ *
+ * @param callback user implementation of the {@link ControllerAlwaysOnStateCallback}
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON)
+ public void unregisterControllerAlwaysOnStateCallback(
+ @NonNull ControllerAlwaysOnStateCallback callback) {
+ mControllerAlwaysOnStateListener.unregister(callback);
+ }
}
diff --git a/core/java/android/nfc/NfcControllerAlwaysOnStateListener.java b/core/java/android/nfc/NfcControllerAlwaysOnStateListener.java
new file mode 100644
index 0000000..69a9ec7
--- /dev/null
+++ b/core/java/android/nfc/NfcControllerAlwaysOnStateListener.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.nfc;
+
+import android.annotation.NonNull;
+import android.nfc.NfcAdapter.ControllerAlwaysOnStateCallback;
+import android.os.Binder;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.Executor;
+
+/**
+ * @hide
+ */
+public class NfcControllerAlwaysOnStateListener extends INfcControllerAlwaysOnStateCallback.Stub {
+ private static final String TAG = "NfcControllerAlwaysOnStateListener";
+
+ private final INfcAdapter mAdapter;
+
+ private final Map<ControllerAlwaysOnStateCallback, Executor> mCallbackMap = new HashMap<>();
+
+ private boolean mCurrentState = false;
+ private boolean mIsRegistered = false;
+
+ public NfcControllerAlwaysOnStateListener(@NonNull INfcAdapter adapter) {
+ mAdapter = adapter;
+ }
+
+ /**
+ * Register a {@link ControllerAlwaysOnStateCallback} with this
+ * {@link NfcControllerAlwaysOnStateListener}
+ *
+ * @param executor an {@link Executor} to execute given callback
+ * @param callback user implementation of the {@link ControllerAlwaysOnStateCallback}
+ */
+ public void register(@NonNull Executor executor,
+ @NonNull ControllerAlwaysOnStateCallback callback) {
+ synchronized (this) {
+ if (mCallbackMap.containsKey(callback)) {
+ return;
+ }
+
+ mCallbackMap.put(callback, executor);
+ if (!mIsRegistered) {
+ try {
+ mAdapter.registerControllerAlwaysOnStateCallback(this);
+ mIsRegistered = true;
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to register ControllerAlwaysOnStateListener");
+ }
+ }
+ }
+ }
+
+ /**
+ * Unregister the specified {@link ControllerAlwaysOnStateCallback}
+ *
+ * @param callback user implementation of the {@link ControllerAlwaysOnStateCallback}
+ */
+ public void unregister(@NonNull ControllerAlwaysOnStateCallback callback) {
+ synchronized (this) {
+ if (!mCallbackMap.containsKey(callback)) {
+ return;
+ }
+
+ mCallbackMap.remove(callback);
+
+ if (mCallbackMap.isEmpty() && mIsRegistered) {
+ try {
+ mAdapter.unregisterControllerAlwaysOnStateCallback(this);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to unregister ControllerAlwaysOnStateListener");
+ }
+ mIsRegistered = false;
+ }
+ }
+ }
+
+ private void sendCurrentState(@NonNull ControllerAlwaysOnStateCallback callback) {
+ synchronized (this) {
+ Executor executor = mCallbackMap.get(callback);
+
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ executor.execute(() -> callback.onStateChanged(
+ mCurrentState));
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+ }
+
+ @Override
+ public void onControllerAlwaysOnStateChanged(boolean isEnabled) {
+ synchronized (this) {
+ mCurrentState = isEnabled;
+ for (ControllerAlwaysOnStateCallback cb : mCallbackMap.keySet()) {
+ sendCurrentState(cb);
+ }
+ }
+ }
+}
+
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index 6425c25..f5130bc 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -543,6 +543,16 @@
public final native void markVintfStability();
/**
+ * Use a VINTF-stability binder w/o VINTF requirements. Should be called
+ * on a binder before it is sent out of process.
+ *
+ * This must be called before the object is sent to another process.
+ *
+ * @hide
+ */
+ public final native void forceDowngradeToSystemStability();
+
+ /**
* Flush any Binder commands pending in the current thread to the kernel
* driver. This can be
* useful to call before performing an operation that may block for a long
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 189a8ac..03caafd 100755
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -115,15 +115,20 @@
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 9d16f18..9b29fb1 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -127,6 +127,7 @@
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
+ @TestApi
public static final int NFC_UID = 1027;
/**
diff --git a/core/java/android/provider/SimPhonebookContract.java b/core/java/android/provider/SimPhonebookContract.java
index 030b863..fb89eb0 100644
--- a/core/java/android/provider/SimPhonebookContract.java
+++ b/core/java/android/provider/SimPhonebookContract.java
@@ -17,13 +17,14 @@
package android.provider;
import static android.provider.SimPhonebookContract.ElementaryFiles.EF_ADN;
-import static android.provider.SimPhonebookContract.ElementaryFiles.EF_ADN_PATH_SEGMENT;
import static android.provider.SimPhonebookContract.ElementaryFiles.EF_FDN;
-import static android.provider.SimPhonebookContract.ElementaryFiles.EF_FDN_PATH_SEGMENT;
import static android.provider.SimPhonebookContract.ElementaryFiles.EF_SDN;
-import static android.provider.SimPhonebookContract.ElementaryFiles.EF_SDN_PATH_SEGMENT;
+import static android.provider.SimPhonebookContract.ElementaryFiles.PATH_SEGMENT_EF_ADN;
+import static android.provider.SimPhonebookContract.ElementaryFiles.PATH_SEGMENT_EF_FDN;
+import static android.provider.SimPhonebookContract.ElementaryFiles.PATH_SEGMENT_EF_SDN;
import android.annotation.IntDef;
+import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.annotation.WorkerThread;
@@ -78,11 +79,11 @@
public static String getEfUriPath(@ElementaryFiles.EfType int efType) {
switch (efType) {
case EF_ADN:
- return EF_ADN_PATH_SEGMENT;
+ return PATH_SEGMENT_EF_ADN;
case EF_FDN:
- return EF_FDN_PATH_SEGMENT;
+ return PATH_SEGMENT_EF_FDN;
case EF_SDN:
- return EF_SDN_PATH_SEGMENT;
+ return PATH_SEGMENT_EF_SDN;
default:
throw new IllegalArgumentException("Unsupported EfType " + efType);
}
@@ -109,9 +110,9 @@
* the phone number can contain at most {@link ElementaryFiles#PHONE_NUMBER_MAX_LENGTH}
* characters. The {@link SimRecords#NAME} column can contain at most
* {@link ElementaryFiles#NAME_MAX_LENGTH} bytes when it is encoded for storage on the SIM.
- * Encoding is done internally and so the name should be provided unencoded but the number of
- * bytes required to encode it will vary depending on the characters it contains. This length
- * can be determined by calling
+ * Encoding is done internally and so the name should be provided to these provider APIs as a
+ * Java String but the number of bytes required to encode it for storage will vary depending on
+ * the characters it contains. This length can be determined by calling
* {@link SimRecords#getEncodedNameLength(ContentResolver, String)}.
* </p>
* <h3>Operations </h3>
@@ -308,7 +309,8 @@
*/
@NonNull
public static Uri getItemUri(
- int subscriptionId, @ElementaryFiles.EfType int efType, int recordNumber) {
+ int subscriptionId, @ElementaryFiles.EfType int efType,
+ @IntRange(from = 1) int recordNumber) {
// Elementary file record indices are 1-based.
Preconditions.checkArgument(recordNumber > 0, "Invalid recordNumber");
@@ -332,6 +334,7 @@
* @see ElementaryFiles#NAME_MAX_LENGTH
*/
@WorkerThread
+ @IntRange(from = 0)
public static int getEncodedNameLength(
@NonNull ContentResolver resolver, @NonNull String name) {
Objects.requireNonNull(name);
@@ -442,12 +445,27 @@
* methods operating on this Uri will throw UnsupportedOperationException
*/
public static final int EF_SDN = 3;
- /** @hide */
- public static final String EF_ADN_PATH_SEGMENT = "adn";
- /** @hide */
- public static final String EF_FDN_PATH_SEGMENT = "fdn";
- /** @hide */
- public static final String EF_SDN_PATH_SEGMENT = "sdn";
+ /**
+ * The Uri path segment used to target the ADN elementary file for SimPhonebookProvider
+ * content operations.
+ *
+ * @hide
+ */
+ public static final String PATH_SEGMENT_EF_ADN = "adn";
+ /**
+ * The Uri path segment used to target the FDN elementary file for SimPhonebookProvider
+ * content operations.
+ *
+ * @hide
+ */
+ public static final String PATH_SEGMENT_EF_FDN = "fdn";
+ /**
+ * The Uri path segment used to target the SDN elementary file for SimPhonebookProvider
+ * content operations.
+ *
+ * @hide
+ */
+ public static final String PATH_SEGMENT_EF_SDN = "sdn";
/** The MIME type of CONTENT_URI providing a directory of ADN-like elementary files. */
public static final String CONTENT_TYPE = "vnd.android.cursor.dir/sim-elementary-file";
/** The MIME type of a CONTENT_URI subdirectory of a single ADN-like elementary file. */
diff --git a/core/java/android/security/ConfirmationPrompt.java b/core/java/android/security/ConfirmationPrompt.java
index 2329037..d8c44ad 100644
--- a/core/java/android/security/ConfirmationPrompt.java
+++ b/core/java/android/security/ConfirmationPrompt.java
@@ -21,7 +21,6 @@
import android.content.Context;
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
-import android.security.keystore.AndroidKeyStoreProvider;
import android.text.TextUtils;
import android.util.Log;
@@ -106,32 +105,6 @@
private void doCallback(int responseCode, byte[] dataThatWasConfirmed,
ConfirmationCallback callback) {
switch (responseCode) {
- case KeyStore.CONFIRMATIONUI_OK:
- callback.onConfirmed(dataThatWasConfirmed);
- break;
-
- case KeyStore.CONFIRMATIONUI_CANCELED:
- callback.onDismissed();
- break;
-
- case KeyStore.CONFIRMATIONUI_ABORTED:
- callback.onCanceled();
- break;
-
- case KeyStore.CONFIRMATIONUI_SYSTEM_ERROR:
- callback.onError(new Exception("System error returned by ConfirmationUI."));
- break;
-
- default:
- callback.onError(new Exception("Unexpected responseCode=" + responseCode
- + " from onConfirmtionPromptCompleted() callback."));
- break;
- }
- }
-
- private void doCallback2(int responseCode, byte[] dataThatWasConfirmed,
- ConfirmationCallback callback) {
- switch (responseCode) {
case AndroidProtectedConfirmation.ERROR_OK:
callback.onConfirmed(dataThatWasConfirmed);
break;
@@ -155,31 +128,6 @@
}
}
- private final android.os.IBinder mCallbackBinder =
- new android.security.IConfirmationPromptCallback.Stub() {
- @Override
- public void onConfirmationPromptCompleted(
- int responseCode, final byte[] dataThatWasConfirmed)
- throws android.os.RemoteException {
- if (mCallback != null) {
- ConfirmationCallback callback = mCallback;
- Executor executor = mExecutor;
- mCallback = null;
- mExecutor = null;
- if (executor == null) {
- doCallback(responseCode, dataThatWasConfirmed, callback);
- } else {
- executor.execute(new Runnable() {
- @Override
- public void run() {
- doCallback(responseCode, dataThatWasConfirmed, callback);
- }
- });
- }
- }
- }
- };
-
private final android.security.apc.IConfirmationCallback mConfirmationCallback =
new android.security.apc.IConfirmationCallback.Stub() {
@Override
@@ -191,11 +139,11 @@
mCallback = null;
mExecutor = null;
if (executor == null) {
- doCallback2(result, dataThatWasConfirmed, callback);
+ doCallback(result, dataThatWasConfirmed, callback);
} else {
executor.execute(new Runnable() {
@Override public void run() {
- doCallback2(result, dataThatWasConfirmed, callback);
+ doCallback(result, dataThatWasConfirmed, callback);
}
});
}
@@ -266,29 +214,7 @@
mExtraData = extraData;
}
- private static final int UI_OPTION_ACCESSIBILITY_INVERTED_FLAG = 1 << 0;
- private static final int UI_OPTION_ACCESSIBILITY_MAGNIFIED_FLAG = 1 << 1;
-
private int getUiOptionsAsFlags() {
- if (AndroidKeyStoreProvider.isKeystore2Enabled()) {
- return getUiOptionsAsFlags2();
- }
- int uiOptionsAsFlags = 0;
- ContentResolver contentResolver = mContext.getContentResolver();
- int inversionEnabled = Settings.Secure.getInt(contentResolver,
- Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, 0);
- if (inversionEnabled == 1) {
- uiOptionsAsFlags |= UI_OPTION_ACCESSIBILITY_INVERTED_FLAG;
- }
- float fontScale = Settings.System.getFloat(contentResolver,
- Settings.System.FONT_SCALE, (float) 1.0);
- if (fontScale > 1.0) {
- uiOptionsAsFlags |= UI_OPTION_ACCESSIBILITY_MAGNIFIED_FLAG;
- }
- return uiOptionsAsFlags;
- }
-
- private int getUiOptionsAsFlags2() {
int uiOptionsAsFlags = 0;
ContentResolver contentResolver = mContext.getContentResolver();
int inversionEnabled = Settings.Secure.getInt(contentResolver,
@@ -349,52 +275,26 @@
mExecutor = executor;
String locale = Locale.getDefault().toLanguageTag();
- if (AndroidKeyStoreProvider.isKeystore2Enabled()) {
- int uiOptionsAsFlags = getUiOptionsAsFlags2();
- int responseCode = getService().presentConfirmationPrompt(
- mConfirmationCallback, mPromptText.toString(), mExtraData, locale,
- uiOptionsAsFlags);
- switch (responseCode) {
- case AndroidProtectedConfirmation.ERROR_OK:
- return;
+ int uiOptionsAsFlags = getUiOptionsAsFlags();
+ int responseCode = getService().presentConfirmationPrompt(
+ mConfirmationCallback, mPromptText.toString(), mExtraData, locale,
+ uiOptionsAsFlags);
+ switch (responseCode) {
+ case AndroidProtectedConfirmation.ERROR_OK:
+ return;
- case AndroidProtectedConfirmation.ERROR_OPERATION_PENDING:
- throw new ConfirmationAlreadyPresentingException();
+ case AndroidProtectedConfirmation.ERROR_OPERATION_PENDING:
+ throw new ConfirmationAlreadyPresentingException();
- case AndroidProtectedConfirmation.ERROR_UNIMPLEMENTED:
- throw new ConfirmationNotAvailableException();
+ case AndroidProtectedConfirmation.ERROR_UNIMPLEMENTED:
+ throw new ConfirmationNotAvailableException();
- default:
- // Unexpected error code.
- Log.w(TAG,
- "Unexpected responseCode=" + responseCode
- + " from presentConfirmationPrompt() call.");
- throw new IllegalArgumentException();
- }
- } else {
- int uiOptionsAsFlags = getUiOptionsAsFlags();
- int responseCode = mKeyStore.presentConfirmationPrompt(
- mCallbackBinder, mPromptText.toString(), mExtraData, locale, uiOptionsAsFlags);
- switch (responseCode) {
- case KeyStore.CONFIRMATIONUI_OK:
- return;
-
- case KeyStore.CONFIRMATIONUI_OPERATION_PENDING:
- throw new ConfirmationAlreadyPresentingException();
-
- case KeyStore.CONFIRMATIONUI_UNIMPLEMENTED:
- throw new ConfirmationNotAvailableException();
-
- case KeyStore.CONFIRMATIONUI_UIERROR:
- throw new IllegalArgumentException();
-
- default:
- // Unexpected error code.
- Log.w(TAG,
- "Unexpected responseCode=" + responseCode
- + " from presentConfirmationPrompt() call.");
- throw new IllegalArgumentException();
- }
+ default:
+ // Unexpected error code.
+ Log.w(TAG,
+ "Unexpected responseCode=" + responseCode
+ + " from presentConfirmationPrompt() call.");
+ throw new IllegalArgumentException();
}
}
@@ -408,33 +308,18 @@
* @throws IllegalStateException if no prompt is currently being presented.
*/
public void cancelPrompt() {
- if (AndroidKeyStoreProvider.isKeystore2Enabled()) {
- int responseCode =
- getService().cancelConfirmationPrompt(mConfirmationCallback);
- if (responseCode == AndroidProtectedConfirmation.ERROR_OK) {
- return;
- } else if (responseCode == AndroidProtectedConfirmation.ERROR_OPERATION_PENDING) {
- throw new IllegalStateException();
- } else {
- // Unexpected error code.
- Log.w(TAG,
- "Unexpected responseCode=" + responseCode
- + " from cancelConfirmationPrompt() call.");
- throw new IllegalStateException();
- }
+ int responseCode =
+ getService().cancelConfirmationPrompt(mConfirmationCallback);
+ if (responseCode == AndroidProtectedConfirmation.ERROR_OK) {
+ return;
+ } else if (responseCode == AndroidProtectedConfirmation.ERROR_OPERATION_PENDING) {
+ throw new IllegalStateException();
} else {
- int responseCode = mKeyStore.cancelConfirmationPrompt(mCallbackBinder);
- if (responseCode == KeyStore.CONFIRMATIONUI_OK) {
- return;
- } else if (responseCode == KeyStore.CONFIRMATIONUI_OPERATION_PENDING) {
- throw new IllegalStateException();
- } else {
- // Unexpected error code.
- Log.w(TAG,
- "Unexpected responseCode=" + responseCode
- + " from cancelConfirmationPrompt() call.");
- throw new IllegalStateException();
- }
+ // Unexpected error code.
+ Log.w(TAG,
+ "Unexpected responseCode=" + responseCode
+ + " from cancelConfirmationPrompt() call.");
+ throw new IllegalStateException();
}
}
@@ -448,9 +333,6 @@
if (isAccessibilityServiceRunning(context)) {
return false;
}
- if (AndroidKeyStoreProvider.isKeystore2Enabled()) {
- return new AndroidProtectedConfirmation().isConfirmationPromptSupported();
- }
- return KeyStore.getInstance().isConfirmationPromptSupported();
+ return new AndroidProtectedConfirmation().isConfirmationPromptSupported();
}
}
diff --git a/core/java/android/security/keymaster/KeymasterCertificateChain.aidl b/core/java/android/security/keymaster/KeymasterCertificateChain.aidl
new file mode 100644
index 0000000..e01db7a
--- /dev/null
+++ b/core/java/android/security/keymaster/KeymasterCertificateChain.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.keymaster;
+
+parcelable KeymasterCertificateChain;
diff --git a/core/java/android/security/keystore/recovery/RecoveryController.java b/core/java/android/security/keystore/recovery/RecoveryController.java
index 1dc7f71..17ad5f1 100644
--- a/core/java/android/security/keystore/recovery/RecoveryController.java
+++ b/core/java/android/security/keystore/recovery/RecoveryController.java
@@ -712,18 +712,10 @@
*/
@NonNull Key getKeyFromGrant(@NonNull String grantAlias)
throws UnrecoverableKeyException, KeyPermanentlyInvalidatedException {
- if (grantAlias.startsWith(APPLICATION_KEY_GRANT_PREFIX)) {
- return AndroidKeyStoreProvider
- .loadAndroidKeyStoreSecretKeyFromKeystore(
- KeyStore2.getInstance(),
- getGrantDescriptor(grantAlias));
- }
- // TODO(b/171305545): remove KeyStore1 logic.
- return android.security.keystore.AndroidKeyStoreProvider.loadAndroidKeyStoreKeyFromKeystore(
- mKeyStore,
- grantAlias,
- KeyStore.UID_SELF);
-
+ return AndroidKeyStoreProvider
+ .loadAndroidKeyStoreSecretKeyFromKeystore(
+ KeyStore2.getInstance(),
+ getGrantDescriptor(grantAlias));
}
private static final String APPLICATION_KEY_GRANT_PREFIX = "recoverable_key:";
diff --git a/core/java/android/speech/OWNERS b/core/java/android/speech/OWNERS
new file mode 100644
index 0000000..32f4822
--- /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 aea94bf..b29598e 100644
--- a/core/java/android/speech/SpeechRecognizer.java
+++ b/core/java/android/speech/SpeechRecognizer.java
@@ -205,6 +205,17 @@
* 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 @@
* {@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/util/TimeUtils.java b/core/java/android/util/TimeUtils.java
index cd6585c..5fd0c33 100644
--- a/core/java/android/util/TimeUtils.java
+++ b/core/java/android/util/TimeUtils.java
@@ -30,6 +30,7 @@
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
+import java.time.Instant;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.Calendar;
@@ -43,11 +44,39 @@
public class TimeUtils {
/** @hide */ public TimeUtils() {}
/** {@hide} */
- private static SimpleDateFormat sLoggingFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+ private static final SimpleDateFormat sLoggingFormat =
+ new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
/** @hide */
public static final SimpleDateFormat sDumpDateFormat =
new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
+
+ /**
+ * This timestamp is used in TimeUtils methods and by the SettingsUI to filter time zones
+ * to only "effective" ones in a country. It is compared against the notUsedAfter metadata that
+ * Android records for some time zones.
+ *
+ * <p>What is notUsedAfter?</p>
+ * Android chooses to avoid making users choose between functionally identical time zones at the
+ * expense of not being able to represent local times in the past.
+ *
+ * notUsedAfter exists because some time zones can "merge" with other time zones after a given
+ * point in time (i.e. they change to have identical transitions, offsets, display names, etc.).
+ * From the notUsedAfter time, the zone will express the same local time as the one it merged
+ * with.
+ *
+ * <p>Why hardcoded?</p>
+ * Rather than using System.currentTimeMillis(), a timestamp known to be in the recent past is
+ * used to ensure consistent behavior across devices and time, and avoid assumptions that the
+ * system clock on a device is currently set correctly. The fixed value should be updated
+ * occasionally, but it doesn't have to be very often as effective time zones for a country
+ * don't change very often.
+ *
+ * @hide
+ */
+ public static final Instant MIN_USE_DATE_OF_TIMEZONE =
+ Instant.ofEpochMilli(1546300800000L); // 1/1/2019 00:00 UTC
+
/**
* Tries to return a time zone that would have had the specified offset
* and DST value at the specified moment in the specified country.
@@ -109,7 +138,7 @@
List<String> timeZoneIds = new ArrayList<>();
for (TimeZoneMapping timeZoneMapping : countryTimeZones.getTimeZoneMappings()) {
- if (timeZoneMapping.isShownInPicker()) {
+ if (timeZoneMapping.isShownInPickerAt(MIN_USE_DATE_OF_TIMEZONE)) {
timeZoneIds.add(timeZoneMapping.getTimeZoneId());
}
}
diff --git a/core/java/android/uwb/DistanceMeasurement.java b/core/java/android/uwb/DistanceMeasurement.java
index 2a9bbdf..9856553 100644
--- a/core/java/android/uwb/DistanceMeasurement.java
+++ b/core/java/android/uwb/DistanceMeasurement.java
@@ -60,6 +60,7 @@
*
* @return error of distance measurement in meters
*/
+ @FloatRange(from = 0.0)
public double getErrorMeters() {
return mErrorMeters;
}
@@ -162,7 +163,7 @@
* @throws IllegalArgumentException if error is negative or NaN
*/
@NonNull
- public Builder setErrorMeters(double errorMeters) {
+ public Builder setErrorMeters(@FloatRange(from = 0.0) double errorMeters) {
if (Double.isNaN(errorMeters) || errorMeters < 0.0) {
throw new IllegalArgumentException(
"errorMeters must be >= 0.0 and not NaN: " + errorMeters);
@@ -178,7 +179,8 @@
* @throws IllegalArgumentException if confidence level is not in the range of [0.0, 1.0]
*/
@NonNull
- public Builder setConfidenceLevel(double confidenceLevel) {
+ public Builder setConfidenceLevel(
+ @FloatRange(from = 0.0, to = 1.0) double confidenceLevel) {
if (confidenceLevel < 0.0 || confidenceLevel > 1.0) {
throw new IllegalArgumentException(
"confidenceLevel must be in the range [0.0, 1.0]: " + confidenceLevel);
diff --git a/core/java/android/uwb/IUwbAdapter.aidl b/core/java/android/uwb/IUwbAdapter.aidl
index 4036892..30da248 100644
--- a/core/java/android/uwb/IUwbAdapter.aidl
+++ b/core/java/android/uwb/IUwbAdapter.aidl
@@ -160,14 +160,4 @@
* closed.
*/
const int RANGING_SESSION_CLOSE_THRESHOLD_MS = 3000; // Value TBD
-
- /**
- * Ranging scheduling time unit (RSTU) for High Rate Pulse (HRP) PHY
- */
- const int HIGH_RATE_PULSE_CHIRPS_PER_RSTU = 416;
-
- /**
- * Ranging scheduling time unit (RSTU) for Low Rate Pulse (LRP) PHY
- */
- const int LOW_RATE_PULSE_CHIRPS_PER_RSTU = 1;
}
diff --git a/core/java/android/view/OWNERS b/core/java/android/view/OWNERS
index 31f6f6a..cdf1e46 100644
--- a/core/java/android/view/OWNERS
+++ b/core/java/android/view/OWNERS
@@ -9,6 +9,7 @@
ogunwale@google.com
jjaggi@google.com
roosa@google.com
+jreck@google.com
# Display
per-file Display*.java = file:/services/core/java/com/android/server/display/OWNERS
@@ -58,6 +59,10 @@
per-file ViewRootImpl.java = file:/services/core/java/com/android/server/wm/OWNERS
per-file ViewRootImpl.java = file:/core/java/android/view/inputmethod/OWNERS
per-file AccessibilityInteractionController.java = file:/services/accessibility/OWNERS
+per-file OnReceiveContentListener.java = file:/core/java/android/service/autofill/OWNERS
+per-file OnReceiveContentListener.java = file:/core/java/android/widget/OWNERS
+per-file ContentInfo.java = file:/core/java/android/service/autofill/OWNERS
+per-file ContentInfo.java = file:/core/java/android/widget/OWNERS
# WindowManager
per-file DisplayCutout.aidl = file:/services/core/java/com/android/server/wm/OWNERS
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index a785a1a..51396db 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -4679,6 +4679,7 @@
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/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl
index beef982..0b78a2b 100644
--- a/core/java/com/android/internal/app/IBatteryStats.aidl
+++ b/core/java/com/android/internal/app/IBatteryStats.aidl
@@ -32,7 +32,7 @@
interface IBatteryStats {
// These first methods are also called by native code, so must
- // be kept in sync with frameworks/native/libs/binder/include/binder/IBatteryStats.h
+ // be kept in sync with frameworks/native/libs/binder/include_batterystats/batterystats/IBatteryStats.h
void noteStartSensor(int uid, int sensor);
void noteStopSensor(int uid, int sensor);
void noteStartVideo(int uid);
diff --git a/core/java/com/android/internal/os/BINDER_OWNERS b/core/java/com/android/internal/os/BINDER_OWNERS
new file mode 100644
index 0000000..9f68a32
--- /dev/null
+++ b/core/java/com/android/internal/os/BINDER_OWNERS
@@ -0,0 +1,2 @@
+dplotnikov@google.com
+gaillard@google.com
diff --git a/core/java/com/android/internal/os/OWNERS b/core/java/com/android/internal/os/OWNERS
index 3f01ebb..ea3b3a7 100644
--- a/core/java/com/android/internal/os/OWNERS
+++ b/core/java/com/android/internal/os/OWNERS
@@ -1,6 +1,7 @@
per-file *Power* = file:/services/core/java/com/android/server/power/OWNERS
per-file *Zygote* = file:/ZYGOTE_OWNERS
per-file *Cpu* = file:CPU_OWNERS
+per-file *Binder* = file:BINDER_OWNERS
# BatteryStats
per-file BatterySipper.java = file:/BATTERY_STATS_OWNERS
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 5fea76a..a541089 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -41,6 +41,7 @@
import android.os.ZygoteProcess;
import android.os.storage.StorageManager;
import android.provider.DeviceConfig;
+import android.security.keystore2.AndroidKeyStoreProvider;
import android.system.ErrnoException;
import android.system.Os;
import android.system.OsConstants;
@@ -222,10 +223,8 @@
long startTime = SystemClock.uptimeMillis();
Trace.traceBegin(
Trace.TRACE_TAG_DALVIK, "Starting installation of AndroidKeyStoreProvider");
- // AndroidKeyStoreProvider.install() manipulates the list of JCA providers to insert
- // preferred providers. Note this is not done via security.properties as the JCA providers
- // are not on the classpath in the case of, for example, raw dalvikvm runtimes.
- android.security.keystore2.AndroidKeyStoreProvider.install();
+
+ AndroidKeyStoreProvider.install();
Log.i(TAG, "Installed AndroidKeyStoreProvider in "
+ (SystemClock.uptimeMillis() - startTime) + "ms.");
Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
diff --git a/core/java/com/android/internal/os/ZygoteServer.java b/core/java/com/android/internal/os/ZygoteServer.java
index f71b314..4d2266b 100644
--- a/core/java/com/android/internal/os/ZygoteServer.java
+++ b/core/java/com/android/internal/os/ZygoteServer.java
@@ -547,7 +547,7 @@
try {
ZygoteConnection connection = peers.get(pollIndex);
boolean multipleForksOK = !isUsapPoolEnabled()
- && ZygoteHooks.indefiniteThreadSuspensionOK();
+ && ZygoteHooks.isIndefiniteThreadSuspensionSafe();
final Runnable command =
connection.processCommand(this, multipleForksOK);
diff --git a/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
index 0e35c84..965971d 100644
--- a/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
+++ b/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
@@ -60,7 +60,6 @@
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/java/com/android/internal/util/TrafficStatsConstants.java b/core/java/com/android/internal/util/TrafficStatsConstants.java
index 413be48..131114c 100644
--- a/core/java/com/android/internal/util/TrafficStatsConstants.java
+++ b/core/java/com/android/internal/util/TrafficStatsConstants.java
@@ -21,24 +21,8 @@
* @hide
*/
public class TrafficStatsConstants {
- // These tags are used by the network stack to do traffic for its own purposes. Traffic
- // tagged with these will be counted toward the network stack and must stay inside the
- // range defined by
- // {@link android.net.TrafficStats#TAG_NETWORK_STACK_RANGE_START} and
- // {@link android.net.TrafficStats#TAG_NETWORK_STACK_RANGE_END}.
- public static final int TAG_SYSTEM_DHCP = 0xFFFFFE01;
- public static final int TAG_SYSTEM_NEIGHBOR = 0xFFFFFE02;
- public static final int TAG_SYSTEM_DHCP_SERVER = 0xFFFFFE03;
public static final int TAG_SYSTEM_NTP = 0xFFFFFF41;
public static final int TAG_SYSTEM_GPS = 0xFFFFFF44;
public static final int TAG_SYSTEM_PAC = 0xFFFFFF45;
-
- // These tags are used by the network stack to do traffic on behalf of apps. Traffic
- // tagged with these will be counted toward the app on behalf of which the network
- // stack is doing this traffic. These values must stay inside the range defined by
- // {@link android.net.TrafficStats#TAG_NETWORK_STACK_IMPERSONATION_RANGE_START} and
- // {@link android.net.TrafficStats#TAG_NETWORK_STACK_IMPERSONATION_RANGE_END}.
- public static final int TAG_SYSTEM_PROBE = 0xFFFFFF81;
- public static final int TAG_SYSTEM_DNS = 0xFFFFFF82;
}
diff --git a/core/jni/OWNERS b/core/jni/OWNERS
index c0c4b70..07fb729 100644
--- a/core/jni/OWNERS
+++ b/core/jni/OWNERS
@@ -50,7 +50,6 @@
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_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 a781a37..1cee895 100644
--- a/core/jni/android_net_NetworkUtils.cpp
+++ b/core/jni/android_net_NetworkUtils.cpp
@@ -102,11 +102,6 @@
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 @@
{ "getBoundNetworkForProcess", "()I", (void*) android_net_utils_getBoundNetworkForProcess },
{ "bindProcessToNetworkForHostResolution", "(I)Z", (void*) android_net_utils_bindProcessToNetworkForHostResolution },
{ "bindSocketToNetwork", "(Ljava/io/FileDescriptor;I)I", (void*) android_net_utils_bindSocketToNetwork },
- { "queryUserAccess", "(II)Z", (void*)android_net_utils_queryUserAccess },
{ "attachDropAllBPFFilter", "(Ljava/io/FileDescriptor;)V", (void*) android_net_utils_attachDropAllBPFFilter },
{ "detachBPFFilter", "(Ljava/io/FileDescriptor;)V", (void*) android_net_utils_detachBPFFilter },
{ "getTcpRepairWindow", "(Ljava/io/FileDescriptor;)Landroid/net/TcpRepairWindow;", (void*) android_net_utils_getTcpRepairWindow },
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index 2499504..e4dddd2 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -486,9 +486,15 @@
}
void markVintf() {
+ AutoMutex _l(mLock);
mVintf = true;
}
+ void forceDowngradeToSystemStability() {
+ AutoMutex _l(mLock);
+ mVintf = false;
+ }
+
sp<IBinder> getExtension() {
AutoMutex _l(mLock);
sp<JavaBBinder> b = mBinder.promote();
@@ -1013,6 +1019,12 @@
jbh->markVintf();
}
+static void android_os_Binder_forceDowngradeToSystemStability(JNIEnv* env, jobject clazz) {
+ JavaBBinderHolder* jbh =
+ (JavaBBinderHolder*) env->GetLongField(clazz, gBinderOffsets.mObject);
+ jbh->forceDowngradeToSystemStability();
+}
+
static void android_os_Binder_flushPendingCommands(JNIEnv* env, jobject clazz)
{
IPCThreadState::self()->flushCommands();
@@ -1076,6 +1088,7 @@
{ "clearCallingWorkSource", "()J", (void*)android_os_Binder_clearCallingWorkSource },
{ "restoreCallingWorkSource", "(J)V", (void*)android_os_Binder_restoreCallingWorkSource },
{ "markVintfStability", "()V", (void*)android_os_Binder_markVintfStability},
+ { "forceDowngradeToSystemStability", "()V", (void*)android_os_Binder_forceDowngradeToSystemStability},
{ "flushPendingCommands", "()V", (void*)android_os_Binder_flushPendingCommands },
{ "getNativeBBinderHolder", "()J", (void*)android_os_Binder_getNativeBBinderHolder },
{ "getNativeFinalizer", "()J", (void*)android_os_Binder_getNativeFinalizer },
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 836074f..6ac43bd3 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -1015,21 +1015,6 @@
gUsapPoolCount = 0;
}
-NO_PAC_FUNC
-static void PAuthKeyChange(JNIEnv* env) {
-#ifdef __aarch64__
- unsigned long int hwcaps = getauxval(AT_HWCAP);
- if (hwcaps & HWCAP_PACA) {
- const unsigned long key_mask = PR_PAC_APIAKEY | PR_PAC_APIBKEY |
- PR_PAC_APDAKEY | PR_PAC_APDBKEY | PR_PAC_APGAKEY;
- if (prctl(PR_PAC_RESET_KEYS, key_mask, 0, 0, 0) != 0) {
- ALOGE("Failed to change the PAC keys: %s", strerror(errno));
- RuntimeAbort(env, __LINE__, "PAC key change failed.");
- }
- }
-#endif
-}
-
// Create an app data directory over tmpfs overlayed CE / DE storage, and bind mount it
// from the actual app data directory in data mirror.
static bool createAndMountAppData(std::string_view package_name,
@@ -1980,7 +1965,6 @@
}
// Utility routine to fork a process from the zygote.
-NO_PAC_FUNC
pid_t zygote::ForkCommon(JNIEnv* env, bool is_system_server,
const std::vector<int>& fds_to_close,
const std::vector<int>& fds_to_ignore,
@@ -2035,7 +2019,6 @@
}
// The child process.
- PAuthKeyChange(env);
PreApplicationInit();
// Clean up any descriptors which must be closed immediately
@@ -2067,7 +2050,6 @@
PreApplicationInit();
}
-NO_PAC_FUNC
static jint com_android_internal_os_Zygote_nativeForkAndSpecialize(
JNIEnv* env, jclass, jint uid, jint gid, jintArray gids, jint runtime_flags,
jobjectArray rlimits, jint mount_external, jstring se_info, jstring nice_name,
@@ -2117,7 +2099,6 @@
return pid;
}
-NO_PAC_FUNC
static jint com_android_internal_os_Zygote_nativeForkSystemServer(
JNIEnv* env, jclass, uid_t uid, gid_t gid, jintArray gids,
jint runtime_flags, jobjectArray rlimits, jlong permitted_capabilities,
@@ -2189,7 +2170,6 @@
* @param is_priority_fork Controls the nice level assigned to the newly created process
* @return child pid in the parent, 0 in the child
*/
-NO_PAC_FUNC
static jint com_android_internal_os_Zygote_nativeForkApp(JNIEnv* env,
jclass,
jint read_pipe_fd,
@@ -2204,7 +2184,6 @@
args_known == JNI_TRUE, is_priority_fork == JNI_TRUE, true);
}
-NO_PAC_FUNC
int zygote::forkApp(JNIEnv* env,
int read_pipe_fd,
int write_pipe_fd,
diff --git a/core/jni/com_android_internal_os_Zygote.h b/core/jni/com_android_internal_os_Zygote.h
index d2da914..b87396c 100644
--- a/core/jni/com_android_internal_os_Zygote.h
+++ b/core/jni/com_android_internal_os_Zygote.h
@@ -20,18 +20,6 @@
#define LOG_TAG "Zygote"
#define ATRACE_TAG ATRACE_TAG_DALVIK
-/* Functions in the callchain during the fork shall not be protected with
- Armv8.3-A Pointer Authentication, otherwise child will not be able to return. */
-#ifdef __ARM_FEATURE_PAC_DEFAULT
-#ifdef __ARM_FEATURE_BTI_DEFAULT
-#define NO_PAC_FUNC __attribute__((target("branch-protection=bti")))
-#else
-#define NO_PAC_FUNC __attribute__((target("branch-protection=none")))
-#endif /* __ARM_FEATURE_BTI_DEFAULT */
-#else /* !__ARM_FEATURE_PAC_DEFAULT */
-#define NO_PAC_FUNC
-#endif /* __ARM_FEATURE_PAC_DEFAULT */
-
#include <jni.h>
#include <vector>
#include <android-base/stringprintf.h>
@@ -42,7 +30,6 @@
namespace android {
namespace zygote {
-NO_PAC_FUNC
pid_t ForkCommon(JNIEnv* env,bool is_system_server,
const std::vector<int>& fds_to_close,
const std::vector<int>& fds_to_ignore,
@@ -57,7 +44,6 @@
* communication is required. Is_priority_fork should be true if this is on the app startup
* critical path. Purge specifies that unused pages should be purged before the fork.
*/
-NO_PAC_FUNC
int forkApp(JNIEnv* env,
int read_pipe_fd,
int write_pipe_fd,
diff --git a/core/jni/com_android_internal_os_ZygoteCommandBuffer.cpp b/core/jni/com_android_internal_os_ZygoteCommandBuffer.cpp
index 011e8f8..24fef48 100644
--- a/core/jni/com_android_internal_os_ZygoteCommandBuffer.cpp
+++ b/core/jni/com_android_internal_os_ZygoteCommandBuffer.cpp
@@ -365,7 +365,6 @@
// We only process fork commands if the peer uid matches expected_uid.
// For every fork command after the first, we check that the requested uid is at
// least minUid.
-NO_PAC_FUNC
jboolean com_android_internal_os_ZygoteCommandBuffer_nativeForkRepeatedly(
JNIEnv* env,
jclass,
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index f65d7a7..cc4e2bb 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -313,7 +313,6 @@
<protected-broadcast android:name="android.se.omapi.action.SECURE_ELEMENT_STATE_CHANGED" />
<protected-broadcast android:name="android.nfc.action.ADAPTER_STATE_CHANGED" />
- <protected-broadcast android:name="android.nfc.action.ALWAYS_ON_STATE_CHANGED" />
<protected-broadcast android:name="android.nfc.action.PREFERRED_PAYMENT_CHANGED" />
<protected-broadcast android:name="android.nfc.action.TRANSACTION_DETECTED" />
<protected-broadcast android:name="android.nfc.action.REQUIRE_UNLOCK_FOR_NFC" />
@@ -333,7 +332,7 @@
<protected-broadcast android:name="android.nfc.handover.intent.action.HANDOVER_SEND_MULTIPLE" />
<protected-broadcast android:name="com.android.nfc.handover.action.CANCEL_HANDOVER_TRANSFER" />
- <protected-broadcast android:name="android.intent.action.CLEAR_DNS_CACHE" />
+ <protected-broadcast android:name="android.net.action.CLEAR_DNS_CACHE" />
<protected-broadcast android:name="android.intent.action.PROXY_CHANGE" />
<protected-broadcast android:name="android.os.UpdateLock.UPDATE_LOCK_CHANGED" />
@@ -1882,6 +1881,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 +2550,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 +2557,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 +4112,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 +4594,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 8db991b..bfe7802 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 46efd2c..2901de5 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/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp
index 510578e..5045e3b 100644
--- a/core/tests/coretests/Android.bp
+++ b/core/tests/coretests/Android.bp
@@ -61,7 +61,6 @@
"org.apache.http.legacy",
"android.test.base",
"android.test.mock",
- "framework-atb-backward-compatibility",
"framework",
"ext",
"framework-res",
diff --git a/core/tests/coretests/src/android/view/OWNERS b/core/tests/coretests/src/android/view/OWNERS
index fa1aa5e..74cdd21 100644
--- a/core/tests/coretests/src/android/view/OWNERS
+++ b/core/tests/coretests/src/android/view/OWNERS
@@ -1,3 +1,6 @@
+# Accessibility
+per-file WindowInfoTest.java = file:/services/accessibility/OWNERS
+
# Input
per-file *MotionEventTest.* = file:/services/core/java/com/android/server/input/OWNERS
per-file *KeyEventTest.* = file:/services/core/java/com/android/server/input/OWNERS
@@ -9,6 +12,7 @@
per-file *Insets* = file:/services/core/java/com/android/server/wm/OWNERS
per-file *View* = file:/services/core/java/com/android/server/wm/OWNERS
per-file *Visibility* = file:/services/core/java/com/android/server/wm/OWNERS
+per-file *Window* = file:/services/core/java/com/android/server/wm/OWNERS
# Scroll Capture
per-file *ScrollCapture*.java = file:/packages/SystemUI/src/com/android/systemui/screenshot/OWNERS
diff --git a/core/tests/coretests/src/android/window/OWNERS b/core/tests/coretests/src/android/window/OWNERS
new file mode 100644
index 0000000..6c80cf9
--- /dev/null
+++ b/core/tests/coretests/src/android/window/OWNERS
@@ -0,0 +1,2 @@
+include /services/core/java/com/android/server/wm/OWNERS
+charlesccchen@google.com
diff --git a/data/etc/OWNERS b/data/etc/OWNERS
index 549e074..5aacfdd 100644
--- a/data/etc/OWNERS
+++ b/data/etc/OWNERS
@@ -13,3 +13,4 @@
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 81347d1..aef68d0 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -445,6 +445,8 @@
<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" />
@@ -453,6 +455,10 @@
<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 d2b47c6..4c214b5 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 0000000..21fc018
--- /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 0000000..63d1f6d
--- /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/graphics/java/android/graphics/RecordingCanvas.java b/graphics/java/android/graphics/RecordingCanvas.java
index c0e0a24..4a24b42 100644
--- a/graphics/java/android/graphics/RecordingCanvas.java
+++ b/graphics/java/android/graphics/RecordingCanvas.java
@@ -21,6 +21,7 @@
import android.util.Pools.SynchronizedPool;
import android.view.DisplayListCanvas;
import android.view.TextureLayer;
+import android.os.SystemProperties;
import dalvik.annotation.optimization.CriticalNative;
import dalvik.annotation.optimization.FastNative;
@@ -41,7 +42,14 @@
private static final int POOL_LIMIT = 25;
/** @hide */
- public static final int MAX_BITMAP_SIZE = 100 * 1024 * 1024; // 100 MB
+ private static int getPanelFrameSize() {
+ final int DefaultSize = 100 * 1024 * 1024; // 100 MB;
+ return Math.max(SystemProperties.getInt("ro.hwui.max_texture_allocation_size", DefaultSize),
+ DefaultSize);
+ }
+
+ /** @hide */
+ public static final int MAX_BITMAP_SIZE = getPanelFrameSize();
private static final SynchronizedPool<RecordingCanvas> sPool =
new SynchronizedPool<>(POOL_LIMIT);
diff --git a/identity/Android.bp b/identity/Android.bp
new file mode 100644
index 0000000..826d6f8
--- /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 0000000..a193d97
--- /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 0000000..87707a8
--- /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 0000000..21edff1
--- /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/AndroidKeyStoreMaintenance.java b/keystore/java/android/security/AndroidKeyStoreMaintenance.java
index 72cea0c..82639de 100644
--- a/keystore/java/android/security/AndroidKeyStoreMaintenance.java
+++ b/keystore/java/android/security/AndroidKeyStoreMaintenance.java
@@ -47,7 +47,6 @@
* @hide
*/
public static int onUserAdded(@NonNull int userId) {
- if (!android.security.keystore2.AndroidKeyStoreProvider.isInstalled()) return 0;
try {
getService().onUserAdded(userId);
return 0;
@@ -68,7 +67,6 @@
* @hide
*/
public static int onUserRemoved(int userId) {
- if (!android.security.keystore2.AndroidKeyStoreProvider.isInstalled()) return 0;
try {
getService().onUserRemoved(userId);
return 0;
@@ -91,7 +89,6 @@
* @hide
*/
public static int onUserPasswordChanged(int userId, @Nullable byte[] password) {
- if (!android.security.keystore2.AndroidKeyStoreProvider.isInstalled()) return 0;
try {
getService().onUserPasswordChanged(userId, password);
return 0;
@@ -109,7 +106,6 @@
* be cleared.
*/
public static int clearNamespace(@Domain int domain, long namespace) {
- if (!android.security.keystore2.AndroidKeyStoreProvider.isInstalled()) return 0;
try {
getService().clearNamespace(domain, namespace);
return 0;
@@ -144,7 +140,6 @@
* Informs Keystore 2.0 that an off body event was detected.
*/
public static void onDeviceOffBody() {
- if (!android.security.keystore2.AndroidKeyStoreProvider.isInstalled()) return;
try {
getService().onDeviceOffBody();
} catch (Exception e) {
diff --git a/keystore/java/android/security/Authorization.java b/keystore/java/android/security/Authorization.java
index 50a9082..bd72d45 100644
--- a/keystore/java/android/security/Authorization.java
+++ b/keystore/java/android/security/Authorization.java
@@ -48,7 +48,6 @@
* @return 0 if successful or {@code ResponseCode.SYSTEM_ERROR}.
*/
public static int addAuthToken(@NonNull HardwareAuthToken authToken) {
- if (!android.security.keystore2.AndroidKeyStoreProvider.isInstalled()) return 0;
try {
getService().addAuthToken(authToken);
return 0;
@@ -80,7 +79,6 @@
*/
public static int onLockScreenEvent(@NonNull boolean locked, @NonNull int userId,
@Nullable byte[] syntheticPassword) {
- if (!android.security.keystore2.AndroidKeyStoreProvider.isInstalled()) return 0;
try {
if (locked) {
getService().onLockScreenEvent(LockScreenEvent.LOCK, userId, null);
diff --git a/keystore/java/android/security/Credentials.java b/keystore/java/android/security/Credentials.java
index ae9f866..28c601b 100644
--- a/keystore/java/android/security/Credentials.java
+++ b/keystore/java/android/security/Credentials.java
@@ -208,78 +208,4 @@
pr.close();
}
}
-
- /**
- * Delete all types (private key, user certificate, CA certificate) for a
- * particular {@code alias}. All three can exist for any given alias.
- * Returns {@code true} if the alias no longer contains any types.
- */
- public static boolean deleteAllTypesForAlias(KeyStore keystore, String alias) {
- return deleteAllTypesForAlias(keystore, alias, KeyStore.UID_SELF);
- }
-
- /**
- * Delete all types (private key, user certificate, CA certificate) for a
- * particular {@code alias}. All three can exist for any given alias.
- * Returns {@code true} if the alias no longer contains any types.
- */
- public static boolean deleteAllTypesForAlias(KeyStore keystore, String alias, int uid) {
- /*
- * Make sure every type is deleted. There can be all three types, so
- * don't use a conditional here.
- */
- return deleteUserKeyTypeForAlias(keystore, alias, uid)
- & deleteCertificateTypesForAlias(keystore, alias, uid);
- }
-
- /**
- * Delete certificate types (user certificate, CA certificate) for a
- * particular {@code alias}. Both can exist for any given alias.
- * Returns {@code true} if the alias no longer contains either type.
- */
- public static boolean deleteCertificateTypesForAlias(KeyStore keystore, String alias) {
- return deleteCertificateTypesForAlias(keystore, alias, KeyStore.UID_SELF);
- }
-
- /**
- * Delete certificate types (user certificate, CA certificate) for a
- * particular {@code alias}. Both can exist for any given alias.
- * Returns {@code true} if the alias no longer contains either type.
- */
- public static boolean deleteCertificateTypesForAlias(KeyStore keystore, String alias, int uid) {
- /*
- * Make sure every certificate type is deleted. There can be two types,
- * so don't use a conditional here.
- */
- return keystore.delete(Credentials.USER_CERTIFICATE + alias, uid)
- & keystore.delete(Credentials.CA_CERTIFICATE + alias, uid);
- }
-
- /**
- * Delete user key for a particular {@code alias}.
- * Returns {@code true} if the entry no longer exists.
- */
- public static boolean deleteUserKeyTypeForAlias(KeyStore keystore, String alias) {
- return deleteUserKeyTypeForAlias(keystore, alias, KeyStore.UID_SELF);
- }
-
- /**
- * Delete user key for a particular {@code alias}.
- * Returns {@code true} if the entry no longer exists.
- */
- public static boolean deleteUserKeyTypeForAlias(KeyStore keystore, String alias, int uid) {
- int ret = keystore.delete2(Credentials.USER_PRIVATE_KEY + alias, uid);
- if (ret == KeyStore.KEY_NOT_FOUND) {
- return keystore.delete(Credentials.USER_SECRET_KEY + alias, uid);
- }
- return ret == KeyStore.NO_ERROR;
- }
-
- /**
- * Delete legacy prefixed entry for a particular {@code alias}
- * Returns {@code true} if the entry no longer exists.
- */
- public static boolean deleteLegacyKeyForAlias(KeyStore keystore, String alias, int uid) {
- return keystore.delete(Credentials.USER_SECRET_KEY + alias, uid);
- }
}
diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java
index d59ca98..fd0db93 100644
--- a/keystore/java/android/security/KeyChain.java
+++ b/keystore/java/android/security/KeyChain.java
@@ -37,7 +37,6 @@
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
-import android.security.keystore.AndroidKeyStoreProvider;
import android.security.keystore.KeyPermanentlyInvalidatedException;
import android.security.keystore.KeyProperties;
import android.system.keystore2.Domain;
@@ -676,23 +675,13 @@
return null;
}
- if (AndroidKeyStoreProvider.isKeystore2Enabled()) {
- try {
- return android.security.keystore2.AndroidKeyStoreProvider
- .loadAndroidKeyStoreKeyPairFromKeystore(
- KeyStore2.getInstance(),
- getGrantDescriptor(keyId));
- } catch (UnrecoverableKeyException | KeyPermanentlyInvalidatedException e) {
- throw new KeyChainException(e);
- }
- } else {
- try {
- return AndroidKeyStoreProvider.loadAndroidKeyStoreKeyPairFromKeystore(
- KeyStore.getInstance(), keyId, KeyStore.UID_SELF);
- } catch (RuntimeException | UnrecoverableKeyException
- | KeyPermanentlyInvalidatedException e) {
- throw new KeyChainException(e);
- }
+ try {
+ return android.security.keystore2.AndroidKeyStoreProvider
+ .loadAndroidKeyStoreKeyPairFromKeystore(
+ KeyStore2.getInstance(),
+ getGrantDescriptor(keyId));
+ } catch (UnrecoverableKeyException | KeyPermanentlyInvalidatedException e) {
+ throw new KeyChainException(e);
}
}
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index b05149e..a954344 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -16,53 +16,11 @@
package android.security;
-import android.app.ActivityThread;
-import android.app.Application;
-import android.app.KeyguardManager;
import android.compat.annotation.UnsupportedAppUsage;
-import android.content.Context;
-import android.hardware.biometrics.BiometricManager;
-import android.os.Binder;
import android.os.Build;
-import android.os.IBinder;
-import android.os.Process;
-import android.os.RemoteException;
-import android.os.ServiceManager;
import android.os.UserHandle;
-import android.security.keymaster.ExportResult;
-import android.security.keymaster.KeyCharacteristics;
-import android.security.keymaster.KeymasterArguments;
-import android.security.keymaster.KeymasterBlob;
-import android.security.keymaster.KeymasterCertificateChain;
-import android.security.keymaster.KeymasterDefs;
-import android.security.keymaster.OperationResult;
-import android.security.keystore.IKeystoreService;
-import android.security.keystore.KeyExpiredException;
-import android.security.keystore.KeyNotYetValidException;
-import android.security.keystore.KeyPermanentlyInvalidatedException;
-import android.security.keystore.KeyProperties;
-import android.security.keystore.KeystoreResponse;
-import android.security.keystore.UserNotAuthenticatedException;
import android.security.maintenance.UserState;
import android.system.keystore2.Domain;
-import android.util.Log;
-
-import com.android.internal.org.bouncycastle.asn1.ASN1InputStream;
-import com.android.internal.org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.math.BigInteger;
-import java.security.InvalidKeyException;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
-import java.util.Locale;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.ExecutionException;
-
-import sun.security.util.ObjectIdentifier;
-import sun.security.x509.AlgorithmId;
/**
* @hide This should not be made public in its present form because it
@@ -75,79 +33,10 @@
// ResponseCodes - see system/security/keystore/include/keystore/keystore.h
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public static final int NO_ERROR = 1;
- public static final int LOCKED = 2;
- public static final int UNINITIALIZED = 3;
- public static final int SYSTEM_ERROR = 4;
- public static final int PROTOCOL_ERROR = 5;
- public static final int PERMISSION_DENIED = 6;
- public static final int KEY_NOT_FOUND = 7;
- public static final int VALUE_CORRUPTED = 8;
- public static final int UNDEFINED_ACTION = 9;
- public static final int WRONG_PASSWORD = 10;
- public static final int KEY_ALREADY_EXISTS = 16;
- public static final int CANNOT_ATTEST_IDS = -66;
- public static final int HARDWARE_TYPE_UNAVAILABLE = -68;
-
- /**
- * Per operation authentication is needed before this operation is valid.
- * This is returned from {@link #begin} when begin succeeds but the operation uses
- * per-operation authentication and must authenticate before calling {@link #update} or
- * {@link #finish}.
- */
- public static final int OP_AUTH_NEEDED = 15;
-
- // Used when a user changes their pin, invalidating old auth bound keys.
- public static final int KEY_PERMANENTLY_INVALIDATED = 17;
// Used for UID field to indicate the calling UID.
public static final int UID_SELF = -1;
- // Flags for "put" "import" and "generate"
- public static final int FLAG_NONE = 0;
-
- /**
- * Indicates that this key (or key pair) must be encrypted at rest. This will protect the key
- * (or key pair) with the secure lock screen credential (e.g., password, PIN, or pattern).
- *
- * <p>Note that this requires that the secure lock screen (e.g., password, PIN, pattern) is set
- * up, otherwise key (or key pair) generation or import will fail. Moreover, this key (or key
- * pair) will be deleted when the secure lock screen is disabled or reset (e.g., by the user or
- * a Device Administrator). Finally, this key (or key pair) cannot be used until the user
- * unlocks the secure lock screen after boot.
- *
- * @see KeyguardManager#isDeviceSecure()
- */
- public static final int FLAG_ENCRYPTED = 1;
-
- /**
- * Select Software keymaster device, which as of this writing is the lowest security
- * level available on an android device. If neither FLAG_STRONGBOX nor FLAG_SOFTWARE is provided
- * A TEE based keymaster implementation is implied.
- *
- * Need to be in sync with KeyStoreFlag in system/security/keystore/include/keystore/keystore.h
- * For historical reasons this corresponds to the KEYSTORE_FLAG_FALLBACK flag.
- */
- public static final int FLAG_SOFTWARE = 1 << 1;
-
- /**
- * A private flag that's only available to system server to indicate that this key is part of
- * device encryption flow so it receives special treatment from keystore. For example this key
- * will not be super encrypted, and it will be stored separately under an unique UID instead
- * of the caller UID i.e. SYSTEM.
- *
- * Need to be in sync with KeyStoreFlag in system/security/keystore/include/keystore/keystore.h
- */
- public static final int FLAG_CRITICAL_TO_DEVICE_ENCRYPTION = 1 << 3;
-
- /**
- * Select Strongbox keymaster device, which as of this writing the the highest security level
- * available an android devices. If neither FLAG_STRONGBOX nor FLAG_SOFTWARE is provided
- * A TEE based keymaster implementation is implied.
- *
- * Need to be in sync with KeyStoreFlag in system/security/keystore/include/keystore/keystore.h
- */
- public static final int FLAG_STRONGBOX = 1 << 4;
-
// States
public enum State {
@UnsupportedAppUsage
@@ -157,853 +46,87 @@
UNINITIALIZED
};
- private int mError = NO_ERROR;
-
- private final IKeystoreService mBinder;
- private final Context mContext;
-
- private IBinder mToken;
-
- private KeyStore(IKeystoreService binder) {
- mBinder = binder;
- mContext = getApplicationContext();
- }
-
- @UnsupportedAppUsage
- public static Context getApplicationContext() {
- Application application = ActivityThread.currentApplication();
- if (application == null) {
- throw new IllegalStateException(
- "Failed to obtain application Context from ActivityThread");
- }
- return application;
- }
+ private static final KeyStore KEY_STORE = new KeyStore();
@UnsupportedAppUsage
public static KeyStore getInstance() {
- IKeystoreService keystore = IKeystoreService.Stub.asInterface(ServiceManager
- .getService("android.security.keystore"));
- return new KeyStore(keystore);
+ return KEY_STORE;
}
- private synchronized IBinder getToken() {
- if (mToken == null) {
- mToken = new Binder();
- }
- return mToken;
- }
-
+ /** @hide */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public State state(int userId) {
- final int ret;
- try {
- if (android.security.keystore2.AndroidKeyStoreProvider.isInstalled()) {
- int userState = AndroidKeyStoreMaintenance.getState(userId);
- switch (userState) {
- case UserState.UNINITIALIZED:
- return KeyStore.State.UNINITIALIZED;
- case UserState.LSKF_UNLOCKED:
- return KeyStore.State.UNLOCKED;
- case UserState.LSKF_LOCKED:
- return KeyStore.State.LOCKED;
- default:
- throw new AssertionError(userState);
- }
- }
- ret = mBinder.getState(userId);
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- throw new AssertionError(e);
- }
-
- switch (ret) {
- case NO_ERROR: return State.UNLOCKED;
- case LOCKED: return State.LOCKED;
- case UNINITIALIZED: return State.UNINITIALIZED;
- default: throw new AssertionError(mError);
+ int userState = AndroidKeyStoreMaintenance.getState(userId);
+ switch (userState) {
+ case UserState.UNINITIALIZED:
+ return KeyStore.State.UNINITIALIZED;
+ case UserState.LSKF_UNLOCKED:
+ return KeyStore.State.UNLOCKED;
+ case UserState.LSKF_LOCKED:
+ return KeyStore.State.LOCKED;
+ default:
+ throw new AssertionError(userState);
}
}
+ /** @hide */
@UnsupportedAppUsage
public State state() {
return state(UserHandle.myUserId());
}
- public boolean isUnlocked() {
- return state() == State.UNLOCKED;
- }
-
- public byte[] get(String key, int uid) {
- return get(key, uid, false);
- }
-
+ /** @hide */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public byte[] get(String key) {
- return get(key, UID_SELF);
+ return null;
}
- public byte[] get(String key, int uid, boolean suppressKeyNotFoundWarning) {
- try {
- key = key != null ? key : "";
- return mBinder.get(key, uid);
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- return null;
- } catch (android.os.ServiceSpecificException e) {
- if (!suppressKeyNotFoundWarning || e.errorCode != KEY_NOT_FOUND) {
- Log.w(TAG, "KeyStore exception", e);
- }
- return null;
- }
- }
-
- public byte[] get(String key, boolean suppressKeyNotFoundWarning) {
- return get(key, UID_SELF, suppressKeyNotFoundWarning);
- }
-
-
- public boolean put(String key, byte[] value, int uid, int flags) {
- return insert(key, value, uid, flags) == NO_ERROR;
- }
-
- public int insert(String key, byte[] value, int uid, int flags) {
- try {
- if (value == null) {
- value = new byte[0];
- }
- int error = mBinder.insert(key, value, uid, flags);
- if (error == KEY_ALREADY_EXISTS) {
- mBinder.del(key, uid);
- error = mBinder.insert(key, value, uid, flags);
- }
- return error;
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- return SYSTEM_ERROR;
- }
- }
-
- int delete2(String key, int uid) {
- try {
- return mBinder.del(key, uid);
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- return SYSTEM_ERROR;
- }
- }
-
- public boolean delete(String key, int uid) {
- int ret = delete2(key, uid);
- return ret == NO_ERROR || ret == KEY_NOT_FOUND;
- }
-
+ /** @hide */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public boolean delete(String key) {
- return delete(key, UID_SELF);
- }
-
- public boolean contains(String key, int uid) {
- try {
- return mBinder.exist(key, uid) == NO_ERROR;
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- return false;
- }
- }
-
- public boolean contains(String key) {
- return contains(key, UID_SELF);
- }
-
- /**
- * List all entries in the keystore for {@code uid} starting with {@code prefix}.
- */
- public String[] list(String prefix, int uid) {
- try {
- return mBinder.list(prefix, uid);
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- return null;
- } catch (android.os.ServiceSpecificException e) {
- Log.w(TAG, "KeyStore exception", e);
- return null;
- }
+ return false;
}
/**
* List uids of all keys that are auth bound to the current user.
* Only system is allowed to call this method.
+ * @hide
+ * @deprecated This function always returns null.
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public int[] listUidsOfAuthBoundKeys() {
- // uids are returned as a list of strings because list of integers
- // as an output parameter is not supported by aidl-cpp.
- List<String> uidsOut = new ArrayList<>();
- try {
- int rc = mBinder.listUidsOfAuthBoundKeys(uidsOut);
- if (rc != NO_ERROR) {
- Log.w(TAG, String.format("listUidsOfAuthBoundKeys failed with error code %d", rc));
- return null;
- }
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- return null;
- } catch (android.os.ServiceSpecificException e) {
- Log.w(TAG, "KeyStore exception", e);
- return null;
- }
- // Turn list of strings into an array of uid integers.
- return uidsOut.stream().mapToInt(Integer::parseInt).toArray();
- }
-
- public String[] list(String prefix) {
- return list(prefix, UID_SELF);
+ return null;
}
+
/**
- * Attempt to lock the keystore for {@code user}.
- *
- * @param userId Android user to lock.
- * @return whether {@code user}'s keystore was locked.
+ * @hide
+ * @deprecated This function has no effect.
*/
- public boolean lock(int userId) {
- try {
- return mBinder.lock(userId) == NO_ERROR;
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- return false;
- }
- }
-
- public boolean lock() {
- return lock(UserHandle.myUserId());
- }
-
- /**
- * Attempt to unlock the keystore for {@code user} with the password {@code password}.
- * This is required before keystore entries created with FLAG_ENCRYPTED can be accessed or
- * created.
- *
- * @param userId Android user ID to operate on
- * @param password user's keystore password. Should be the most recent value passed to
- * {@link #onUserPasswordChanged} for the user.
- *
- * @return whether the keystore was unlocked.
- */
- public boolean unlock(int userId, String password) {
- try {
- password = password != null ? password : "";
- mError = mBinder.unlock(userId, password);
- return mError == NO_ERROR;
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- return false;
- }
- }
-
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public boolean unlock(String password) {
- return unlock(UserHandle.getUserId(Process.myUid()), password);
+ return false;
}
/**
- * Check if the keystore for {@code userId} is empty.
+ *
+ * @return
+ * @deprecated This function always returns true.
+ * @hide
*/
- public boolean isEmpty(int userId) {
- try {
- return mBinder.isEmpty(userId) != 0;
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- return false;
- }
- }
-
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public boolean isEmpty() {
- return isEmpty(UserHandle.myUserId());
- }
-
- public String grant(String key, int uid) {
- try {
- String grantAlias = mBinder.grant(key, uid);
- if (grantAlias == "") return null;
- return grantAlias;
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- return null;
- }
- }
-
- public boolean ungrant(String key, int uid) {
- try {
- return mBinder.ungrant(key, uid) == NO_ERROR;
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- return false;
- }
- }
-
- /**
- * Returns the last modification time of the key in milliseconds since the
- * epoch. Will return -1L if the key could not be found or other error.
- */
- public long getmtime(String key, int uid) {
- try {
- final long millis = mBinder.getmtime(key, uid);
- if (millis == -1L) {
- return -1L;
- }
-
- return millis * 1000L;
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- return -1L;
- }
- }
-
- public long getmtime(String key) {
- return getmtime(key, UID_SELF);
- }
-
- // TODO: remove this when it's removed from Settings
- public boolean isHardwareBacked() {
- return isHardwareBacked("RSA");
- }
-
- public boolean isHardwareBacked(String keyType) {
- try {
- return mBinder.is_hardware_backed(keyType.toUpperCase(Locale.US)) == NO_ERROR;
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- return false;
- }
- }
-
- public boolean clearUid(int uid) {
- try {
- if (android.security.keystore2.AndroidKeyStoreProvider.isInstalled()) {
- return AndroidKeyStoreMaintenance.clearNamespace(Domain.APP, uid) == 0;
- }
- return mBinder.clear_uid(uid) == NO_ERROR;
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- return false;
- }
- }
-
- public int getLastError() {
- return mError;
- }
-
- public boolean addRngEntropy(byte[] data, int flags) {
- KeystoreResultPromise promise = new KeystoreResultPromise();
- try {
- mBinder.asBinder().linkToDeath(promise, 0);
- int errorCode = mBinder.addRngEntropy(promise, data, flags);
- if (errorCode == NO_ERROR) {
- return interruptedPreservingGet(promise.getFuture()).getErrorCode() == NO_ERROR;
- } else {
- return false;
- }
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- return false;
- } catch (ExecutionException e) {
- Log.e(TAG, "AddRngEntropy completed with exception", e);
- return false;
- } finally {
- mBinder.asBinder().unlinkToDeath(promise, 0);
- }
- }
-
- private class KeyCharacteristicsCallbackResult {
- private KeystoreResponse keystoreResponse;
- private KeyCharacteristics keyCharacteristics;
-
- public KeyCharacteristicsCallbackResult(KeystoreResponse keystoreResponse,
- KeyCharacteristics keyCharacteristics) {
- this.keystoreResponse = keystoreResponse;
- this.keyCharacteristics = keyCharacteristics;
- }
-
- public KeystoreResponse getKeystoreResponse() {
- return keystoreResponse;
- }
-
- public void setKeystoreResponse(KeystoreResponse keystoreResponse) {
- this.keystoreResponse = keystoreResponse;
- }
-
- public KeyCharacteristics getKeyCharacteristics() {
- return keyCharacteristics;
- }
-
- public void setKeyCharacteristics(KeyCharacteristics keyCharacteristics) {
- this.keyCharacteristics = keyCharacteristics;
- }
- }
-
- private class KeyCharacteristicsPromise
- extends android.security.keystore.IKeystoreKeyCharacteristicsCallback.Stub
- implements IBinder.DeathRecipient {
- final private CompletableFuture<KeyCharacteristicsCallbackResult> future =
- new CompletableFuture<KeyCharacteristicsCallbackResult>();
- @Override
- public void onFinished(KeystoreResponse keystoreResponse,
- KeyCharacteristics keyCharacteristics)
- throws android.os.RemoteException {
- future.complete(
- new KeyCharacteristicsCallbackResult(keystoreResponse, keyCharacteristics));
- }
- public final CompletableFuture<KeyCharacteristicsCallbackResult> getFuture() {
- return future;
- }
- @Override
- public void binderDied() {
- future.completeExceptionally(new RemoteException("Keystore died"));
- }
- };
-
- private int generateKeyInternal(String alias, KeymasterArguments args, byte[] entropy, int uid,
- int flags, KeyCharacteristics outCharacteristics)
- throws RemoteException, ExecutionException {
- KeyCharacteristicsPromise promise = new KeyCharacteristicsPromise();
- int error = NO_ERROR;
- KeyCharacteristicsCallbackResult result = null;
- try {
- mBinder.asBinder().linkToDeath(promise, 0);
- error = mBinder.generateKey(promise, alias, args, entropy, uid, flags);
- if (error != NO_ERROR) {
- Log.e(TAG, "generateKeyInternal failed on request " + error);
- return error;
- }
- result = interruptedPreservingGet(promise.getFuture());
- } finally {
- mBinder.asBinder().unlinkToDeath(promise, 0);
- }
-
- error = result.getKeystoreResponse().getErrorCode();
- if (error != NO_ERROR) {
- Log.e(TAG, "generateKeyInternal failed on response " + error);
- return error;
- }
- KeyCharacteristics characteristics = result.getKeyCharacteristics();
- if (characteristics == null) {
- Log.e(TAG, "generateKeyInternal got empty key characteristics " + error);
- return SYSTEM_ERROR;
- }
- outCharacteristics.shallowCopyFrom(characteristics);
- return NO_ERROR;
- }
-
- public int generateKey(String alias, KeymasterArguments args, byte[] entropy, int uid,
- int flags, KeyCharacteristics outCharacteristics) {
- try {
- entropy = entropy != null ? entropy : new byte[0];
- args = args != null ? args : new KeymasterArguments();
- int error = generateKeyInternal(alias, args, entropy, uid, flags, outCharacteristics);
- if (error == KEY_ALREADY_EXISTS) {
- mBinder.del(alias, uid);
- error = generateKeyInternal(alias, args, entropy, uid, flags, outCharacteristics);
- }
- return error;
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- return SYSTEM_ERROR;
- } catch (ExecutionException e) {
- Log.e(TAG, "generateKey completed with exception", e);
- return SYSTEM_ERROR;
- }
- }
-
- public int generateKey(String alias, KeymasterArguments args, byte[] entropy, int flags,
- KeyCharacteristics outCharacteristics) {
- return generateKey(alias, args, entropy, UID_SELF, flags, outCharacteristics);
- }
-
- public int getKeyCharacteristics(String alias, KeymasterBlob clientId, KeymasterBlob appId,
- int uid, KeyCharacteristics outCharacteristics) {
- KeyCharacteristicsPromise promise = new KeyCharacteristicsPromise();
- try {
- mBinder.asBinder().linkToDeath(promise, 0);
- clientId = clientId != null ? clientId : new KeymasterBlob(new byte[0]);
- appId = appId != null ? appId : new KeymasterBlob(new byte[0]);
-
- int error = mBinder.getKeyCharacteristics(promise, alias, clientId, appId, uid);
- if (error != NO_ERROR) return error;
-
- KeyCharacteristicsCallbackResult result = interruptedPreservingGet(promise.getFuture());
- error = result.getKeystoreResponse().getErrorCode();
- if (error != NO_ERROR) return error;
-
- KeyCharacteristics characteristics = result.getKeyCharacteristics();
- if (characteristics == null) return SYSTEM_ERROR;
- outCharacteristics.shallowCopyFrom(characteristics);
- return NO_ERROR;
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- return SYSTEM_ERROR;
- } catch (ExecutionException e) {
- Log.e(TAG, "GetKeyCharacteristics completed with exception", e);
- return SYSTEM_ERROR;
- } finally {
- mBinder.asBinder().unlinkToDeath(promise, 0);
- }
- }
-
- public int getKeyCharacteristics(String alias, KeymasterBlob clientId, KeymasterBlob appId,
- KeyCharacteristics outCharacteristics) {
- return getKeyCharacteristics(alias, clientId, appId, UID_SELF, outCharacteristics);
- }
-
- private int importKeyInternal(String alias, KeymasterArguments args, int format, byte[] keyData,
- int uid, int flags, KeyCharacteristics outCharacteristics)
- throws RemoteException, ExecutionException {
- KeyCharacteristicsPromise promise = new KeyCharacteristicsPromise();
- mBinder.asBinder().linkToDeath(promise, 0);
- try {
- int error = mBinder.importKey(promise, alias, args, format, keyData, uid, flags);
- if (error != NO_ERROR) return error;
-
- KeyCharacteristicsCallbackResult result = interruptedPreservingGet(promise.getFuture());
-
- error = result.getKeystoreResponse().getErrorCode();
- if (error != NO_ERROR) return error;
-
- KeyCharacteristics characteristics = result.getKeyCharacteristics();
- if (characteristics == null) return SYSTEM_ERROR;
- outCharacteristics.shallowCopyFrom(characteristics);
- return NO_ERROR;
- } finally {
- mBinder.asBinder().unlinkToDeath(promise, 0);
- }
- }
-
- public int importKey(String alias, KeymasterArguments args, int format, byte[] keyData,
- int uid, int flags, KeyCharacteristics outCharacteristics) {
- try {
- int error = importKeyInternal(alias, args, format, keyData, uid, flags,
- outCharacteristics);
- if (error == KEY_ALREADY_EXISTS) {
- mBinder.del(alias, uid);
- error = importKeyInternal(alias, args, format, keyData, uid, flags,
- outCharacteristics);
- }
- return error;
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- return SYSTEM_ERROR;
- } catch (ExecutionException e) {
- Log.e(TAG, "ImportKey completed with exception", e);
- return SYSTEM_ERROR;
- }
- }
-
- public int importKey(String alias, KeymasterArguments args, int format, byte[] keyData,
- int flags, KeyCharacteristics outCharacteristics) {
- return importKey(alias, args, format, keyData, UID_SELF, flags, outCharacteristics);
- }
-
- private String getAlgorithmFromPKCS8(byte[] keyData) {
- try {
- final ASN1InputStream bIn = new ASN1InputStream(new ByteArrayInputStream(keyData));
- final PrivateKeyInfo pki = PrivateKeyInfo.getInstance(bIn.readObject());
- final String algOid = pki.getPrivateKeyAlgorithm().getAlgorithm().getId();
- return new AlgorithmId(new ObjectIdentifier(algOid)).getName();
- } catch (IOException e) {
- Log.e(TAG, "getAlgorithmFromPKCS8 Failed to parse key data");
- Log.e(TAG, Log.getStackTraceString(e));
- return null;
- }
- }
-
- private KeymasterArguments makeLegacyArguments(String algorithm) {
- KeymasterArguments args = new KeymasterArguments();
- args.addEnum(KeymasterDefs.KM_TAG_ALGORITHM,
- KeyProperties.KeyAlgorithm.toKeymasterAsymmetricKeyAlgorithm(algorithm));
- args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_SIGN);
- args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_VERIFY);
- args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_ENCRYPT);
- args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_DECRYPT);
- args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_NONE);
- if (algorithm.equalsIgnoreCase(KeyProperties.KEY_ALGORITHM_RSA)) {
- args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_RSA_OAEP);
- args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_ENCRYPT);
- args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_SIGN);
- args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_RSA_PSS);
- }
- args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_NONE);
- args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_MD5);
- args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA1);
- args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA_2_224);
- args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA_2_256);
- args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA_2_384);
- args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA_2_512);
- args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
- args.addDate(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME, new Date(Long.MAX_VALUE));
- args.addDate(KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME, new Date(Long.MAX_VALUE));
- args.addDate(KeymasterDefs.KM_TAG_ACTIVE_DATETIME, new Date(0));
- return args;
- }
-
- public boolean importKey(String alias, byte[] keyData, int uid, int flags) {
- String algorithm = getAlgorithmFromPKCS8(keyData);
- if (algorithm == null) return false;
- KeymasterArguments args = makeLegacyArguments(algorithm);
- KeyCharacteristics out = new KeyCharacteristics();
- int result = importKey(alias, args, KeymasterDefs.KM_KEY_FORMAT_PKCS8, keyData, uid,
- flags, out);
- if (result != NO_ERROR) {
- Log.e(TAG, Log.getStackTraceString(
- new KeyStoreException(result, "legacy key import failed")));
- return false;
- }
return true;
}
- private int importWrappedKeyInternal(String wrappedKeyAlias, byte[] wrappedKey,
- String wrappingKeyAlias,
- byte[] maskingKey, KeymasterArguments args, long rootSid, long fingerprintSid,
- KeyCharacteristics outCharacteristics)
- throws RemoteException, ExecutionException {
- KeyCharacteristicsPromise promise = new KeyCharacteristicsPromise();
- mBinder.asBinder().linkToDeath(promise, 0);
- try {
- int error = mBinder.importWrappedKey(promise, wrappedKeyAlias, wrappedKey,
- wrappingKeyAlias, maskingKey, args, rootSid, fingerprintSid);
- if (error != NO_ERROR) return error;
-
- KeyCharacteristicsCallbackResult result = interruptedPreservingGet(promise.getFuture());
-
- error = result.getKeystoreResponse().getErrorCode();
- if (error != NO_ERROR) return error;
-
- KeyCharacteristics characteristics = result.getKeyCharacteristics();
- if (characteristics == null) return SYSTEM_ERROR;
- outCharacteristics.shallowCopyFrom(characteristics);
- return NO_ERROR;
- } finally {
- mBinder.asBinder().unlinkToDeath(promise, 0);
- }
- }
-
- public int importWrappedKey(String wrappedKeyAlias, byte[] wrappedKey,
- String wrappingKeyAlias,
- byte[] maskingKey, KeymasterArguments args, long rootSid, long fingerprintSid, int uid,
- KeyCharacteristics outCharacteristics) {
- // TODO b/119217337 uid parameter gets silently ignored.
- try {
- int error = importWrappedKeyInternal(wrappedKeyAlias, wrappedKey, wrappingKeyAlias,
- maskingKey, args, rootSid, fingerprintSid, outCharacteristics);
- if (error == KEY_ALREADY_EXISTS) {
- mBinder.del(wrappedKeyAlias, UID_SELF);
- error = importWrappedKeyInternal(wrappedKeyAlias, wrappedKey, wrappingKeyAlias,
- maskingKey, args, rootSid, fingerprintSid, outCharacteristics);
- }
- return error;
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- return SYSTEM_ERROR;
- } catch (ExecutionException e) {
- Log.e(TAG, "ImportWrappedKey completed with exception", e);
- return SYSTEM_ERROR;
- }
- }
-
- private class ExportKeyPromise
- extends android.security.keystore.IKeystoreExportKeyCallback.Stub
- implements IBinder.DeathRecipient {
- final private CompletableFuture<ExportResult> future = new CompletableFuture<ExportResult>();
- @Override
- public void onFinished(ExportResult exportKeyResult) throws android.os.RemoteException {
- future.complete(exportKeyResult);
- }
- public final CompletableFuture<ExportResult> getFuture() {
- return future;
- }
- @Override
- public void binderDied() {
- future.completeExceptionally(new RemoteException("Keystore died"));
- }
- };
-
- public ExportResult exportKey(String alias, int format, KeymasterBlob clientId,
- KeymasterBlob appId, int uid) {
- ExportKeyPromise promise = new ExportKeyPromise();
- try {
- mBinder.asBinder().linkToDeath(promise, 0);
- clientId = clientId != null ? clientId : new KeymasterBlob(new byte[0]);
- appId = appId != null ? appId : new KeymasterBlob(new byte[0]);
- int error = mBinder.exportKey(promise, alias, format, clientId, appId, uid);
- if (error == NO_ERROR) {
- return interruptedPreservingGet(promise.getFuture());
- } else {
- return new ExportResult(error);
- }
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- return null;
- } catch (ExecutionException e) {
- Log.e(TAG, "ExportKey completed with exception", e);
- return null;
- } finally {
- mBinder.asBinder().unlinkToDeath(promise, 0);
- }
- }
- public ExportResult exportKey(String alias, int format, KeymasterBlob clientId,
- KeymasterBlob appId) {
- return exportKey(alias, format, clientId, appId, UID_SELF);
- }
-
- private class OperationPromise
- extends android.security.keystore.IKeystoreOperationResultCallback.Stub
- implements IBinder.DeathRecipient {
- final private CompletableFuture<OperationResult> future = new CompletableFuture<OperationResult>();
- @Override
- public void onFinished(OperationResult operationResult) throws android.os.RemoteException {
- future.complete(operationResult);
- }
- public final CompletableFuture<OperationResult> getFuture() {
- return future;
- }
- @Override
- public void binderDied() {
- future.completeExceptionally(new RemoteException("Keystore died"));
- }
- };
-
- public OperationResult begin(String alias, int purpose, boolean pruneable,
- KeymasterArguments args, byte[] entropy, int uid) {
- OperationPromise promise = new OperationPromise();
- try {
- mBinder.asBinder().linkToDeath(promise, 0);
- args = args != null ? args : new KeymasterArguments();
- entropy = entropy != null ? entropy : new byte[0];
- int errorCode = mBinder.begin(promise, getToken(), alias, purpose, pruneable, args,
- entropy, uid);
- if (errorCode == NO_ERROR) {
- return interruptedPreservingGet(promise.getFuture());
- } else {
- return new OperationResult(errorCode);
- }
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- return null;
- } catch (ExecutionException e) {
- Log.e(TAG, "Begin completed with exception", e);
- return null;
- } finally {
- mBinder.asBinder().unlinkToDeath(promise, 0);
- }
- }
-
- public OperationResult begin(String alias, int purpose, boolean pruneable,
- KeymasterArguments args, byte[] entropy) {
- entropy = entropy != null ? entropy : new byte[0];
- args = args != null ? args : new KeymasterArguments();
- return begin(alias, purpose, pruneable, args, entropy, UID_SELF);
- }
-
- public OperationResult update(IBinder token, KeymasterArguments arguments, byte[] input) {
- OperationPromise promise = new OperationPromise();
- try {
- mBinder.asBinder().linkToDeath(promise, 0);
- arguments = arguments != null ? arguments : new KeymasterArguments();
- input = input != null ? input : new byte[0];
- int errorCode = mBinder.update(promise, token, arguments, input);
- if (errorCode == NO_ERROR) {
- return interruptedPreservingGet(promise.getFuture());
- } else {
- return new OperationResult(errorCode);
- }
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- return null;
- } catch (ExecutionException e) {
- Log.e(TAG, "Update completed with exception", e);
- return null;
- } finally {
- mBinder.asBinder().unlinkToDeath(promise, 0);
- }
- }
-
/**
- * Android KeyStore finish operation.
- *
- * @param token Authentication token.
- * @param arguments Keymaster arguments
- * @param input Optional additional input data.
- * @param signature Optional signature to be verified.
- * @param entropy Optional additional entropy
- * @return OperationResult that will indicate success or error of the operation.
+ * Forwards the request to clear a UID to Keystore 2.0.
+ * @hide
*/
- public OperationResult finish(IBinder token, KeymasterArguments arguments, byte[] input,
- byte[] signature, byte[] entropy) {
- OperationPromise promise = new OperationPromise();
- try {
- mBinder.asBinder().linkToDeath(promise, 0);
- arguments = arguments != null ? arguments : new KeymasterArguments();
- entropy = entropy != null ? entropy : new byte[0];
- input = input != null ? input : new byte[0];
- signature = signature != null ? signature : new byte[0];
- int errorCode = mBinder.finish(promise, token, arguments, input, signature, entropy);
- if (errorCode == NO_ERROR) {
- return interruptedPreservingGet(promise.getFuture());
- } else {
- return new OperationResult(errorCode);
- }
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- return null;
- } catch (ExecutionException e) {
- Log.e(TAG, "Finish completed with exception", e);
- return null;
- } finally {
- mBinder.asBinder().unlinkToDeath(promise, 0);
- }
+ public boolean clearUid(int uid) {
+ return AndroidKeyStoreMaintenance.clearNamespace(Domain.APP, uid) == 0;
}
- public OperationResult finish(IBinder token, KeymasterArguments arguments, byte[] signature) {
- return finish(token, arguments, null, signature, null);
- }
-
- private class KeystoreResultPromise
- extends android.security.keystore.IKeystoreResponseCallback.Stub
- implements IBinder.DeathRecipient {
- final private CompletableFuture<KeystoreResponse> future = new CompletableFuture<KeystoreResponse>();
- @Override
- public void onFinished(KeystoreResponse keystoreResponse) throws android.os.RemoteException {
- future.complete(keystoreResponse);
- }
- public final CompletableFuture<KeystoreResponse> getFuture() {
- return future;
- }
- @Override
- public void binderDied() {
- future.completeExceptionally(new RemoteException("Keystore died"));
- }
- };
-
- public int abort(IBinder token) {
- KeystoreResultPromise promise = new KeystoreResultPromise();
- try {
- mBinder.asBinder().linkToDeath(promise, 0);
- int errorCode = mBinder.abort(promise, token);
- if (errorCode == NO_ERROR) {
- return interruptedPreservingGet(promise.getFuture()).getErrorCode();
- } else {
- return errorCode;
- }
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- return SYSTEM_ERROR;
- } catch (ExecutionException e) {
- Log.e(TAG, "Abort completed with exception", e);
- return SYSTEM_ERROR;
- } finally {
- mBinder.asBinder().unlinkToDeath(promise, 0);
- }
- }
/**
* Add an authentication record to the keystore authorization table.
@@ -1013,191 +136,7 @@
* a {@code KeymasterDefs.KM_ERROR_} value or {@code KeyStore} ResponseCode.
*/
public int addAuthToken(byte[] authToken) {
- try {
- Authorization.addAuthToken(authToken);
- return mBinder.addAuthToken(authToken);
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- return SYSTEM_ERROR;
- }
- }
-
- /**
- * Notify keystore that a user's password has changed.
- *
- * @param userId the user whose password changed.
- * @param newPassword the new password or "" if the password was removed.
- */
- public boolean onUserPasswordChanged(int userId, String newPassword) {
- // Parcel.cpp doesn't support deserializing null strings and treats them as "". Make that
- // explicit here.
- if (newPassword == null) {
- newPassword = "";
- }
- try {
- return mBinder.onUserPasswordChanged(userId, newPassword) == NO_ERROR;
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- return false;
- }
- }
-
- /**
- * Notify keystore that a user was added.
- *
- * @param userId the new user.
- * @param parentId the parent of the new user, or -1 if the user has no parent. If parentId is
- * specified then the new user's keystore will be intialized with the same secure lockscreen
- * password as the parent.
- */
- public void onUserAdded(int userId, int parentId) {
- try {
- mBinder.onUserAdded(userId, parentId);
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- }
- }
-
- /**
- * Notify keystore that a user was added.
- *
- * @param userId the new user.
- */
- public void onUserAdded(int userId) {
- onUserAdded(userId, -1);
- }
-
- /**
- * Notify keystore that a user was removed.
- *
- * @param userId the removed user.
- */
- public void onUserRemoved(int userId) {
- try {
- mBinder.onUserRemoved(userId);
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- }
- }
-
- public boolean onUserPasswordChanged(String newPassword) {
- return onUserPasswordChanged(UserHandle.getUserId(Process.myUid()), newPassword);
- }
-
- /**
- * Notify keystore about the latest user locked state. This is to support keyguard-bound key.
- */
- public void onUserLockedStateChanged(int userHandle, boolean locked) {
- try {
- mBinder.onKeyguardVisibilityChanged(locked, userHandle);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to update user locked state " + userHandle, e);
- }
- }
-
- private class KeyAttestationCallbackResult {
- private KeystoreResponse keystoreResponse;
- private KeymasterCertificateChain certificateChain;
-
- public KeyAttestationCallbackResult(KeystoreResponse keystoreResponse,
- KeymasterCertificateChain certificateChain) {
- this.keystoreResponse = keystoreResponse;
- this.certificateChain = certificateChain;
- }
-
- public KeystoreResponse getKeystoreResponse() {
- return keystoreResponse;
- }
-
- public void setKeystoreResponse(KeystoreResponse keystoreResponse) {
- this.keystoreResponse = keystoreResponse;
- }
-
- public KeymasterCertificateChain getCertificateChain() {
- return certificateChain;
- }
-
- public void setCertificateChain(KeymasterCertificateChain certificateChain) {
- this.certificateChain = certificateChain;
- }
- }
-
- private class CertificateChainPromise
- extends android.security.keystore.IKeystoreCertificateChainCallback.Stub
- implements IBinder.DeathRecipient {
- final private CompletableFuture<KeyAttestationCallbackResult> future = new CompletableFuture<KeyAttestationCallbackResult>();
- @Override
- public void onFinished(KeystoreResponse keystoreResponse,
- KeymasterCertificateChain certificateChain) throws android.os.RemoteException {
- future.complete(new KeyAttestationCallbackResult(keystoreResponse, certificateChain));
- }
- public final CompletableFuture<KeyAttestationCallbackResult> getFuture() {
- return future;
- }
- @Override
- public void binderDied() {
- future.completeExceptionally(new RemoteException("Keystore died"));
- }
- };
-
-
- public int attestKey(
- String alias, KeymasterArguments params, KeymasterCertificateChain outChain) {
- CertificateChainPromise promise = new CertificateChainPromise();
- try {
- mBinder.asBinder().linkToDeath(promise, 0);
- if (params == null) {
- params = new KeymasterArguments();
- }
- if (outChain == null) {
- outChain = new KeymasterCertificateChain();
- }
- int error = mBinder.attestKey(promise, alias, params);
- if (error != NO_ERROR) return error;
- KeyAttestationCallbackResult result = interruptedPreservingGet(promise.getFuture());
- error = result.getKeystoreResponse().getErrorCode();
- if (error == NO_ERROR) {
- outChain.shallowCopyFrom(result.getCertificateChain());
- }
- return error;
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- return SYSTEM_ERROR;
- } catch (ExecutionException e) {
- Log.e(TAG, "AttestKey completed with exception", e);
- return SYSTEM_ERROR;
- } finally {
- mBinder.asBinder().unlinkToDeath(promise, 0);
- }
- }
-
- public int attestDeviceIds(KeymasterArguments params, KeymasterCertificateChain outChain) {
- CertificateChainPromise promise = new CertificateChainPromise();
- try {
- mBinder.asBinder().linkToDeath(promise, 0);
- if (params == null) {
- params = new KeymasterArguments();
- }
- if (outChain == null) {
- outChain = new KeymasterCertificateChain();
- }
- int error = mBinder.attestDeviceIds(promise, params);
- if (error != NO_ERROR) return error;
- KeyAttestationCallbackResult result = interruptedPreservingGet(promise.getFuture());
- error = result.getKeystoreResponse().getErrorCode();
- if (error == NO_ERROR) {
- outChain.shallowCopyFrom(result.getCertificateChain());
- }
- return error;
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- return SYSTEM_ERROR;
- } catch (ExecutionException e) {
- Log.e(TAG, "AttestDevicdeIds completed with exception", e);
- return SYSTEM_ERROR;
- } finally {
- mBinder.asBinder().unlinkToDeath(promise, 0);
- }
+ return Authorization.addAuthToken(authToken);
}
/**
@@ -1205,77 +144,6 @@
*/
public void onDeviceOffBody() {
AndroidKeyStoreMaintenance.onDeviceOffBody();
- try {
- mBinder.onDeviceOffBody();
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- }
- }
-
- // Keep in sync with confirmationui/1.0/types.hal.
- public static final int CONFIRMATIONUI_OK = 0;
- public static final int CONFIRMATIONUI_CANCELED = 1;
- public static final int CONFIRMATIONUI_ABORTED = 2;
- public static final int CONFIRMATIONUI_OPERATION_PENDING = 3;
- public static final int CONFIRMATIONUI_IGNORED = 4;
- public static final int CONFIRMATIONUI_SYSTEM_ERROR = 5;
- public static final int CONFIRMATIONUI_UNIMPLEMENTED = 6;
- public static final int CONFIRMATIONUI_UNEXPECTED = 7;
- public static final int CONFIRMATIONUI_UIERROR = 0x10000;
- public static final int CONFIRMATIONUI_UIERROR_MISSING_GLYPH = 0x10001;
- public static final int CONFIRMATIONUI_UIERROR_MESSAGE_TOO_LONG = 0x10002;
- public static final int CONFIRMATIONUI_UIERROR_MALFORMED_UTF8_ENCODING = 0x10003;
-
- /**
- * Requests keystore call into the confirmationui HAL to display a prompt.
- *
- * @param listener the binder to use for callbacks.
- * @param promptText the prompt to display.
- * @param extraData extra data / nonce from application.
- * @param locale the locale as a BCP 47 langauge tag.
- * @param uiOptionsAsFlags the UI options to use, as flags.
- * @return one of the {@code CONFIRMATIONUI_*} constants, for
- * example {@code KeyStore.CONFIRMATIONUI_OK}.
- */
- public int presentConfirmationPrompt(IBinder listener, String promptText, byte[] extraData,
- String locale, int uiOptionsAsFlags) {
- try {
- return mBinder.presentConfirmationPrompt(listener, promptText, extraData, locale,
- uiOptionsAsFlags);
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- return CONFIRMATIONUI_SYSTEM_ERROR;
- }
- }
-
- /**
- * Requests keystore call into the confirmationui HAL to cancel displaying a prompt.
- *
- * @param listener the binder passed to the {@link #presentConfirmationPrompt} method.
- * @return one of the {@code CONFIRMATIONUI_*} constants, for
- * example {@code KeyStore.CONFIRMATIONUI_OK}.
- */
- public int cancelConfirmationPrompt(IBinder listener) {
- try {
- return mBinder.cancelConfirmationPrompt(listener);
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- return CONFIRMATIONUI_SYSTEM_ERROR;
- }
- }
-
- /**
- * Requests keystore to check if the confirmationui HAL is available.
- *
- * @return whether the confirmationUI HAL is available.
- */
- public boolean isConfirmationPromptSupported() {
- try {
- return mBinder.isConfirmationPromptSupported();
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- return false;
- }
}
/**
@@ -1284,143 +152,6 @@
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public static KeyStoreException getKeyStoreException(int errorCode) {
- if (errorCode > 0) {
- // KeyStore layer error
- switch (errorCode) {
- case NO_ERROR:
- return new KeyStoreException(errorCode, "OK");
- case LOCKED:
- return new KeyStoreException(errorCode, "User authentication required");
- case UNINITIALIZED:
- return new KeyStoreException(errorCode, "Keystore not initialized");
- case SYSTEM_ERROR:
- return new KeyStoreException(errorCode, "System error");
- case PERMISSION_DENIED:
- return new KeyStoreException(errorCode, "Permission denied");
- case KEY_NOT_FOUND:
- return new KeyStoreException(errorCode, "Key not found");
- case VALUE_CORRUPTED:
- return new KeyStoreException(errorCode, "Key blob corrupted");
- case OP_AUTH_NEEDED:
- return new KeyStoreException(errorCode, "Operation requires authorization");
- case KEY_PERMANENTLY_INVALIDATED:
- return new KeyStoreException(errorCode, "Key permanently invalidated");
- default:
- return new KeyStoreException(errorCode, String.valueOf(errorCode));
- }
- } else {
- // Keymaster layer error
- switch (errorCode) {
- case KeymasterDefs.KM_ERROR_INVALID_AUTHORIZATION_TIMEOUT:
- // The name of this parameter significantly differs between Keymaster and
- // framework APIs. Use the framework wording to make life easier for developers.
- return new KeyStoreException(errorCode,
- "Invalid user authentication validity duration");
- default:
- return new KeyStoreException(errorCode,
- KeymasterDefs.getErrorMessage(errorCode));
- }
- }
- }
-
- /**
- * Returns an {@link InvalidKeyException} corresponding to the provided
- * {@link KeyStoreException}.
- */
- public InvalidKeyException getInvalidKeyException(
- String keystoreKeyAlias, int uid, KeyStoreException e) {
- switch (e.getErrorCode()) {
- case LOCKED:
- return new UserNotAuthenticatedException();
- case KeymasterDefs.KM_ERROR_KEY_EXPIRED:
- return new KeyExpiredException();
- case KeymasterDefs.KM_ERROR_KEY_NOT_YET_VALID:
- return new KeyNotYetValidException();
- case KeymasterDefs.KM_ERROR_KEY_USER_NOT_AUTHENTICATED:
- case OP_AUTH_NEEDED:
- {
- // We now need to determine whether the key/operation can become usable if user
- // authentication is performed, or whether it can never become usable again.
- // User authentication requirements are contained in the key's characteristics. We
- // need to check whether these requirements can be be satisfied by asking the user
- // to authenticate.
- KeyCharacteristics keyCharacteristics = new KeyCharacteristics();
- int getKeyCharacteristicsErrorCode =
- getKeyCharacteristics(keystoreKeyAlias, null, null, uid,
- keyCharacteristics);
- if (getKeyCharacteristicsErrorCode != NO_ERROR) {
- return new InvalidKeyException(
- "Failed to obtained key characteristics",
- getKeyStoreException(getKeyCharacteristicsErrorCode));
- }
- List<BigInteger> keySids =
- keyCharacteristics.getUnsignedLongs(KeymasterDefs.KM_TAG_USER_SECURE_ID);
- if (keySids.isEmpty()) {
- // Key is not bound to any SIDs -- no amount of authentication will help here.
- return new KeyPermanentlyInvalidatedException();
- }
- long rootSid = GateKeeper.getSecureUserId();
- if ((rootSid != 0) && (keySids.contains(KeymasterArguments.toUint64(rootSid)))) {
- // One of the key's SIDs is the current root SID -- user can be authenticated
- // against that SID.
- return new UserNotAuthenticatedException();
- }
-
- final BiometricManager bm = mContext.getSystemService(BiometricManager.class);
- long[] biometricSids = bm.getAuthenticatorIds();
-
- // The key must contain every biometric SID. This is because the current API surface
- // treats all biometrics (capable of keystore integration) equally. e.g. if the
- // device has multiple keystore-capable sensors, and one of the sensor's SIDs
- // changed, 1) there is no way for a developer to specify authentication with a
- // specific sensor (the one that hasn't changed), and 2) currently the only
- // signal to developers is the UserNotAuthenticatedException, which doesn't
- // indicate a specific sensor.
- boolean canUnlockViaBiometrics = true;
- for (long sid : biometricSids) {
- if (!keySids.contains(KeymasterArguments.toUint64(sid))) {
- canUnlockViaBiometrics = false;
- break;
- }
- }
-
- if (canUnlockViaBiometrics) {
- // All of the biometric SIDs are contained in the key's SIDs.
- return new UserNotAuthenticatedException();
- }
-
- // None of the key's SIDs can ever be authenticated
- return new KeyPermanentlyInvalidatedException();
- }
- case UNINITIALIZED:
- return new KeyPermanentlyInvalidatedException();
- default:
- return new InvalidKeyException("Keystore operation failed", e);
- }
- }
-
- /**
- * Returns an {@link InvalidKeyException} corresponding to the provided keystore/keymaster error
- * code.
- */
- public InvalidKeyException getInvalidKeyException(String keystoreKeyAlias, int uid,
- int errorCode) {
- return getInvalidKeyException(keystoreKeyAlias, uid, getKeyStoreException(errorCode));
- }
-
- private static <R> R interruptedPreservingGet(CompletableFuture<R> future)
- throws ExecutionException {
- boolean wasInterrupted = false;
- while (true) {
- try {
- R result = future.get();
- if (wasInterrupted) {
- Thread.currentThread().interrupt();
- }
- return result;
- } catch (InterruptedException e) {
- wasInterrupted = true;
- }
- }
+ return new KeyStoreException(-10000, "Should not be called.");
}
}
diff --git a/keystore/java/android/security/KeyStore2.java b/keystore/java/android/security/KeyStore2.java
index 75e248e..df579bb 100644
--- a/keystore/java/android/security/KeyStore2.java
+++ b/keystore/java/android/security/KeyStore2.java
@@ -125,6 +125,8 @@
}
}
+ private static final String KEYSTORE2_SERVICE_NAME =
+ "android.system.keystore2.IKeystoreService/default";
private KeyStore2() {
mBinder = null;
@@ -137,7 +139,7 @@
private synchronized IKeystoreService getService(boolean retryLookup) {
if (mBinder == null || retryLookup) {
mBinder = IKeystoreService.Stub.asInterface(ServiceManager
- .getService("android.system.keystore2"));
+ .getService(KEYSTORE2_SERVICE_NAME));
}
return mBinder;
}
diff --git a/keystore/java/android/security/LegacyVpnProfileStore.java b/keystore/java/android/security/LegacyVpnProfileStore.java
index 41cfb27..1d2738e 100644
--- a/keystore/java/android/security/LegacyVpnProfileStore.java
+++ b/keystore/java/android/security/LegacyVpnProfileStore.java
@@ -19,7 +19,6 @@
import android.annotation.NonNull;
import android.os.ServiceManager;
import android.os.ServiceSpecificException;
-import android.security.keystore.AndroidKeyStoreProvider;
import android.security.vpnprofilestore.IVpnProfileStore;
import android.util.Log;
@@ -53,13 +52,8 @@
*/
public static boolean put(@NonNull String alias, @NonNull byte[] profile) {
try {
- if (AndroidKeyStoreProvider.isKeystore2Enabled()) {
- getService().put(alias, profile);
- return true;
- } else {
- return KeyStore.getInstance().put(
- alias, profile, KeyStore.UID_SELF, 0);
- }
+ getService().put(alias, profile);
+ return true;
} catch (Exception e) {
Log.e(TAG, "Failed to put vpn profile.", e);
return false;
@@ -77,11 +71,7 @@
*/
public static byte[] get(@NonNull String alias) {
try {
- if (AndroidKeyStoreProvider.isKeystore2Enabled()) {
- return getService().get(alias);
- } else {
- return KeyStore.getInstance().get(alias, true /* suppressKeyNotFoundWarning */);
- }
+ return getService().get(alias);
} catch (ServiceSpecificException e) {
if (e.errorCode != PROFILE_NOT_FOUND) {
Log.e(TAG, "Failed to get vpn profile.", e);
@@ -100,12 +90,8 @@
*/
public static boolean remove(@NonNull String alias) {
try {
- if (AndroidKeyStoreProvider.isKeystore2Enabled()) {
- getService().remove(alias);
- return true;
- } else {
- return KeyStore.getInstance().delete(alias);
- }
+ getService().remove(alias);
+ return true;
} catch (ServiceSpecificException e) {
if (e.errorCode != PROFILE_NOT_FOUND) {
Log.e(TAG, "Failed to remove vpn profile.", e);
@@ -124,16 +110,11 @@
*/
public static @NonNull String[] list(@NonNull String prefix) {
try {
- if (AndroidKeyStoreProvider.isKeystore2Enabled()) {
- final String[] aliases = getService().list(prefix);
- for (int i = 0; i < aliases.length; ++i) {
- aliases[i] = aliases[i].substring(prefix.length());
- }
- return aliases;
- } else {
- final String[] result = KeyStore.getInstance().list(prefix);
- return result != null ? result : new String[0];
+ final String[] aliases = getService().list(prefix);
+ for (int i = 0; i < aliases.length; ++i) {
+ aliases[i] = aliases[i].substring(prefix.length());
}
+ return aliases;
} catch (Exception e) {
Log.e(TAG, "Failed to list vpn profiles.", e);
}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStore3DESCipherSpi.java b/keystore/java/android/security/keystore/AndroidKeyStore3DESCipherSpi.java
deleted file mode 100644
index 01fd062..0000000
--- a/keystore/java/android/security/keystore/AndroidKeyStore3DESCipherSpi.java
+++ /dev/null
@@ -1,298 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.keystore;
-
-import android.security.keymaster.KeymasterArguments;
-import android.security.keymaster.KeymasterDefs;
-
-import java.security.AlgorithmParameters;
-import java.security.InvalidAlgorithmParameterException;
-import java.security.InvalidKeyException;
-import java.security.Key;
-import java.security.NoSuchAlgorithmException;
-import java.security.ProviderException;
-import java.security.spec.AlgorithmParameterSpec;
-import java.security.spec.InvalidParameterSpecException;
-import java.util.Arrays;
-
-import javax.crypto.CipherSpi;
-import javax.crypto.spec.IvParameterSpec;
-
-/**
- * Base class for Android Keystore 3DES {@link CipherSpi} implementations.
- *
- * @hide
- */
-public class AndroidKeyStore3DESCipherSpi extends AndroidKeyStoreCipherSpiBase {
-
- private static final int BLOCK_SIZE_BYTES = 8;
-
- private final int mKeymasterBlockMode;
- private final int mKeymasterPadding;
- /** Whether this transformation requires an IV. */
- private final boolean mIvRequired;
-
- private byte[] mIv;
-
- /** Whether the current {@code #mIv} has been used by the underlying crypto operation. */
- private boolean mIvHasBeenUsed;
-
- AndroidKeyStore3DESCipherSpi(
- int keymasterBlockMode,
- int keymasterPadding,
- boolean ivRequired) {
- mKeymasterBlockMode = keymasterBlockMode;
- mKeymasterPadding = keymasterPadding;
- mIvRequired = ivRequired;
- }
-
- abstract static class ECB extends AndroidKeyStore3DESCipherSpi {
- protected ECB(int keymasterPadding) {
- super(KeymasterDefs.KM_MODE_ECB, keymasterPadding, false);
- }
-
- public static class NoPadding extends ECB {
- public NoPadding() {
- super(KeymasterDefs.KM_PAD_NONE);
- }
- }
-
- public static class PKCS7Padding extends ECB {
- public PKCS7Padding() {
- super(KeymasterDefs.KM_PAD_PKCS7);
- }
- }
- }
-
- abstract static class CBC extends AndroidKeyStore3DESCipherSpi {
- protected CBC(int keymasterPadding) {
- super(KeymasterDefs.KM_MODE_CBC, keymasterPadding, true);
- }
-
- public static class NoPadding extends CBC {
- public NoPadding() {
- super(KeymasterDefs.KM_PAD_NONE);
- }
- }
-
- public static class PKCS7Padding extends CBC {
- public PKCS7Padding() {
- super(KeymasterDefs.KM_PAD_PKCS7);
- }
- }
- }
-
- @Override
- protected void initKey(int i, Key key) throws InvalidKeyException {
- if (!(key instanceof AndroidKeyStoreSecretKey)) {
- throw new InvalidKeyException(
- "Unsupported key: " + ((key != null) ? key.getClass().getName() : "null"));
- }
- if (!KeyProperties.KEY_ALGORITHM_3DES.equalsIgnoreCase(key.getAlgorithm())) {
- throw new InvalidKeyException(
- "Unsupported key algorithm: " + key.getAlgorithm() + ". Only " +
- KeyProperties.KEY_ALGORITHM_3DES + " supported");
- }
- setKey((AndroidKeyStoreSecretKey) key);
- }
-
- @Override
- protected int engineGetBlockSize() {
- return BLOCK_SIZE_BYTES;
- }
-
- @Override
- protected int engineGetOutputSize(int inputLen) {
- return inputLen + 3 * BLOCK_SIZE_BYTES;
- }
-
- @Override
- protected final byte[] engineGetIV() {
- return ArrayUtils.cloneIfNotEmpty(mIv);
- }
-
- @Override
- protected AlgorithmParameters engineGetParameters() {
- if (!mIvRequired) {
- return null;
- }
- if ((mIv != null) && (mIv.length > 0)) {
- try {
- AlgorithmParameters params = AlgorithmParameters.getInstance("DESede");
- params.init(new IvParameterSpec(mIv));
- return params;
- } catch (NoSuchAlgorithmException e) {
- throw new ProviderException(
- "Failed to obtain 3DES AlgorithmParameters", e);
- } catch (InvalidParameterSpecException e) {
- throw new ProviderException(
- "Failed to initialize 3DES AlgorithmParameters with an IV",
- e);
- }
- }
- return null;
- }
-
- @Override
- protected void initAlgorithmSpecificParameters() throws InvalidKeyException {
- if (!mIvRequired) {
- return;
- }
-
- // IV is used
- if (!isEncrypting()) {
- throw new InvalidKeyException("IV required when decrypting"
- + ". Use IvParameterSpec or AlgorithmParameters to provide it.");
- }
- }
-
- @Override
- protected void initAlgorithmSpecificParameters(AlgorithmParameterSpec params)
- throws InvalidAlgorithmParameterException {
- if (!mIvRequired) {
- if (params != null) {
- throw new InvalidAlgorithmParameterException("Unsupported parameters: " + params);
- }
- return;
- }
-
- // IV is used
- if (params == null) {
- if (!isEncrypting()) {
- // IV must be provided by the caller
- throw new InvalidAlgorithmParameterException(
- "IvParameterSpec must be provided when decrypting");
- }
- return;
- }
- if (!(params instanceof IvParameterSpec)) {
- throw new InvalidAlgorithmParameterException("Only IvParameterSpec supported");
- }
- mIv = ((IvParameterSpec) params).getIV();
- if (mIv == null) {
- throw new InvalidAlgorithmParameterException("Null IV in IvParameterSpec");
- }
- }
-
- @Override
- protected void initAlgorithmSpecificParameters(AlgorithmParameters params)
- throws InvalidAlgorithmParameterException {
- if (!mIvRequired) {
- if (params != null) {
- throw new InvalidAlgorithmParameterException("Unsupported parameters: " + params);
- }
- return;
- }
-
- // IV is used
- if (params == null) {
- if (!isEncrypting()) {
- // IV must be provided by the caller
- throw new InvalidAlgorithmParameterException("IV required when decrypting"
- + ". Use IvParameterSpec or AlgorithmParameters to provide it.");
- }
- return;
- }
-
- if (!"DESede".equalsIgnoreCase(params.getAlgorithm())) {
- throw new InvalidAlgorithmParameterException(
- "Unsupported AlgorithmParameters algorithm: " + params.getAlgorithm()
- + ". Supported: DESede");
- }
-
- IvParameterSpec ivSpec;
- try {
- ivSpec = params.getParameterSpec(IvParameterSpec.class);
- } catch (InvalidParameterSpecException e) {
- if (!isEncrypting()) {
- // IV must be provided by the caller
- throw new InvalidAlgorithmParameterException("IV required when decrypting"
- + ", but not found in parameters: " + params, e);
- }
- mIv = null;
- return;
- }
- mIv = ivSpec.getIV();
- if (mIv == null) {
- throw new InvalidAlgorithmParameterException("Null IV in AlgorithmParameters");
- }
- }
-
- @Override
- protected final int getAdditionalEntropyAmountForBegin() {
- if ((mIvRequired) && (mIv == null) && (isEncrypting())) {
- // IV will need to be generated
- return BLOCK_SIZE_BYTES;
- }
-
- return 0;
- }
-
- @Override
- protected int getAdditionalEntropyAmountForFinish() {
- return 0;
- }
-
- @Override
- protected void addAlgorithmSpecificParametersToBegin(KeymasterArguments keymasterArgs) {
- if ((isEncrypting()) && (mIvRequired) && (mIvHasBeenUsed)) {
- // IV is being reused for encryption: this violates security best practices.
- throw new IllegalStateException(
- "IV has already been used. Reusing IV in encryption mode violates security best"
- + " practices.");
- }
-
- keymasterArgs.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_3DES);
- keymasterArgs.addEnum(KeymasterDefs.KM_TAG_BLOCK_MODE, mKeymasterBlockMode);
- keymasterArgs.addEnum(KeymasterDefs.KM_TAG_PADDING, mKeymasterPadding);
- if ((mIvRequired) && (mIv != null)) {
- keymasterArgs.addBytes(KeymasterDefs.KM_TAG_NONCE, mIv);
- }
- }
-
- @Override
- protected void loadAlgorithmSpecificParametersFromBeginResult(
- KeymasterArguments keymasterArgs) {
- mIvHasBeenUsed = true;
-
- // NOTE: Keymaster doesn't always return an IV, even if it's used.
- byte[] returnedIv = keymasterArgs.getBytes(KeymasterDefs.KM_TAG_NONCE, null);
- if ((returnedIv != null) && (returnedIv.length == 0)) {
- returnedIv = null;
- }
-
- if (mIvRequired) {
- if (mIv == null) {
- mIv = returnedIv;
- } else if ((returnedIv != null) && (!Arrays.equals(returnedIv, mIv))) {
- throw new ProviderException("IV in use differs from provided IV");
- }
- } else {
- if (returnedIv != null) {
- throw new ProviderException(
- "IV in use despite IV not being used by this transformation");
- }
- }
- }
-
- @Override
- protected final void resetAll() {
- mIv = null;
- mIvHasBeenUsed = false;
- super.resetAll();
- }
-}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreAuthenticatedAESCipherSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreAuthenticatedAESCipherSpi.java
deleted file mode 100644
index feb6101..0000000
--- a/keystore/java/android/security/keystore/AndroidKeyStoreAuthenticatedAESCipherSpi.java
+++ /dev/null
@@ -1,449 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.keystore;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.os.IBinder;
-import android.security.KeyStore;
-import android.security.KeyStoreException;
-import android.security.keymaster.KeymasterArguments;
-import android.security.keymaster.KeymasterDefs;
-import android.security.keymaster.OperationResult;
-import android.security.keystore.KeyStoreCryptoOperationChunkedStreamer.Stream;
-
-import libcore.util.EmptyArray;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.security.AlgorithmParameters;
-import java.security.InvalidAlgorithmParameterException;
-import java.security.InvalidKeyException;
-import java.security.Key;
-import java.security.NoSuchAlgorithmException;
-import java.security.ProviderException;
-import java.security.spec.AlgorithmParameterSpec;
-import java.security.spec.InvalidParameterSpecException;
-import java.util.Arrays;
-
-import javax.crypto.CipherSpi;
-import javax.crypto.spec.GCMParameterSpec;
-
-/**
- * Base class for Android Keystore authenticated AES {@link CipherSpi} implementations.
- *
- * @hide
- */
-abstract class AndroidKeyStoreAuthenticatedAESCipherSpi extends AndroidKeyStoreCipherSpiBase {
-
- abstract static class GCM extends AndroidKeyStoreAuthenticatedAESCipherSpi {
- static final int MIN_SUPPORTED_TAG_LENGTH_BITS = 96;
- private static final int MAX_SUPPORTED_TAG_LENGTH_BITS = 128;
- private static final int DEFAULT_TAG_LENGTH_BITS = 128;
- private static final int IV_LENGTH_BYTES = 12;
-
- private int mTagLengthBits = DEFAULT_TAG_LENGTH_BITS;
-
- GCM(int keymasterPadding) {
- super(KeymasterDefs.KM_MODE_GCM, keymasterPadding);
- }
-
- @Override
- protected final void resetAll() {
- mTagLengthBits = DEFAULT_TAG_LENGTH_BITS;
- super.resetAll();
- }
-
- @Override
- protected final void resetWhilePreservingInitState() {
- super.resetWhilePreservingInitState();
- }
-
- @Override
- protected final void initAlgorithmSpecificParameters() throws InvalidKeyException {
- if (!isEncrypting()) {
- throw new InvalidKeyException("IV required when decrypting"
- + ". Use IvParameterSpec or AlgorithmParameters to provide it.");
- }
- }
-
- @Override
- protected final void initAlgorithmSpecificParameters(AlgorithmParameterSpec params)
- throws InvalidAlgorithmParameterException {
- // IV is used
- if (params == null) {
- if (!isEncrypting()) {
- // IV must be provided by the caller
- throw new InvalidAlgorithmParameterException(
- "GCMParameterSpec must be provided when decrypting");
- }
- return;
- }
- if (!(params instanceof GCMParameterSpec)) {
- throw new InvalidAlgorithmParameterException("Only GCMParameterSpec supported");
- }
- GCMParameterSpec spec = (GCMParameterSpec) params;
- byte[] iv = spec.getIV();
- if (iv == null) {
- throw new InvalidAlgorithmParameterException("Null IV in GCMParameterSpec");
- } else if (iv.length != IV_LENGTH_BYTES) {
- throw new InvalidAlgorithmParameterException("Unsupported IV length: "
- + iv.length + " bytes. Only " + IV_LENGTH_BYTES
- + " bytes long IV supported");
- }
- int tagLengthBits = spec.getTLen();
- if ((tagLengthBits < MIN_SUPPORTED_TAG_LENGTH_BITS)
- || (tagLengthBits > MAX_SUPPORTED_TAG_LENGTH_BITS)
- || ((tagLengthBits % 8) != 0)) {
- throw new InvalidAlgorithmParameterException(
- "Unsupported tag length: " + tagLengthBits + " bits"
- + ". Supported lengths: 96, 104, 112, 120, 128");
- }
- setIv(iv);
- mTagLengthBits = tagLengthBits;
- }
-
- @Override
- protected final void initAlgorithmSpecificParameters(AlgorithmParameters params)
- throws InvalidAlgorithmParameterException {
- if (params == null) {
- if (!isEncrypting()) {
- // IV must be provided by the caller
- throw new InvalidAlgorithmParameterException("IV required when decrypting"
- + ". Use GCMParameterSpec or GCM AlgorithmParameters to provide it.");
- }
- return;
- }
-
- if (!"GCM".equalsIgnoreCase(params.getAlgorithm())) {
- throw new InvalidAlgorithmParameterException(
- "Unsupported AlgorithmParameters algorithm: " + params.getAlgorithm()
- + ". Supported: GCM");
- }
-
- GCMParameterSpec spec;
- try {
- spec = params.getParameterSpec(GCMParameterSpec.class);
- } catch (InvalidParameterSpecException e) {
- if (!isEncrypting()) {
- // IV must be provided by the caller
- throw new InvalidAlgorithmParameterException("IV and tag length required when"
- + " decrypting, but not found in parameters: " + params, e);
- }
- setIv(null);
- return;
- }
- initAlgorithmSpecificParameters(spec);
- }
-
- @Nullable
- @Override
- protected final AlgorithmParameters engineGetParameters() {
- byte[] iv = getIv();
- if ((iv != null) && (iv.length > 0)) {
- try {
- AlgorithmParameters params = AlgorithmParameters.getInstance("GCM");
- params.init(new GCMParameterSpec(mTagLengthBits, iv));
- return params;
- } catch (NoSuchAlgorithmException e) {
- throw new ProviderException(
- "Failed to obtain GCM AlgorithmParameters", e);
- } catch (InvalidParameterSpecException e) {
- throw new ProviderException(
- "Failed to initialize GCM AlgorithmParameters", e);
- }
- }
- return null;
- }
-
- @NonNull
- @Override
- protected KeyStoreCryptoOperationStreamer createMainDataStreamer(
- KeyStore keyStore, IBinder operationToken) {
- KeyStoreCryptoOperationStreamer streamer = new KeyStoreCryptoOperationChunkedStreamer(
- new KeyStoreCryptoOperationChunkedStreamer.MainDataStream(
- keyStore, operationToken), 0);
- if (isEncrypting()) {
- return streamer;
- } else {
- // When decrypting, to avoid leaking unauthenticated plaintext, do not return any
- // plaintext before ciphertext is authenticated by KeyStore.finish.
- return new BufferAllOutputUntilDoFinalStreamer(streamer);
- }
- }
-
- @NonNull
- @Override
- protected final KeyStoreCryptoOperationStreamer createAdditionalAuthenticationDataStreamer(
- KeyStore keyStore, IBinder operationToken) {
- return new KeyStoreCryptoOperationChunkedStreamer(
- new AdditionalAuthenticationDataStream(keyStore, operationToken), 0);
- }
-
- @Override
- protected final int getAdditionalEntropyAmountForBegin() {
- if ((getIv() == null) && (isEncrypting())) {
- // IV will need to be generated
- return IV_LENGTH_BYTES;
- }
-
- return 0;
- }
-
- @Override
- protected final int getAdditionalEntropyAmountForFinish() {
- return 0;
- }
-
- @Override
- protected final void addAlgorithmSpecificParametersToBegin(
- @NonNull KeymasterArguments keymasterArgs) {
- super.addAlgorithmSpecificParametersToBegin(keymasterArgs);
- keymasterArgs.addUnsignedInt(KeymasterDefs.KM_TAG_MAC_LENGTH, mTagLengthBits);
- }
-
- protected final int getTagLengthBits() {
- return mTagLengthBits;
- }
-
- public static final class NoPadding extends GCM {
- public NoPadding() {
- super(KeymasterDefs.KM_PAD_NONE);
- }
-
- @Override
- protected final int engineGetOutputSize(int inputLen) {
- int tagLengthBytes = (getTagLengthBits() + 7) / 8;
- long result;
- if (isEncrypting()) {
- result = getConsumedInputSizeBytes() - getProducedOutputSizeBytes() + inputLen
- + tagLengthBytes;
- } else {
- result = getConsumedInputSizeBytes() - getProducedOutputSizeBytes() + inputLen
- - tagLengthBytes;
- }
- if (result < 0) {
- return 0;
- } else if (result > Integer.MAX_VALUE) {
- return Integer.MAX_VALUE;
- }
- return (int) result;
- }
- }
- }
-
- private static final int BLOCK_SIZE_BYTES = 16;
-
- private final int mKeymasterBlockMode;
- private final int mKeymasterPadding;
-
- private byte[] mIv;
-
- /** Whether the current {@code #mIv} has been used by the underlying crypto operation. */
- private boolean mIvHasBeenUsed;
-
- AndroidKeyStoreAuthenticatedAESCipherSpi(
- int keymasterBlockMode,
- int keymasterPadding) {
- mKeymasterBlockMode = keymasterBlockMode;
- mKeymasterPadding = keymasterPadding;
- }
-
- @Override
- protected void resetAll() {
- mIv = null;
- mIvHasBeenUsed = false;
- super.resetAll();
- }
-
- @Override
- protected final void initKey(int opmode, Key key) throws InvalidKeyException {
- if (!(key instanceof AndroidKeyStoreSecretKey)) {
- throw new InvalidKeyException(
- "Unsupported key: " + ((key != null) ? key.getClass().getName() : "null"));
- }
- if (!KeyProperties.KEY_ALGORITHM_AES.equalsIgnoreCase(key.getAlgorithm())) {
- throw new InvalidKeyException(
- "Unsupported key algorithm: " + key.getAlgorithm() + ". Only " +
- KeyProperties.KEY_ALGORITHM_AES + " supported");
- }
- setKey((AndroidKeyStoreSecretKey) key);
- }
-
- @Override
- protected void addAlgorithmSpecificParametersToBegin(
- @NonNull KeymasterArguments keymasterArgs) {
- if ((isEncrypting()) && (mIvHasBeenUsed)) {
- // IV is being reused for encryption: this violates security best practices.
- throw new IllegalStateException(
- "IV has already been used. Reusing IV in encryption mode violates security best"
- + " practices.");
- }
-
- keymasterArgs.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_AES);
- keymasterArgs.addEnum(KeymasterDefs.KM_TAG_BLOCK_MODE, mKeymasterBlockMode);
- keymasterArgs.addEnum(KeymasterDefs.KM_TAG_PADDING, mKeymasterPadding);
- if (mIv != null) {
- keymasterArgs.addBytes(KeymasterDefs.KM_TAG_NONCE, mIv);
- }
- }
-
- @Override
- protected final void loadAlgorithmSpecificParametersFromBeginResult(
- @NonNull KeymasterArguments keymasterArgs) {
- mIvHasBeenUsed = true;
-
- // NOTE: Keymaster doesn't always return an IV, even if it's used.
- byte[] returnedIv = keymasterArgs.getBytes(KeymasterDefs.KM_TAG_NONCE, null);
- if ((returnedIv != null) && (returnedIv.length == 0)) {
- returnedIv = null;
- }
-
- if (mIv == null) {
- mIv = returnedIv;
- } else if ((returnedIv != null) && (!Arrays.equals(returnedIv, mIv))) {
- throw new ProviderException("IV in use differs from provided IV");
- }
- }
-
- @Override
- protected final int engineGetBlockSize() {
- return BLOCK_SIZE_BYTES;
- }
-
- @Override
- protected final byte[] engineGetIV() {
- return ArrayUtils.cloneIfNotEmpty(mIv);
- }
-
- protected void setIv(byte[] iv) {
- mIv = iv;
- }
-
- protected byte[] getIv() {
- return mIv;
- }
-
- /**
- * {@link KeyStoreCryptoOperationStreamer} which buffers all output until {@code doFinal} from
- * which it returns all output in one go, provided {@code doFinal} succeeds.
- */
- private static class BufferAllOutputUntilDoFinalStreamer
- implements KeyStoreCryptoOperationStreamer {
-
- private final KeyStoreCryptoOperationStreamer mDelegate;
- private ByteArrayOutputStream mBufferedOutput = new ByteArrayOutputStream();
- private long mProducedOutputSizeBytes;
-
- private BufferAllOutputUntilDoFinalStreamer(KeyStoreCryptoOperationStreamer delegate) {
- mDelegate = delegate;
- }
-
- @Override
- public byte[] update(byte[] input, int inputOffset, int inputLength)
- throws KeyStoreException {
- byte[] output = mDelegate.update(input, inputOffset, inputLength);
- if (output != null) {
- try {
- mBufferedOutput.write(output);
- } catch (IOException e) {
- throw new ProviderException("Failed to buffer output", e);
- }
- }
- return EmptyArray.BYTE;
- }
-
- @Override
- public byte[] doFinal(byte[] input, int inputOffset, int inputLength,
- byte[] signature, byte[] additionalEntropy) throws KeyStoreException {
- byte[] output = mDelegate.doFinal(input, inputOffset, inputLength, signature,
- additionalEntropy);
- if (output != null) {
- try {
- mBufferedOutput.write(output);
- } catch (IOException e) {
- throw new ProviderException("Failed to buffer output", e);
- }
- }
- byte[] result = mBufferedOutput.toByteArray();
- mBufferedOutput.reset();
- mProducedOutputSizeBytes += result.length;
- return result;
- }
-
- @Override
- public long getConsumedInputSizeBytes() {
- return mDelegate.getConsumedInputSizeBytes();
- }
-
- @Override
- public long getProducedOutputSizeBytes() {
- return mProducedOutputSizeBytes;
- }
- }
-
- /**
- * Additional Authentication Data (AAD) stream via a KeyStore streaming operation. This stream
- * sends AAD into the KeyStore.
- */
- private static class AdditionalAuthenticationDataStream implements Stream {
-
- private final KeyStore mKeyStore;
- private final IBinder mOperationToken;
-
- private AdditionalAuthenticationDataStream(KeyStore keyStore, IBinder operationToken) {
- mKeyStore = keyStore;
- mOperationToken = operationToken;
- }
-
- @Override
- public OperationResult update(byte[] input) {
- KeymasterArguments keymasterArgs = new KeymasterArguments();
- keymasterArgs.addBytes(KeymasterDefs.KM_TAG_ASSOCIATED_DATA, input);
-
- // KeyStore does not reflect AAD in inputConsumed, but users of Stream rely on this
- // field. We fix this discrepancy here. KeyStore.update contract is that all of AAD
- // has been consumed if the method succeeds.
- OperationResult result = mKeyStore.update(mOperationToken, keymasterArgs, null);
- if (result.resultCode == KeyStore.NO_ERROR) {
- result = new OperationResult(
- result.resultCode,
- result.token,
- result.operationHandle,
- input.length, // inputConsumed
- result.output,
- result.outParams);
- }
- return result;
- }
-
- @Override
- public OperationResult finish(byte[] input, byte[] signature, byte[] additionalEntropy) {
- if ((additionalEntropy != null) && (additionalEntropy.length > 0)) {
- throw new ProviderException("AAD stream does not support additional entropy");
- }
- return new OperationResult(
- KeyStore.NO_ERROR,
- mOperationToken,
- 0, // operation handle -- nobody cares about this being returned from finish
- 0, // inputConsumed
- EmptyArray.BYTE, // output
- new KeymasterArguments() // additional params returned by finish
- );
- }
- }
-}
\ No newline at end of file
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreBCWorkaroundProvider.java b/keystore/java/android/security/keystore/AndroidKeyStoreBCWorkaroundProvider.java
deleted file mode 100644
index 5730234..0000000
--- a/keystore/java/android/security/keystore/AndroidKeyStoreBCWorkaroundProvider.java
+++ /dev/null
@@ -1,279 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.keystore;
-
-import java.security.Provider;
-
-/**
- * {@link Provider} of JCA crypto operations operating on Android KeyStore keys.
- *
- * <p>This provider was separated out of {@link AndroidKeyStoreProvider} to work around the issue
- * that Bouncy Castle provider incorrectly declares that it accepts arbitrary keys (incl. Android
- * KeyStore ones). This causes JCA to select the Bouncy Castle's implementation of JCA crypto
- * operations for Android KeyStore keys unless Android KeyStore's own implementations are installed
- * as higher-priority than Bouncy Castle ones. The purpose of this provider is to do just that: to
- * offer crypto operations operating on Android KeyStore keys and to be installed at higher priority
- * than the Bouncy Castle provider.
- *
- * <p>Once Bouncy Castle provider is fixed, this provider can be merged into the
- * {@code AndroidKeyStoreProvider}.
- *
- * @hide
- */
-public class AndroidKeyStoreBCWorkaroundProvider extends Provider {
-
- // IMPLEMENTATION NOTE: Class names are hard-coded in this provider to avoid loading these
- // classes when this provider is instantiated and installed early on during each app's
- // initialization process.
-
- private static final String PACKAGE_NAME = "android.security.keystore";
- private static final String KEYSTORE_SECRET_KEY_CLASS_NAME =
- PACKAGE_NAME + ".AndroidKeyStoreSecretKey";
- private static final String KEYSTORE_PRIVATE_KEY_CLASS_NAME =
- PACKAGE_NAME + ".AndroidKeyStorePrivateKey";
- private static final String KEYSTORE_PUBLIC_KEY_CLASS_NAME =
- PACKAGE_NAME + ".AndroidKeyStorePublicKey";
-
- private static final String DESEDE_SYSTEM_PROPERTY = "ro.hardware.keystore_desede";
-
- /** @hide */
- public AndroidKeyStoreBCWorkaroundProvider() {
- this("AndroidKeyStoreBCWorkaround");
- }
-
- /** @hide **/
- public AndroidKeyStoreBCWorkaroundProvider(String providerName) {
- super(providerName,
- 1.0,
- "Android KeyStore security provider to work around Bouncy Castle");
-
- // --------------------- javax.crypto.Mac
- putMacImpl("HmacSHA1", PACKAGE_NAME + ".AndroidKeyStoreHmacSpi$HmacSHA1");
- put("Alg.Alias.Mac.1.2.840.113549.2.7", "HmacSHA1");
- put("Alg.Alias.Mac.HMAC-SHA1", "HmacSHA1");
- put("Alg.Alias.Mac.HMAC/SHA1", "HmacSHA1");
-
- putMacImpl("HmacSHA224", PACKAGE_NAME + ".AndroidKeyStoreHmacSpi$HmacSHA224");
- put("Alg.Alias.Mac.1.2.840.113549.2.9", "HmacSHA224");
- put("Alg.Alias.Mac.HMAC-SHA224", "HmacSHA224");
- put("Alg.Alias.Mac.HMAC/SHA224", "HmacSHA224");
-
- putMacImpl("HmacSHA256", PACKAGE_NAME + ".AndroidKeyStoreHmacSpi$HmacSHA256");
- put("Alg.Alias.Mac.1.2.840.113549.2.9", "HmacSHA256");
- put("Alg.Alias.Mac.HMAC-SHA256", "HmacSHA256");
- put("Alg.Alias.Mac.HMAC/SHA256", "HmacSHA256");
-
- putMacImpl("HmacSHA384", PACKAGE_NAME + ".AndroidKeyStoreHmacSpi$HmacSHA384");
- put("Alg.Alias.Mac.1.2.840.113549.2.10", "HmacSHA384");
- put("Alg.Alias.Mac.HMAC-SHA384", "HmacSHA384");
- put("Alg.Alias.Mac.HMAC/SHA384", "HmacSHA384");
-
- putMacImpl("HmacSHA512", PACKAGE_NAME + ".AndroidKeyStoreHmacSpi$HmacSHA512");
- put("Alg.Alias.Mac.1.2.840.113549.2.11", "HmacSHA512");
- put("Alg.Alias.Mac.HMAC-SHA512", "HmacSHA512");
- put("Alg.Alias.Mac.HMAC/SHA512", "HmacSHA512");
-
- // --------------------- javax.crypto.Cipher
- putSymmetricCipherImpl("AES/ECB/NoPadding",
- PACKAGE_NAME + ".AndroidKeyStoreUnauthenticatedAESCipherSpi$ECB$NoPadding");
- putSymmetricCipherImpl("AES/ECB/PKCS7Padding",
- PACKAGE_NAME + ".AndroidKeyStoreUnauthenticatedAESCipherSpi$ECB$PKCS7Padding");
-
- putSymmetricCipherImpl("AES/CBC/NoPadding",
- PACKAGE_NAME + ".AndroidKeyStoreUnauthenticatedAESCipherSpi$CBC$NoPadding");
- putSymmetricCipherImpl("AES/CBC/PKCS7Padding",
- PACKAGE_NAME + ".AndroidKeyStoreUnauthenticatedAESCipherSpi$CBC$PKCS7Padding");
-
- putSymmetricCipherImpl("AES/CTR/NoPadding",
- PACKAGE_NAME + ".AndroidKeyStoreUnauthenticatedAESCipherSpi$CTR$NoPadding");
-
- if ("true".equals(android.os.SystemProperties.get(DESEDE_SYSTEM_PROPERTY))) {
- putSymmetricCipherImpl("DESede/CBC/NoPadding",
- PACKAGE_NAME + ".AndroidKeyStore3DESCipherSpi$CBC$NoPadding");
- putSymmetricCipherImpl("DESede/CBC/PKCS7Padding",
- PACKAGE_NAME + ".AndroidKeyStore3DESCipherSpi$CBC$PKCS7Padding");
-
- putSymmetricCipherImpl("DESede/ECB/NoPadding",
- PACKAGE_NAME + ".AndroidKeyStore3DESCipherSpi$ECB$NoPadding");
- putSymmetricCipherImpl("DESede/ECB/PKCS7Padding",
- PACKAGE_NAME + ".AndroidKeyStore3DESCipherSpi$ECB$PKCS7Padding");
- }
-
- putSymmetricCipherImpl("AES/GCM/NoPadding",
- PACKAGE_NAME + ".AndroidKeyStoreAuthenticatedAESCipherSpi$GCM$NoPadding");
-
- putAsymmetricCipherImpl("RSA/ECB/NoPadding",
- PACKAGE_NAME + ".AndroidKeyStoreRSACipherSpi$NoPadding");
- put("Alg.Alias.Cipher.RSA/None/NoPadding", "RSA/ECB/NoPadding");
- putAsymmetricCipherImpl("RSA/ECB/PKCS1Padding",
- PACKAGE_NAME + ".AndroidKeyStoreRSACipherSpi$PKCS1Padding");
- put("Alg.Alias.Cipher.RSA/None/PKCS1Padding", "RSA/ECB/PKCS1Padding");
- putAsymmetricCipherImpl("RSA/ECB/OAEPPadding",
- PACKAGE_NAME + ".AndroidKeyStoreRSACipherSpi$OAEPWithSHA1AndMGF1Padding");
- put("Alg.Alias.Cipher.RSA/None/OAEPPadding", "RSA/ECB/OAEPPadding");
- putAsymmetricCipherImpl("RSA/ECB/OAEPWithSHA-1AndMGF1Padding",
- PACKAGE_NAME + ".AndroidKeyStoreRSACipherSpi$OAEPWithSHA1AndMGF1Padding");
- put("Alg.Alias.Cipher.RSA/None/OAEPWithSHA-1AndMGF1Padding",
- "RSA/ECB/OAEPWithSHA-1AndMGF1Padding");
- putAsymmetricCipherImpl("RSA/ECB/OAEPWithSHA-224AndMGF1Padding",
- PACKAGE_NAME + ".AndroidKeyStoreRSACipherSpi$OAEPWithSHA224AndMGF1Padding");
- put("Alg.Alias.Cipher.RSA/None/OAEPWithSHA-224AndMGF1Padding",
- "RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
- putAsymmetricCipherImpl("RSA/ECB/OAEPWithSHA-256AndMGF1Padding",
- PACKAGE_NAME + ".AndroidKeyStoreRSACipherSpi$OAEPWithSHA256AndMGF1Padding");
- put("Alg.Alias.Cipher.RSA/None/OAEPWithSHA-256AndMGF1Padding",
- "RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
- putAsymmetricCipherImpl("RSA/ECB/OAEPWithSHA-384AndMGF1Padding",
- PACKAGE_NAME + ".AndroidKeyStoreRSACipherSpi$OAEPWithSHA384AndMGF1Padding");
- put("Alg.Alias.Cipher.RSA/None/OAEPWithSHA-384AndMGF1Padding",
- "RSA/ECB/OAEPWithSHA-384AndMGF1Padding");
- putAsymmetricCipherImpl("RSA/ECB/OAEPWithSHA-512AndMGF1Padding",
- PACKAGE_NAME + ".AndroidKeyStoreRSACipherSpi$OAEPWithSHA512AndMGF1Padding");
- put("Alg.Alias.Cipher.RSA/None/OAEPWithSHA-512AndMGF1Padding",
- "RSA/ECB/OAEPWithSHA-512AndMGF1Padding");
-
- // --------------------- java.security.Signature
- putSignatureImpl("NONEwithRSA",
- PACKAGE_NAME + ".AndroidKeyStoreRSASignatureSpi$NONEWithPKCS1Padding");
-
- putSignatureImpl("MD5withRSA",
- PACKAGE_NAME + ".AndroidKeyStoreRSASignatureSpi$MD5WithPKCS1Padding");
- put("Alg.Alias.Signature.MD5WithRSAEncryption", "MD5withRSA");
- put("Alg.Alias.Signature.MD5/RSA", "MD5withRSA");
- put("Alg.Alias.Signature.1.2.840.113549.1.1.4", "MD5withRSA");
- put("Alg.Alias.Signature.1.2.840.113549.2.5with1.2.840.113549.1.1.1", "MD5withRSA");
-
- putSignatureImpl("SHA1withRSA",
- PACKAGE_NAME + ".AndroidKeyStoreRSASignatureSpi$SHA1WithPKCS1Padding");
- put("Alg.Alias.Signature.SHA1WithRSAEncryption", "SHA1withRSA");
- put("Alg.Alias.Signature.SHA1/RSA", "SHA1withRSA");
- put("Alg.Alias.Signature.SHA-1/RSA", "SHA1withRSA");
- put("Alg.Alias.Signature.1.2.840.113549.1.1.5", "SHA1withRSA");
- put("Alg.Alias.Signature.1.3.14.3.2.26with1.2.840.113549.1.1.1", "SHA1withRSA");
- put("Alg.Alias.Signature.1.3.14.3.2.26with1.2.840.113549.1.1.5", "SHA1withRSA");
- put("Alg.Alias.Signature.1.3.14.3.2.29", "SHA1withRSA");
-
- putSignatureImpl("SHA224withRSA",
- PACKAGE_NAME + ".AndroidKeyStoreRSASignatureSpi$SHA224WithPKCS1Padding");
- put("Alg.Alias.Signature.SHA224WithRSAEncryption", "SHA224withRSA");
- put("Alg.Alias.Signature.1.2.840.113549.1.1.11", "SHA224withRSA");
- put("Alg.Alias.Signature.2.16.840.1.101.3.4.2.4with1.2.840.113549.1.1.1",
- "SHA224withRSA");
- put("Alg.Alias.Signature.2.16.840.1.101.3.4.2.4with1.2.840.113549.1.1.11",
- "SHA224withRSA");
-
- putSignatureImpl("SHA256withRSA",
- PACKAGE_NAME + ".AndroidKeyStoreRSASignatureSpi$SHA256WithPKCS1Padding");
- put("Alg.Alias.Signature.SHA256WithRSAEncryption", "SHA256withRSA");
- put("Alg.Alias.Signature.1.2.840.113549.1.1.11", "SHA256withRSA");
- put("Alg.Alias.Signature.2.16.840.1.101.3.4.2.1with1.2.840.113549.1.1.1",
- "SHA256withRSA");
- put("Alg.Alias.Signature.2.16.840.1.101.3.4.2.1with1.2.840.113549.1.1.11",
- "SHA256withRSA");
-
- putSignatureImpl("SHA384withRSA",
- PACKAGE_NAME + ".AndroidKeyStoreRSASignatureSpi$SHA384WithPKCS1Padding");
- put("Alg.Alias.Signature.SHA384WithRSAEncryption", "SHA384withRSA");
- put("Alg.Alias.Signature.1.2.840.113549.1.1.12", "SHA384withRSA");
- put("Alg.Alias.Signature.2.16.840.1.101.3.4.2.2with1.2.840.113549.1.1.1",
- "SHA384withRSA");
-
- putSignatureImpl("SHA512withRSA",
- PACKAGE_NAME + ".AndroidKeyStoreRSASignatureSpi$SHA512WithPKCS1Padding");
- put("Alg.Alias.Signature.SHA512WithRSAEncryption", "SHA512withRSA");
- put("Alg.Alias.Signature.1.2.840.113549.1.1.13", "SHA512withRSA");
- put("Alg.Alias.Signature.2.16.840.1.101.3.4.2.3with1.2.840.113549.1.1.1",
- "SHA512withRSA");
-
- putSignatureImpl("SHA1withRSA/PSS",
- PACKAGE_NAME + ".AndroidKeyStoreRSASignatureSpi$SHA1WithPSSPadding");
- putSignatureImpl("SHA224withRSA/PSS",
- PACKAGE_NAME + ".AndroidKeyStoreRSASignatureSpi$SHA224WithPSSPadding");
- putSignatureImpl("SHA256withRSA/PSS",
- PACKAGE_NAME + ".AndroidKeyStoreRSASignatureSpi$SHA256WithPSSPadding");
- putSignatureImpl("SHA384withRSA/PSS",
- PACKAGE_NAME + ".AndroidKeyStoreRSASignatureSpi$SHA384WithPSSPadding");
- putSignatureImpl("SHA512withRSA/PSS",
- PACKAGE_NAME + ".AndroidKeyStoreRSASignatureSpi$SHA512WithPSSPadding");
-
- putSignatureImpl("NONEwithECDSA",
- PACKAGE_NAME + ".AndroidKeyStoreECDSASignatureSpi$NONE");
-
- putSignatureImpl("SHA1withECDSA", PACKAGE_NAME + ".AndroidKeyStoreECDSASignatureSpi$SHA1");
- put("Alg.Alias.Signature.ECDSA", "SHA1withECDSA");
- put("Alg.Alias.Signature.ECDSAwithSHA1", "SHA1withECDSA");
- // iso(1) member-body(2) us(840) ansi-x962(10045) signatures(4) ecdsa-with-SHA1(1)
- put("Alg.Alias.Signature.1.2.840.10045.4.1", "SHA1withECDSA");
- put("Alg.Alias.Signature.1.3.14.3.2.26with1.2.840.10045.2.1", "SHA1withECDSA");
-
- // iso(1) member-body(2) us(840) ansi-x962(10045) signatures(4) ecdsa-with-SHA2(3)
- putSignatureImpl("SHA224withECDSA",
- PACKAGE_NAME + ".AndroidKeyStoreECDSASignatureSpi$SHA224");
- // ecdsa-with-SHA224(1)
- put("Alg.Alias.Signature.1.2.840.10045.4.3.1", "SHA224withECDSA");
- put("Alg.Alias.Signature.2.16.840.1.101.3.4.2.4with1.2.840.10045.2.1", "SHA224withECDSA");
-
- // iso(1) member-body(2) us(840) ansi-x962(10045) signatures(4) ecdsa-with-SHA2(3)
- putSignatureImpl("SHA256withECDSA",
- PACKAGE_NAME + ".AndroidKeyStoreECDSASignatureSpi$SHA256");
- // ecdsa-with-SHA256(2)
- put("Alg.Alias.Signature.1.2.840.10045.4.3.2", "SHA256withECDSA");
- put("Alg.Alias.Signature.2.16.840.1.101.3.4.2.1with1.2.840.10045.2.1", "SHA256withECDSA");
-
- putSignatureImpl("SHA384withECDSA",
- PACKAGE_NAME + ".AndroidKeyStoreECDSASignatureSpi$SHA384");
- // ecdsa-with-SHA384(3)
- put("Alg.Alias.Signature.1.2.840.10045.4.3.3", "SHA384withECDSA");
- put("Alg.Alias.Signature.2.16.840.1.101.3.4.2.2with1.2.840.10045.2.1", "SHA384withECDSA");
-
- putSignatureImpl("SHA512withECDSA",
- PACKAGE_NAME + ".AndroidKeyStoreECDSASignatureSpi$SHA512");
- // ecdsa-with-SHA512(4)
- put("Alg.Alias.Signature.1.2.840.10045.4.3.4", "SHA512withECDSA");
- put("Alg.Alias.Signature.2.16.840.1.101.3.4.2.3with1.2.840.10045.2.1", "SHA512withECDSA");
- }
-
- private void putMacImpl(String algorithm, String implClass) {
- put("Mac." + algorithm, implClass);
- put("Mac." + algorithm + " SupportedKeyClasses", KEYSTORE_SECRET_KEY_CLASS_NAME);
- }
-
- private void putSymmetricCipherImpl(String transformation, String implClass) {
- put("Cipher." + transformation, implClass);
- put("Cipher." + transformation + " SupportedKeyClasses", KEYSTORE_SECRET_KEY_CLASS_NAME);
- }
-
- private void putAsymmetricCipherImpl(String transformation, String implClass) {
- put("Cipher." + transformation, implClass);
- put("Cipher." + transformation + " SupportedKeyClasses",
- KEYSTORE_PRIVATE_KEY_CLASS_NAME + "|" + KEYSTORE_PUBLIC_KEY_CLASS_NAME);
- }
-
- private void putSignatureImpl(String algorithm, String implClass) {
- put("Signature." + algorithm, implClass);
- put("Signature." + algorithm + " SupportedKeyClasses",
- KEYSTORE_PRIVATE_KEY_CLASS_NAME + "|" + KEYSTORE_PUBLIC_KEY_CLASS_NAME);
- }
-
- public static String[] getSupportedEcdsaSignatureDigests() {
- return new String[] {"NONE", "SHA-1", "SHA-224", "SHA-256", "SHA-384", "SHA-512"};
- }
-
- public static String[] getSupportedRsaSignatureWithPkcs1PaddingDigests() {
- return new String[] {"NONE", "MD5", "SHA-1", "SHA-224", "SHA-256", "SHA-384", "SHA-512"};
- }
-}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreCipherSpiBase.java b/keystore/java/android/security/keystore/AndroidKeyStoreCipherSpiBase.java
deleted file mode 100644
index ccc3153..0000000
--- a/keystore/java/android/security/keystore/AndroidKeyStoreCipherSpiBase.java
+++ /dev/null
@@ -1,920 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.keystore;
-
-import android.annotation.CallSuper;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.os.IBinder;
-import android.security.KeyStore;
-import android.security.KeyStoreException;
-import android.security.keymaster.KeymasterArguments;
-import android.security.keymaster.KeymasterDefs;
-import android.security.keymaster.OperationResult;
-
-import libcore.util.EmptyArray;
-
-import java.nio.BufferOverflowException;
-import java.nio.ByteBuffer;
-import java.security.AlgorithmParameters;
-import java.security.GeneralSecurityException;
-import java.security.InvalidAlgorithmParameterException;
-import java.security.InvalidKeyException;
-import java.security.InvalidParameterException;
-import java.security.Key;
-import java.security.KeyFactory;
-import java.security.NoSuchAlgorithmException;
-import java.security.PrivateKey;
-import java.security.ProviderException;
-import java.security.PublicKey;
-import java.security.SecureRandom;
-import java.security.spec.AlgorithmParameterSpec;
-import java.security.spec.InvalidKeySpecException;
-import java.security.spec.PKCS8EncodedKeySpec;
-import java.security.spec.X509EncodedKeySpec;
-
-import javax.crypto.AEADBadTagException;
-import javax.crypto.BadPaddingException;
-import javax.crypto.Cipher;
-import javax.crypto.CipherSpi;
-import javax.crypto.IllegalBlockSizeException;
-import javax.crypto.NoSuchPaddingException;
-import javax.crypto.SecretKey;
-import javax.crypto.SecretKeyFactory;
-import javax.crypto.ShortBufferException;
-import javax.crypto.spec.SecretKeySpec;
-
-/**
- * Base class for {@link CipherSpi} implementations of Android KeyStore backed ciphers.
- *
- * @hide
- */
-abstract class AndroidKeyStoreCipherSpiBase extends CipherSpi implements KeyStoreCryptoOperation {
- private final KeyStore mKeyStore;
-
- // Fields below are populated by Cipher.init and KeyStore.begin and should be preserved after
- // doFinal finishes.
- private boolean mEncrypting;
- private int mKeymasterPurposeOverride = -1;
- private AndroidKeyStoreKey mKey;
- private SecureRandom mRng;
-
- /**
- * Token referencing this operation inside keystore service. It is initialized by
- * {@code engineInit} and is invalidated when {@code engineDoFinal} succeeds and on some error
- * conditions in between.
- */
- private IBinder mOperationToken;
- private long mOperationHandle;
- private KeyStoreCryptoOperationStreamer mMainDataStreamer;
- private KeyStoreCryptoOperationStreamer mAdditionalAuthenticationDataStreamer;
- private boolean mAdditionalAuthenticationDataStreamerClosed;
-
- /**
- * Encountered exception which could not be immediately thrown because it was encountered inside
- * a method that does not throw checked exception. This exception will be thrown from
- * {@code engineDoFinal}. Once such an exception is encountered, {@code engineUpdate} and
- * {@code engineDoFinal} start ignoring input data.
- */
- private Exception mCachedException;
-
- AndroidKeyStoreCipherSpiBase() {
- mKeyStore = KeyStore.getInstance();
- }
-
- @Override
- protected final void engineInit(int opmode, Key key, SecureRandom random)
- throws InvalidKeyException {
- resetAll();
-
- boolean success = false;
- try {
- init(opmode, key, random);
- initAlgorithmSpecificParameters();
- try {
- ensureKeystoreOperationInitialized();
- } catch (InvalidAlgorithmParameterException e) {
- throw new InvalidKeyException(e);
- }
- success = true;
- } finally {
- if (!success) {
- resetAll();
- }
- }
- }
-
- @Override
- protected final void engineInit(int opmode, Key key, AlgorithmParameters params,
- SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException {
- resetAll();
-
- boolean success = false;
- try {
- init(opmode, key, random);
- initAlgorithmSpecificParameters(params);
- ensureKeystoreOperationInitialized();
- success = true;
- } finally {
- if (!success) {
- resetAll();
- }
- }
- }
-
- @Override
- protected final void engineInit(int opmode, Key key, AlgorithmParameterSpec params,
- SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException {
- resetAll();
-
- boolean success = false;
- try {
- init(opmode, key, random);
- initAlgorithmSpecificParameters(params);
- ensureKeystoreOperationInitialized();
- success = true;
- } finally {
- if (!success) {
- resetAll();
- }
- }
- }
-
- private void init(int opmode, Key key, SecureRandom random) throws InvalidKeyException {
- switch (opmode) {
- case Cipher.ENCRYPT_MODE:
- case Cipher.WRAP_MODE:
- mEncrypting = true;
- break;
- case Cipher.DECRYPT_MODE:
- case Cipher.UNWRAP_MODE:
- mEncrypting = false;
- break;
- default:
- throw new InvalidParameterException("Unsupported opmode: " + opmode);
- }
- initKey(opmode, key);
- if (mKey == null) {
- throw new ProviderException("initKey did not initialize the key");
- }
- mRng = random;
- }
-
- /**
- * Resets this cipher to its pristine pre-init state. This must be equivalent to obtaining a new
- * cipher instance.
- *
- * <p>Subclasses storing additional state should override this method, reset the additional
- * state, and then chain to superclass.
- */
- @CallSuper
- protected void resetAll() {
- IBinder operationToken = mOperationToken;
- if (operationToken != null) {
- mKeyStore.abort(operationToken);
- }
- mEncrypting = false;
- mKeymasterPurposeOverride = -1;
- mKey = null;
- mRng = null;
- mOperationToken = null;
- mOperationHandle = 0;
- mMainDataStreamer = null;
- mAdditionalAuthenticationDataStreamer = null;
- mAdditionalAuthenticationDataStreamerClosed = false;
- mCachedException = null;
- }
-
- /**
- * Resets this cipher while preserving the initialized state. This must be equivalent to
- * rolling back the cipher's state to just after the most recent {@code engineInit} completed
- * successfully.
- *
- * <p>Subclasses storing additional post-init state should override this method, reset the
- * additional state, and then chain to superclass.
- */
- @CallSuper
- protected void resetWhilePreservingInitState() {
- IBinder operationToken = mOperationToken;
- if (operationToken != null) {
- mKeyStore.abort(operationToken);
- }
- mOperationToken = null;
- mOperationHandle = 0;
- mMainDataStreamer = null;
- mAdditionalAuthenticationDataStreamer = null;
- mAdditionalAuthenticationDataStreamerClosed = false;
- mCachedException = null;
- }
-
- private void ensureKeystoreOperationInitialized() throws InvalidKeyException,
- InvalidAlgorithmParameterException {
- if (mMainDataStreamer != null) {
- return;
- }
- if (mCachedException != null) {
- return;
- }
- if (mKey == null) {
- throw new IllegalStateException("Not initialized");
- }
-
- KeymasterArguments keymasterInputArgs = new KeymasterArguments();
- addAlgorithmSpecificParametersToBegin(keymasterInputArgs);
- byte[] additionalEntropy = KeyStoreCryptoOperationUtils.getRandomBytesToMixIntoKeystoreRng(
- mRng, getAdditionalEntropyAmountForBegin());
-
- int purpose;
- if (mKeymasterPurposeOverride != -1) {
- purpose = mKeymasterPurposeOverride;
- } else {
- purpose = mEncrypting
- ? KeymasterDefs.KM_PURPOSE_ENCRYPT : KeymasterDefs.KM_PURPOSE_DECRYPT;
- }
- OperationResult opResult = mKeyStore.begin(
- mKey.getAlias(),
- purpose,
- true, // permit aborting this operation if keystore runs out of resources
- keymasterInputArgs,
- additionalEntropy,
- mKey.getUid());
- if (opResult == null) {
- throw new KeyStoreConnectException();
- }
-
- // Store operation token and handle regardless of the error code returned by KeyStore to
- // ensure that the operation gets aborted immediately if the code below throws an exception.
- mOperationToken = opResult.token;
- mOperationHandle = opResult.operationHandle;
-
- // If necessary, throw an exception due to KeyStore operation having failed.
- GeneralSecurityException e = KeyStoreCryptoOperationUtils.getExceptionForCipherInit(
- mKeyStore, mKey, opResult.resultCode);
- if (e != null) {
- if (e instanceof InvalidKeyException) {
- throw (InvalidKeyException) e;
- } else if (e instanceof InvalidAlgorithmParameterException) {
- throw (InvalidAlgorithmParameterException) e;
- } else {
- throw new ProviderException("Unexpected exception type", e);
- }
- }
-
- if (mOperationToken == null) {
- throw new ProviderException("Keystore returned null operation token");
- }
- if (mOperationHandle == 0) {
- throw new ProviderException("Keystore returned invalid operation handle");
- }
-
- loadAlgorithmSpecificParametersFromBeginResult(opResult.outParams);
- mMainDataStreamer = createMainDataStreamer(mKeyStore, opResult.token);
- mAdditionalAuthenticationDataStreamer =
- createAdditionalAuthenticationDataStreamer(mKeyStore, opResult.token);
- mAdditionalAuthenticationDataStreamerClosed = false;
- }
-
- /**
- * Creates a streamer which sends plaintext/ciphertext into the provided KeyStore and receives
- * the corresponding ciphertext/plaintext from the KeyStore.
- *
- * <p>This implementation returns a working streamer.
- */
- @NonNull
- protected KeyStoreCryptoOperationStreamer createMainDataStreamer(
- KeyStore keyStore, IBinder operationToken) {
- return new KeyStoreCryptoOperationChunkedStreamer(
- new KeyStoreCryptoOperationChunkedStreamer.MainDataStream(
- keyStore, operationToken), 0);
- }
-
- /**
- * Creates a streamer which sends Additional Authentication Data (AAD) into the KeyStore.
- *
- * <p>This implementation returns {@code null}.
- *
- * @return stream or {@code null} if AAD is not supported by this cipher.
- */
- @Nullable
- protected KeyStoreCryptoOperationStreamer createAdditionalAuthenticationDataStreamer(
- @SuppressWarnings("unused") KeyStore keyStore,
- @SuppressWarnings("unused") IBinder operationToken) {
- return null;
- }
-
- @Override
- protected final byte[] engineUpdate(byte[] input, int inputOffset, int inputLen) {
- if (mCachedException != null) {
- return null;
- }
- try {
- ensureKeystoreOperationInitialized();
- } catch (InvalidKeyException | InvalidAlgorithmParameterException e) {
- mCachedException = e;
- return null;
- }
-
- if (inputLen == 0) {
- return null;
- }
-
- byte[] output;
- try {
- flushAAD();
- output = mMainDataStreamer.update(input, inputOffset, inputLen);
- } catch (KeyStoreException e) {
- mCachedException = e;
- return null;
- }
-
- if (output.length == 0) {
- return null;
- }
-
- return output;
- }
-
- private void flushAAD() throws KeyStoreException {
- if ((mAdditionalAuthenticationDataStreamer != null)
- && (!mAdditionalAuthenticationDataStreamerClosed)) {
- byte[] output;
- try {
- output = mAdditionalAuthenticationDataStreamer.doFinal(
- EmptyArray.BYTE, 0, 0,
- null, // no signature
- null // no additional entropy needed flushing AAD
- );
- } finally {
- mAdditionalAuthenticationDataStreamerClosed = true;
- }
- if ((output != null) && (output.length > 0)) {
- throw new ProviderException(
- "AAD update unexpectedly returned data: " + output.length + " bytes");
- }
- }
- }
-
- @Override
- protected final int engineUpdate(byte[] input, int inputOffset, int inputLen, byte[] output,
- int outputOffset) throws ShortBufferException {
- byte[] outputCopy = engineUpdate(input, inputOffset, inputLen);
- if (outputCopy == null) {
- return 0;
- }
- int outputAvailable = output.length - outputOffset;
- if (outputCopy.length > outputAvailable) {
- throw new ShortBufferException("Output buffer too short. Produced: "
- + outputCopy.length + ", available: " + outputAvailable);
- }
- System.arraycopy(outputCopy, 0, output, outputOffset, outputCopy.length);
- return outputCopy.length;
- }
-
- @Override
- protected final int engineUpdate(ByteBuffer input, ByteBuffer output)
- throws ShortBufferException {
- if (input == null) {
- throw new NullPointerException("input == null");
- }
- if (output == null) {
- throw new NullPointerException("output == null");
- }
-
- int inputSize = input.remaining();
- byte[] outputArray;
- if (input.hasArray()) {
- outputArray =
- engineUpdate(
- input.array(), input.arrayOffset() + input.position(), inputSize);
- input.position(input.position() + inputSize);
- } else {
- byte[] inputArray = new byte[inputSize];
- input.get(inputArray);
- outputArray = engineUpdate(inputArray, 0, inputSize);
- }
-
- int outputSize = (outputArray != null) ? outputArray.length : 0;
- if (outputSize > 0) {
- int outputBufferAvailable = output.remaining();
- try {
- output.put(outputArray);
- } catch (BufferOverflowException e) {
- throw new ShortBufferException(
- "Output buffer too small. Produced: " + outputSize + ", available: "
- + outputBufferAvailable);
- }
- }
- return outputSize;
- }
-
- @Override
- protected final void engineUpdateAAD(byte[] input, int inputOffset, int inputLen) {
- if (mCachedException != null) {
- return;
- }
-
- try {
- ensureKeystoreOperationInitialized();
- } catch (InvalidKeyException | InvalidAlgorithmParameterException e) {
- mCachedException = e;
- return;
- }
-
- if (mAdditionalAuthenticationDataStreamerClosed) {
- throw new IllegalStateException(
- "AAD can only be provided before Cipher.update is invoked");
- }
-
- if (mAdditionalAuthenticationDataStreamer == null) {
- throw new IllegalStateException("This cipher does not support AAD");
- }
-
- byte[] output;
- try {
- output = mAdditionalAuthenticationDataStreamer.update(input, inputOffset, inputLen);
- } catch (KeyStoreException e) {
- mCachedException = e;
- return;
- }
-
- if ((output != null) && (output.length > 0)) {
- throw new ProviderException("AAD update unexpectedly produced output: "
- + output.length + " bytes");
- }
- }
-
- @Override
- protected final void engineUpdateAAD(ByteBuffer src) {
- if (src == null) {
- throw new IllegalArgumentException("src == null");
- }
- if (!src.hasRemaining()) {
- return;
- }
-
- byte[] input;
- int inputOffset;
- int inputLen;
- if (src.hasArray()) {
- input = src.array();
- inputOffset = src.arrayOffset() + src.position();
- inputLen = src.remaining();
- src.position(src.limit());
- } else {
- input = new byte[src.remaining()];
- inputOffset = 0;
- inputLen = input.length;
- src.get(input);
- }
- engineUpdateAAD(input, inputOffset, inputLen);
- }
-
- @Override
- protected final byte[] engineDoFinal(byte[] input, int inputOffset, int inputLen)
- throws IllegalBlockSizeException, BadPaddingException {
- if (mCachedException != null) {
- throw (IllegalBlockSizeException)
- new IllegalBlockSizeException().initCause(mCachedException);
- }
-
- try {
- ensureKeystoreOperationInitialized();
- } catch (InvalidKeyException | InvalidAlgorithmParameterException e) {
- throw (IllegalBlockSizeException) new IllegalBlockSizeException().initCause(e);
- }
-
- byte[] output;
- try {
- flushAAD();
- byte[] additionalEntropy =
- KeyStoreCryptoOperationUtils.getRandomBytesToMixIntoKeystoreRng(
- mRng, getAdditionalEntropyAmountForFinish());
- output = mMainDataStreamer.doFinal(
- input, inputOffset, inputLen,
- null, // no signature involved
- additionalEntropy);
- } catch (KeyStoreException e) {
- switch (e.getErrorCode()) {
- case KeymasterDefs.KM_ERROR_INVALID_INPUT_LENGTH:
- throw (IllegalBlockSizeException) new IllegalBlockSizeException().initCause(e);
- case KeymasterDefs.KM_ERROR_INVALID_ARGUMENT:
- throw (BadPaddingException) new BadPaddingException().initCause(e);
- case KeymasterDefs.KM_ERROR_VERIFICATION_FAILED:
- throw (AEADBadTagException) new AEADBadTagException().initCause(e);
- default:
- throw (IllegalBlockSizeException) new IllegalBlockSizeException().initCause(e);
- }
- }
-
- resetWhilePreservingInitState();
- return output;
- }
-
- @Override
- protected final int engineDoFinal(byte[] input, int inputOffset, int inputLen, byte[] output,
- int outputOffset) throws ShortBufferException, IllegalBlockSizeException,
- BadPaddingException {
- byte[] outputCopy = engineDoFinal(input, inputOffset, inputLen);
- if (outputCopy == null) {
- return 0;
- }
- int outputAvailable = output.length - outputOffset;
- if (outputCopy.length > outputAvailable) {
- throw new ShortBufferException("Output buffer too short. Produced: "
- + outputCopy.length + ", available: " + outputAvailable);
- }
- System.arraycopy(outputCopy, 0, output, outputOffset, outputCopy.length);
- return outputCopy.length;
- }
-
- @Override
- protected final int engineDoFinal(ByteBuffer input, ByteBuffer output)
- throws ShortBufferException, IllegalBlockSizeException, BadPaddingException {
- if (input == null) {
- throw new NullPointerException("input == null");
- }
- if (output == null) {
- throw new NullPointerException("output == null");
- }
-
- int inputSize = input.remaining();
- byte[] outputArray;
- if (input.hasArray()) {
- outputArray =
- engineDoFinal(
- input.array(), input.arrayOffset() + input.position(), inputSize);
- input.position(input.position() + inputSize);
- } else {
- byte[] inputArray = new byte[inputSize];
- input.get(inputArray);
- outputArray = engineDoFinal(inputArray, 0, inputSize);
- }
-
- int outputSize = (outputArray != null) ? outputArray.length : 0;
- if (outputSize > 0) {
- int outputBufferAvailable = output.remaining();
- try {
- output.put(outputArray);
- } catch (BufferOverflowException e) {
- throw new ShortBufferException(
- "Output buffer too small. Produced: " + outputSize + ", available: "
- + outputBufferAvailable);
- }
- }
- return outputSize;
- }
-
- @Override
- protected final byte[] engineWrap(Key key)
- throws IllegalBlockSizeException, InvalidKeyException {
- if (mKey == null) {
- throw new IllegalStateException("Not initilized");
- }
-
- if (!isEncrypting()) {
- throw new IllegalStateException(
- "Cipher must be initialized in Cipher.WRAP_MODE to wrap keys");
- }
-
- if (key == null) {
- throw new NullPointerException("key == null");
- }
- byte[] encoded = null;
- if (key instanceof SecretKey) {
- if ("RAW".equalsIgnoreCase(key.getFormat())) {
- encoded = key.getEncoded();
- }
- if (encoded == null) {
- try {
- SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(key.getAlgorithm());
- SecretKeySpec spec =
- (SecretKeySpec) keyFactory.getKeySpec(
- (SecretKey) key, SecretKeySpec.class);
- encoded = spec.getEncoded();
- } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
- throw new InvalidKeyException(
- "Failed to wrap key because it does not export its key material",
- e);
- }
- }
- } else if (key instanceof PrivateKey) {
- if ("PKCS8".equalsIgnoreCase(key.getFormat())) {
- encoded = key.getEncoded();
- }
- if (encoded == null) {
- try {
- KeyFactory keyFactory = KeyFactory.getInstance(key.getAlgorithm());
- PKCS8EncodedKeySpec spec =
- keyFactory.getKeySpec(key, PKCS8EncodedKeySpec.class);
- encoded = spec.getEncoded();
- } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
- throw new InvalidKeyException(
- "Failed to wrap key because it does not export its key material",
- e);
- }
- }
- } else if (key instanceof PublicKey) {
- if ("X.509".equalsIgnoreCase(key.getFormat())) {
- encoded = key.getEncoded();
- }
- if (encoded == null) {
- try {
- KeyFactory keyFactory = KeyFactory.getInstance(key.getAlgorithm());
- X509EncodedKeySpec spec =
- keyFactory.getKeySpec(key, X509EncodedKeySpec.class);
- encoded = spec.getEncoded();
- } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
- throw new InvalidKeyException(
- "Failed to wrap key because it does not export its key material",
- e);
- }
- }
- } else {
- throw new InvalidKeyException("Unsupported key type: " + key.getClass().getName());
- }
-
- if (encoded == null) {
- throw new InvalidKeyException(
- "Failed to wrap key because it does not export its key material");
- }
-
- try {
- return engineDoFinal(encoded, 0, encoded.length);
- } catch (BadPaddingException e) {
- throw (IllegalBlockSizeException) new IllegalBlockSizeException().initCause(e);
- }
- }
-
- @Override
- protected final Key engineUnwrap(byte[] wrappedKey, String wrappedKeyAlgorithm,
- int wrappedKeyType) throws InvalidKeyException, NoSuchAlgorithmException {
- if (mKey == null) {
- throw new IllegalStateException("Not initilized");
- }
-
- if (isEncrypting()) {
- throw new IllegalStateException(
- "Cipher must be initialized in Cipher.WRAP_MODE to wrap keys");
- }
-
- if (wrappedKey == null) {
- throw new NullPointerException("wrappedKey == null");
- }
-
- byte[] encoded;
- try {
- encoded = engineDoFinal(wrappedKey, 0, wrappedKey.length);
- } catch (IllegalBlockSizeException | BadPaddingException e) {
- throw new InvalidKeyException("Failed to unwrap key", e);
- }
-
- switch (wrappedKeyType) {
- case Cipher.SECRET_KEY:
- {
- return new SecretKeySpec(encoded, wrappedKeyAlgorithm);
- // break;
- }
- case Cipher.PRIVATE_KEY:
- {
- KeyFactory keyFactory = KeyFactory.getInstance(wrappedKeyAlgorithm);
- try {
- return keyFactory.generatePrivate(new PKCS8EncodedKeySpec(encoded));
- } catch (InvalidKeySpecException e) {
- throw new InvalidKeyException(
- "Failed to create private key from its PKCS#8 encoded form", e);
- }
- // break;
- }
- case Cipher.PUBLIC_KEY:
- {
- KeyFactory keyFactory = KeyFactory.getInstance(wrappedKeyAlgorithm);
- try {
- return keyFactory.generatePublic(new X509EncodedKeySpec(encoded));
- } catch (InvalidKeySpecException e) {
- throw new InvalidKeyException(
- "Failed to create public key from its X.509 encoded form", e);
- }
- // break;
- }
- default:
- throw new InvalidParameterException(
- "Unsupported wrappedKeyType: " + wrappedKeyType);
- }
- }
-
- @Override
- protected final void engineSetMode(String mode) throws NoSuchAlgorithmException {
- // This should never be invoked because all algorithms registered with the AndroidKeyStore
- // provide explicitly specify block mode.
- throw new UnsupportedOperationException();
- }
-
- @Override
- protected final void engineSetPadding(String arg0) throws NoSuchPaddingException {
- // This should never be invoked because all algorithms registered with the AndroidKeyStore
- // provide explicitly specify padding mode.
- throw new UnsupportedOperationException();
- }
-
- @Override
- protected final int engineGetKeySize(Key key) throws InvalidKeyException {
- throw new UnsupportedOperationException();
- }
-
- @CallSuper
- @Override
- public void finalize() throws Throwable {
- try {
- IBinder operationToken = mOperationToken;
- if (operationToken != null) {
- mKeyStore.abort(operationToken);
- }
- } finally {
- super.finalize();
- }
- }
-
- @Override
- public final long getOperationHandle() {
- return mOperationHandle;
- }
-
- protected final void setKey(@NonNull AndroidKeyStoreKey key) {
- mKey = key;
- }
-
- /**
- * Overrides the default purpose/type of the crypto operation.
- */
- protected final void setKeymasterPurposeOverride(int keymasterPurpose) {
- mKeymasterPurposeOverride = keymasterPurpose;
- }
-
- protected final int getKeymasterPurposeOverride() {
- return mKeymasterPurposeOverride;
- }
-
- /**
- * Returns {@code true} if this cipher is initialized for encryption, {@code false} if this
- * cipher is initialized for decryption.
- */
- protected final boolean isEncrypting() {
- return mEncrypting;
- }
-
- @NonNull
- protected final KeyStore getKeyStore() {
- return mKeyStore;
- }
-
- protected final long getConsumedInputSizeBytes() {
- if (mMainDataStreamer == null) {
- throw new IllegalStateException("Not initialized");
- }
- return mMainDataStreamer.getConsumedInputSizeBytes();
- }
-
- protected final long getProducedOutputSizeBytes() {
- if (mMainDataStreamer == null) {
- throw new IllegalStateException("Not initialized");
- }
- return mMainDataStreamer.getProducedOutputSizeBytes();
- }
-
- static String opmodeToString(int opmode) {
- switch (opmode) {
- case Cipher.ENCRYPT_MODE:
- return "ENCRYPT_MODE";
- case Cipher.DECRYPT_MODE:
- return "DECRYPT_MODE";
- case Cipher.WRAP_MODE:
- return "WRAP_MODE";
- case Cipher.UNWRAP_MODE:
- return "UNWRAP_MODE";
- default:
- return String.valueOf(opmode);
- }
- }
-
- // The methods below need to be implemented by subclasses.
-
- /**
- * Initializes this cipher with the provided key.
- *
- * @throws InvalidKeyException if the {@code key} is not suitable for this cipher in the
- * specified {@code opmode}.
- *
- * @see #setKey(AndroidKeyStoreKey)
- */
- protected abstract void initKey(int opmode, @Nullable Key key) throws InvalidKeyException;
-
- /**
- * Returns algorithm-specific parameters used by this cipher or {@code null} if no
- * algorithm-specific parameters are used.
- */
- @Nullable
- @Override
- protected abstract AlgorithmParameters engineGetParameters();
-
- /**
- * Invoked by {@code engineInit} to initialize algorithm-specific parameters when no additional
- * initialization parameters were provided.
- *
- * @throws InvalidKeyException if this cipher cannot be configured based purely on the provided
- * key and needs additional parameters to be provided to {@code Cipher.init}.
- */
- protected abstract void initAlgorithmSpecificParameters() throws InvalidKeyException;
-
- /**
- * Invoked by {@code engineInit} to initialize algorithm-specific parameters when additional
- * parameters were provided.
- *
- * @param params additional algorithm parameters or {@code null} if not specified.
- *
- * @throws InvalidAlgorithmParameterException if there is insufficient information to configure
- * this cipher or if the provided parameters are not suitable for this cipher.
- */
- protected abstract void initAlgorithmSpecificParameters(
- @Nullable AlgorithmParameterSpec params) throws InvalidAlgorithmParameterException;
-
- /**
- * Invoked by {@code engineInit} to initialize algorithm-specific parameters when additional
- * parameters were provided.
- *
- * @param params additional algorithm parameters or {@code null} if not specified.
- *
- * @throws InvalidAlgorithmParameterException if there is insufficient information to configure
- * this cipher or if the provided parameters are not suitable for this cipher.
- */
- protected abstract void initAlgorithmSpecificParameters(@Nullable AlgorithmParameters params)
- throws InvalidAlgorithmParameterException;
-
- /**
- * Returns the amount of additional entropy (in bytes) to be provided to the KeyStore's
- * {@code begin} operation. This amount of entropy is typically what's consumed to generate
- * random parameters, such as IV.
- *
- * <p>For decryption, the return value should be {@code 0} because decryption should not be
- * consuming any entropy. For encryption, the value combined with
- * {@link #getAdditionalEntropyAmountForFinish()} should match (or exceed) the amount of Shannon
- * entropy of the ciphertext produced by this cipher assuming the key, the plaintext, and all
- * explicitly provided parameters to {@code Cipher.init} are known. For example, for AES CBC
- * encryption with an explicitly provided IV the return value should be {@code 0}, whereas for
- * the case where IV is generated by the KeyStore's {@code begin} operation it should be
- * {@code 16}.
- */
- protected abstract int getAdditionalEntropyAmountForBegin();
-
- /**
- * Returns the amount of additional entropy (in bytes) to be provided to the KeyStore's
- * {@code finish} operation. This amount of entropy is typically what's consumed by encryption
- * padding scheme.
- *
- * <p>For decryption, the return value should be {@code 0} because decryption should not be
- * consuming any entropy. For encryption, the value combined with
- * {@link #getAdditionalEntropyAmountForBegin()} should match (or exceed) the amount of Shannon
- * entropy of the ciphertext produced by this cipher assuming the key, the plaintext, and all
- * explicitly provided parameters to {@code Cipher.init} are known. For example, for RSA with
- * OAEP the return value should be the size of the OAEP hash output. For RSA with PKCS#1 padding
- * the return value should be the size of the padding string or could be raised (for simplicity)
- * to the size of the modulus.
- */
- protected abstract int getAdditionalEntropyAmountForFinish();
-
- /**
- * Invoked to add algorithm-specific parameters for the KeyStore's {@code begin} operation.
- *
- * @param keymasterArgs keystore/keymaster arguments to be populated with algorithm-specific
- * parameters.
- */
- protected abstract void addAlgorithmSpecificParametersToBegin(
- @NonNull KeymasterArguments keymasterArgs);
-
- /**
- * Invoked to obtain algorithm-specific parameters from the result of the KeyStore's
- * {@code begin} operation.
- *
- * <p>Some parameters, such as IV, are not required to be provided to {@code Cipher.init}. Such
- * parameters, if not provided, must be generated by KeyStore and returned to the user of
- * {@code Cipher} and potentially reused after {@code doFinal}.
- *
- * @param keymasterArgs keystore/keymaster arguments returned by KeyStore {@code begin}
- * operation.
- */
- protected abstract void loadAlgorithmSpecificParametersFromBeginResult(
- @NonNull KeymasterArguments keymasterArgs);
-}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreECDSASignatureSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreECDSASignatureSpi.java
deleted file mode 100644
index 45f2110..0000000
--- a/keystore/java/android/security/keystore/AndroidKeyStoreECDSASignatureSpi.java
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.keystore;
-
-import android.annotation.NonNull;
-import android.os.IBinder;
-import android.security.KeyStore;
-import android.security.KeyStoreException;
-import android.security.keymaster.KeyCharacteristics;
-import android.security.keymaster.KeymasterArguments;
-import android.security.keymaster.KeymasterDefs;
-
-import libcore.util.EmptyArray;
-
-import java.io.ByteArrayOutputStream;
-import java.security.InvalidKeyException;
-import java.security.SignatureSpi;
-
-/**
- * Base class for {@link SignatureSpi} providing Android KeyStore backed ECDSA signatures.
- *
- * @hide
- */
-abstract class AndroidKeyStoreECDSASignatureSpi extends AndroidKeyStoreSignatureSpiBase {
-
- public final static class NONE extends AndroidKeyStoreECDSASignatureSpi {
- public NONE() {
- super(KeymasterDefs.KM_DIGEST_NONE);
- }
-
- @Override
- protected KeyStoreCryptoOperationStreamer createMainDataStreamer(KeyStore keyStore,
- IBinder operationToken) {
- return new TruncateToFieldSizeMessageStreamer(
- super.createMainDataStreamer(keyStore, operationToken),
- getGroupSizeBits());
- }
-
- /**
- * Streamer which buffers all input, then truncates it to field size, and then sends it into
- * KeyStore via the provided delegate streamer.
- */
- private static class TruncateToFieldSizeMessageStreamer
- implements KeyStoreCryptoOperationStreamer {
-
- private final KeyStoreCryptoOperationStreamer mDelegate;
- private final int mGroupSizeBits;
- private final ByteArrayOutputStream mInputBuffer = new ByteArrayOutputStream();
- private long mConsumedInputSizeBytes;
-
- private TruncateToFieldSizeMessageStreamer(
- KeyStoreCryptoOperationStreamer delegate,
- int groupSizeBits) {
- mDelegate = delegate;
- mGroupSizeBits = groupSizeBits;
- }
-
- @Override
- public byte[] update(byte[] input, int inputOffset, int inputLength)
- throws KeyStoreException {
- if (inputLength > 0) {
- mInputBuffer.write(input, inputOffset, inputLength);
- mConsumedInputSizeBytes += inputLength;
- }
- return EmptyArray.BYTE;
- }
-
- @Override
- public byte[] doFinal(byte[] input, int inputOffset, int inputLength, byte[] signature,
- byte[] additionalEntropy) throws KeyStoreException {
- if (inputLength > 0) {
- mConsumedInputSizeBytes += inputLength;
- mInputBuffer.write(input, inputOffset, inputLength);
- }
-
- byte[] bufferedInput = mInputBuffer.toByteArray();
- mInputBuffer.reset();
- // Truncate input at field size (bytes)
- return mDelegate.doFinal(bufferedInput,
- 0,
- Math.min(bufferedInput.length, ((mGroupSizeBits + 7) / 8)),
- signature, additionalEntropy);
- }
-
- @Override
- public long getConsumedInputSizeBytes() {
- return mConsumedInputSizeBytes;
- }
-
- @Override
- public long getProducedOutputSizeBytes() {
- return mDelegate.getProducedOutputSizeBytes();
- }
- }
- }
-
- public final static class SHA1 extends AndroidKeyStoreECDSASignatureSpi {
- public SHA1() {
- super(KeymasterDefs.KM_DIGEST_SHA1);
- }
- }
-
- public final static class SHA224 extends AndroidKeyStoreECDSASignatureSpi {
- public SHA224() {
- super(KeymasterDefs.KM_DIGEST_SHA_2_224);
- }
- }
-
- public final static class SHA256 extends AndroidKeyStoreECDSASignatureSpi {
- public SHA256() {
- super(KeymasterDefs.KM_DIGEST_SHA_2_256);
- }
- }
-
- public final static class SHA384 extends AndroidKeyStoreECDSASignatureSpi {
- public SHA384() {
- super(KeymasterDefs.KM_DIGEST_SHA_2_384);
- }
- }
-
- public final static class SHA512 extends AndroidKeyStoreECDSASignatureSpi {
- public SHA512() {
- super(KeymasterDefs.KM_DIGEST_SHA_2_512);
- }
- }
-
- private final int mKeymasterDigest;
-
- private int mGroupSizeBits = -1;
-
- AndroidKeyStoreECDSASignatureSpi(int keymasterDigest) {
- mKeymasterDigest = keymasterDigest;
- }
-
- @Override
- protected final void initKey(AndroidKeyStoreKey key) throws InvalidKeyException {
- if (!KeyProperties.KEY_ALGORITHM_EC.equalsIgnoreCase(key.getAlgorithm())) {
- throw new InvalidKeyException("Unsupported key algorithm: " + key.getAlgorithm()
- + ". Only" + KeyProperties.KEY_ALGORITHM_EC + " supported");
- }
-
- KeyCharacteristics keyCharacteristics = new KeyCharacteristics();
- int errorCode = getKeyStore().getKeyCharacteristics(
- key.getAlias(), null, null, key.getUid(), keyCharacteristics);
- if (errorCode != KeyStore.NO_ERROR) {
- throw getKeyStore().getInvalidKeyException(key.getAlias(), key.getUid(), errorCode);
- }
- long keySizeBits = keyCharacteristics.getUnsignedInt(KeymasterDefs.KM_TAG_KEY_SIZE, -1);
- if (keySizeBits == -1) {
- throw new InvalidKeyException("Size of key not known");
- } else if (keySizeBits > Integer.MAX_VALUE) {
- throw new InvalidKeyException("Key too large: " + keySizeBits + " bits");
- }
- mGroupSizeBits = (int) keySizeBits;
-
- super.initKey(key);
- }
-
- @Override
- protected final void resetAll() {
- mGroupSizeBits = -1;
- super.resetAll();
- }
-
- @Override
- protected final void resetWhilePreservingInitState() {
- super.resetWhilePreservingInitState();
- }
-
- @Override
- protected final void addAlgorithmSpecificParametersToBegin(
- @NonNull KeymasterArguments keymasterArgs) {
- keymasterArgs.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_EC);
- keymasterArgs.addEnum(KeymasterDefs.KM_TAG_DIGEST, mKeymasterDigest);
- }
-
- @Override
- protected final int getAdditionalEntropyAmountForSign() {
- return (mGroupSizeBits + 7) / 8;
- }
-
- protected final int getGroupSizeBits() {
- if (mGroupSizeBits == -1) {
- throw new IllegalStateException("Not initialized");
- }
- return mGroupSizeBits;
- }
-}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreECPrivateKey.java b/keystore/java/android/security/keystore/AndroidKeyStoreECPrivateKey.java
deleted file mode 100644
index aa7bdff..0000000
--- a/keystore/java/android/security/keystore/AndroidKeyStoreECPrivateKey.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.keystore;
-
-import java.security.PrivateKey;
-import java.security.interfaces.ECKey;
-import java.security.spec.ECParameterSpec;
-
-/**
- * EC private key (instance of {@link PrivateKey} and {@link ECKey}) backed by keystore.
- *
- * @hide
- */
-public class AndroidKeyStoreECPrivateKey extends AndroidKeyStorePrivateKey implements ECKey {
- private final ECParameterSpec mParams;
-
- public AndroidKeyStoreECPrivateKey(String alias, int uid, ECParameterSpec params) {
- super(alias, uid, KeyProperties.KEY_ALGORITHM_EC);
- mParams = params;
- }
-
- @Override
- public ECParameterSpec getParams() {
- return mParams;
- }
-}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreECPublicKey.java b/keystore/java/android/security/keystore/AndroidKeyStoreECPublicKey.java
deleted file mode 100644
index 2efaeb6..0000000
--- a/keystore/java/android/security/keystore/AndroidKeyStoreECPublicKey.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.keystore;
-
-import java.security.interfaces.ECPublicKey;
-import java.security.spec.ECParameterSpec;
-import java.security.spec.ECPoint;
-
-/**
- * {@link ECPublicKey} backed by keystore.
- *
- * @hide
- */
-public class AndroidKeyStoreECPublicKey extends AndroidKeyStorePublicKey implements ECPublicKey {
-
- private final ECParameterSpec mParams;
- private final ECPoint mW;
-
- public AndroidKeyStoreECPublicKey(String alias, int uid, byte[] x509EncodedForm, ECParameterSpec params,
- ECPoint w) {
- super(alias, uid, KeyProperties.KEY_ALGORITHM_EC, x509EncodedForm);
- mParams = params;
- mW = w;
- }
-
- public AndroidKeyStoreECPublicKey(String alias, int uid, ECPublicKey info) {
- this(alias, uid, info.getEncoded(), info.getParams(), info.getW());
- if (!"X.509".equalsIgnoreCase(info.getFormat())) {
- throw new IllegalArgumentException(
- "Unsupported key export format: " + info.getFormat());
- }
- }
-
- @Override
- public ECParameterSpec getParams() {
- return mParams;
- }
-
- @Override
- public ECPoint getW() {
- return mW;
- }
-}
\ No newline at end of file
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreHmacSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreHmacSpi.java
deleted file mode 100644
index 2e8ac32..0000000
--- a/keystore/java/android/security/keystore/AndroidKeyStoreHmacSpi.java
+++ /dev/null
@@ -1,265 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.keystore;
-
-import android.os.IBinder;
-import android.security.KeyStore;
-import android.security.KeyStoreException;
-import android.security.keymaster.KeymasterArguments;
-import android.security.keymaster.KeymasterDefs;
-import android.security.keymaster.OperationResult;
-
-import java.security.InvalidAlgorithmParameterException;
-import java.security.InvalidKeyException;
-import java.security.Key;
-import java.security.ProviderException;
-import java.security.spec.AlgorithmParameterSpec;
-
-import javax.crypto.MacSpi;
-
-/**
- * {@link MacSpi} which provides HMAC implementations backed by Android KeyStore.
- *
- * @hide
- */
-public abstract class AndroidKeyStoreHmacSpi extends MacSpi implements KeyStoreCryptoOperation {
-
- public static class HmacSHA1 extends AndroidKeyStoreHmacSpi {
- public HmacSHA1() {
- super(KeymasterDefs.KM_DIGEST_SHA1);
- }
- }
-
- public static class HmacSHA224 extends AndroidKeyStoreHmacSpi {
- public HmacSHA224() {
- super(KeymasterDefs.KM_DIGEST_SHA_2_224);
- }
- }
-
- public static class HmacSHA256 extends AndroidKeyStoreHmacSpi {
- public HmacSHA256() {
- super(KeymasterDefs.KM_DIGEST_SHA_2_256);
- }
- }
-
- public static class HmacSHA384 extends AndroidKeyStoreHmacSpi {
- public HmacSHA384() {
- super(KeymasterDefs.KM_DIGEST_SHA_2_384);
- }
- }
-
- public static class HmacSHA512 extends AndroidKeyStoreHmacSpi {
- public HmacSHA512() {
- super(KeymasterDefs.KM_DIGEST_SHA_2_512);
- }
- }
-
- private final KeyStore mKeyStore = KeyStore.getInstance();
- private final int mKeymasterDigest;
- private final int mMacSizeBits;
-
- // Fields below are populated by engineInit and should be preserved after engineDoFinal.
- private AndroidKeyStoreSecretKey mKey;
-
- // Fields below are reset when engineDoFinal succeeds.
- private KeyStoreCryptoOperationChunkedStreamer mChunkedStreamer;
- private IBinder mOperationToken;
- private long mOperationHandle;
-
- protected AndroidKeyStoreHmacSpi(int keymasterDigest) {
- mKeymasterDigest = keymasterDigest;
- mMacSizeBits = KeymasterUtils.getDigestOutputSizeBits(keymasterDigest);
- }
-
- @Override
- protected int engineGetMacLength() {
- return (mMacSizeBits + 7) / 8;
- }
-
- @Override
- protected void engineInit(Key key, AlgorithmParameterSpec params) throws InvalidKeyException,
- InvalidAlgorithmParameterException {
- resetAll();
-
- boolean success = false;
- try {
- init(key, params);
- ensureKeystoreOperationInitialized();
- success = true;
- } finally {
- if (!success) {
- resetAll();
- }
- }
- }
-
- private void init(Key key, AlgorithmParameterSpec params) throws InvalidKeyException,
- InvalidAlgorithmParameterException {
- if (key == null) {
- throw new InvalidKeyException("key == null");
- } else if (!(key instanceof AndroidKeyStoreSecretKey)) {
- throw new InvalidKeyException(
- "Only Android KeyStore secret keys supported. Key: " + key);
- }
- mKey = (AndroidKeyStoreSecretKey) key;
-
- if (params != null) {
- throw new InvalidAlgorithmParameterException(
- "Unsupported algorithm parameters: " + params);
- }
-
- }
-
- private void resetAll() {
- mKey = null;
- IBinder operationToken = mOperationToken;
- if (operationToken != null) {
- mKeyStore.abort(operationToken);
- }
- mOperationToken = null;
- mOperationHandle = 0;
- mChunkedStreamer = null;
- }
-
- private void resetWhilePreservingInitState() {
- IBinder operationToken = mOperationToken;
- if (operationToken != null) {
- mKeyStore.abort(operationToken);
- }
- mOperationToken = null;
- mOperationHandle = 0;
- mChunkedStreamer = null;
- }
-
- @Override
- protected void engineReset() {
- resetWhilePreservingInitState();
- }
-
- private void ensureKeystoreOperationInitialized() throws InvalidKeyException {
- if (mChunkedStreamer != null) {
- return;
- }
- if (mKey == null) {
- throw new IllegalStateException("Not initialized");
- }
-
- KeymasterArguments keymasterArgs = new KeymasterArguments();
- keymasterArgs.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_HMAC);
- keymasterArgs.addEnum(KeymasterDefs.KM_TAG_DIGEST, mKeymasterDigest);
- keymasterArgs.addUnsignedInt(KeymasterDefs.KM_TAG_MAC_LENGTH, mMacSizeBits);
-
- OperationResult opResult = mKeyStore.begin(
- mKey.getAlias(),
- KeymasterDefs.KM_PURPOSE_SIGN,
- true,
- keymasterArgs,
- null, // no additional entropy needed for HMAC because it's deterministic
- mKey.getUid());
-
- if (opResult == null) {
- throw new KeyStoreConnectException();
- }
-
- // Store operation token and handle regardless of the error code returned by KeyStore to
- // ensure that the operation gets aborted immediately if the code below throws an exception.
- mOperationToken = opResult.token;
- mOperationHandle = opResult.operationHandle;
-
- // If necessary, throw an exception due to KeyStore operation having failed.
- InvalidKeyException e = KeyStoreCryptoOperationUtils.getInvalidKeyExceptionForInit(
- mKeyStore, mKey, opResult.resultCode);
- if (e != null) {
- throw e;
- }
-
- if (mOperationToken == null) {
- throw new ProviderException("Keystore returned null operation token");
- }
- if (mOperationHandle == 0) {
- throw new ProviderException("Keystore returned invalid operation handle");
- }
-
- mChunkedStreamer = new KeyStoreCryptoOperationChunkedStreamer(
- new KeyStoreCryptoOperationChunkedStreamer.MainDataStream(
- mKeyStore, mOperationToken));
- }
-
- @Override
- protected void engineUpdate(byte input) {
- engineUpdate(new byte[] {input}, 0, 1);
- }
-
- @Override
- protected void engineUpdate(byte[] input, int offset, int len) {
- try {
- ensureKeystoreOperationInitialized();
- } catch (InvalidKeyException e) {
- throw new ProviderException("Failed to reinitialize MAC", e);
- }
-
- byte[] output;
- try {
- output = mChunkedStreamer.update(input, offset, len);
- } catch (KeyStoreException e) {
- throw new ProviderException("Keystore operation failed", e);
- }
- if ((output != null) && (output.length != 0)) {
- throw new ProviderException("Update operation unexpectedly produced output");
- }
- }
-
- @Override
- protected byte[] engineDoFinal() {
- try {
- ensureKeystoreOperationInitialized();
- } catch (InvalidKeyException e) {
- throw new ProviderException("Failed to reinitialize MAC", e);
- }
-
- byte[] result;
- try {
- result = mChunkedStreamer.doFinal(
- null, 0, 0,
- null, // no signature provided -- this invocation will generate one
- null // no additional entropy needed -- HMAC is deterministic
- );
- } catch (KeyStoreException e) {
- throw new ProviderException("Keystore operation failed", e);
- }
-
- resetWhilePreservingInitState();
- return result;
- }
-
- @Override
- public void finalize() throws Throwable {
- try {
- IBinder operationToken = mOperationToken;
- if (operationToken != null) {
- mKeyStore.abort(operationToken);
- }
- } finally {
- super.finalize();
- }
- }
-
- @Override
- public long getOperationHandle() {
- return mOperationHandle;
- }
-}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKey.java b/keystore/java/android/security/keystore/AndroidKeyStoreKey.java
deleted file mode 100644
index e8e6310..0000000
--- a/keystore/java/android/security/keystore/AndroidKeyStoreKey.java
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.keystore;
-
-import java.security.Key;
-
-/**
- * {@link Key} backed by Android Keystore.
- *
- * @hide
- */
-public class AndroidKeyStoreKey implements Key {
- private final String mAlias;
- private final int mUid;
- private final String mAlgorithm;
-
- public AndroidKeyStoreKey(String alias, int uid, String algorithm) {
- mAlias = alias;
- mUid = uid;
- mAlgorithm = algorithm;
- }
-
- String getAlias() {
- return mAlias;
- }
-
- int getUid() {
- return mUid;
- }
-
- @Override
- public String getAlgorithm() {
- return mAlgorithm;
- }
-
- @Override
- public String getFormat() {
- // This key does not export its key material
- return null;
- }
-
- @Override
- public byte[] getEncoded() {
- // This key does not export its key material
- return null;
- }
-
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result + ((mAlgorithm == null) ? 0 : mAlgorithm.hashCode());
- result = prime * result + ((mAlias == null) ? 0 : mAlias.hashCode());
- result = prime * result + mUid;
- return result;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
- if (obj == null) {
- return false;
- }
- if (getClass() != obj.getClass()) {
- return false;
- }
- AndroidKeyStoreKey other = (AndroidKeyStoreKey) obj;
- if (mAlgorithm == null) {
- if (other.mAlgorithm != null) {
- return false;
- }
- } else if (!mAlgorithm.equals(other.mAlgorithm)) {
- return false;
- }
- if (mAlias == null) {
- if (other.mAlias != null) {
- return false;
- }
- } else if (!mAlias.equals(other.mAlias)) {
- return false;
- }
- if (mUid != other.mUid) {
- return false;
- }
- return true;
- }
-}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyFactorySpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyFactorySpi.java
deleted file mode 100644
index 303b0f2..0000000
--- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyFactorySpi.java
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.keystore;
-
-import android.security.Credentials;
-import android.security.KeyStore;
-
-import java.security.InvalidKeyException;
-import java.security.Key;
-import java.security.KeyFactorySpi;
-import java.security.PrivateKey;
-import java.security.PublicKey;
-import java.security.spec.ECPublicKeySpec;
-import java.security.spec.InvalidKeySpecException;
-import java.security.spec.KeySpec;
-import java.security.spec.PKCS8EncodedKeySpec;
-import java.security.spec.RSAPublicKeySpec;
-import java.security.spec.X509EncodedKeySpec;
-
-/**
- * {@link KeyFactorySpi} backed by Android KeyStore.
- *
- * @hide
- */
-public class AndroidKeyStoreKeyFactorySpi extends KeyFactorySpi {
-
- private final KeyStore mKeyStore = KeyStore.getInstance();
-
- @Override
- protected <T extends KeySpec> T engineGetKeySpec(Key key, Class<T> keySpecClass)
- throws InvalidKeySpecException {
- if (key == null) {
- throw new InvalidKeySpecException("key == null");
- } else if ((!(key instanceof AndroidKeyStorePrivateKey))
- && (!(key instanceof AndroidKeyStorePublicKey))) {
- throw new InvalidKeySpecException(
- "Unsupported key type: " + key.getClass().getName()
- + ". This KeyFactory supports only Android Keystore asymmetric keys");
- }
-
- // key is an Android Keystore private or public key
-
- if (keySpecClass == null) {
- throw new InvalidKeySpecException("keySpecClass == null");
- } else if (KeyInfo.class.equals(keySpecClass)) {
- if (!(key instanceof AndroidKeyStorePrivateKey)) {
- throw new InvalidKeySpecException(
- "Unsupported key type: " + key.getClass().getName()
- + ". KeyInfo can be obtained only for Android Keystore private keys");
- }
- AndroidKeyStorePrivateKey keystorePrivateKey = (AndroidKeyStorePrivateKey) key;
- String keyAliasInKeystore = keystorePrivateKey.getAlias();
- String entryAlias;
- if (keyAliasInKeystore.startsWith(Credentials.USER_PRIVATE_KEY)) {
- entryAlias = keyAliasInKeystore.substring(Credentials.USER_PRIVATE_KEY.length());
- } else {
- throw new InvalidKeySpecException("Invalid key alias: " + keyAliasInKeystore);
- }
- @SuppressWarnings("unchecked")
- T result = (T) AndroidKeyStoreSecretKeyFactorySpi.getKeyInfo(
- mKeyStore, entryAlias, keyAliasInKeystore, keystorePrivateKey.getUid());
- return result;
- } else if (X509EncodedKeySpec.class.equals(keySpecClass)) {
- if (!(key instanceof AndroidKeyStorePublicKey)) {
- throw new InvalidKeySpecException(
- "Unsupported key type: " + key.getClass().getName()
- + ". X509EncodedKeySpec can be obtained only for Android Keystore public"
- + " keys");
- }
- @SuppressWarnings("unchecked")
- T result = (T) new X509EncodedKeySpec(((AndroidKeyStorePublicKey) key).getEncoded());
- return result;
- } else if (PKCS8EncodedKeySpec.class.equals(keySpecClass)) {
- if (key instanceof AndroidKeyStorePrivateKey) {
- throw new InvalidKeySpecException(
- "Key material export of Android Keystore private keys is not supported");
- } else {
- throw new InvalidKeySpecException(
- "Cannot export key material of public key in PKCS#8 format."
- + " Only X.509 format (X509EncodedKeySpec) supported for public keys.");
- }
- } else if (RSAPublicKeySpec.class.equals(keySpecClass)) {
- if (key instanceof AndroidKeyStoreRSAPublicKey) {
- AndroidKeyStoreRSAPublicKey rsaKey = (AndroidKeyStoreRSAPublicKey) key;
- @SuppressWarnings("unchecked")
- T result =
- (T) new RSAPublicKeySpec(rsaKey.getModulus(), rsaKey.getPublicExponent());
- return result;
- } else {
- throw new InvalidKeySpecException(
- "Obtaining RSAPublicKeySpec not supported for " + key.getAlgorithm() + " "
- + ((key instanceof AndroidKeyStorePrivateKey) ? "private" : "public")
- + " key");
- }
- } else if (ECPublicKeySpec.class.equals(keySpecClass)) {
- if (key instanceof AndroidKeyStoreECPublicKey) {
- AndroidKeyStoreECPublicKey ecKey = (AndroidKeyStoreECPublicKey) key;
- @SuppressWarnings("unchecked")
- T result = (T) new ECPublicKeySpec(ecKey.getW(), ecKey.getParams());
- return result;
- } else {
- throw new InvalidKeySpecException(
- "Obtaining ECPublicKeySpec not supported for " + key.getAlgorithm() + " "
- + ((key instanceof AndroidKeyStorePrivateKey) ? "private" : "public")
- + " key");
- }
- } else {
- throw new InvalidKeySpecException("Unsupported key spec: " + keySpecClass.getName());
- }
- }
-
- @Override
- protected PrivateKey engineGeneratePrivate(KeySpec spec) throws InvalidKeySpecException {
- throw new InvalidKeySpecException(
- "To generate a key pair in Android Keystore, use KeyPairGenerator initialized with"
- + " " + KeyGenParameterSpec.class.getName());
- }
-
- @Override
- protected PublicKey engineGeneratePublic(KeySpec spec) throws InvalidKeySpecException {
- throw new InvalidKeySpecException(
- "To generate a key pair in Android Keystore, use KeyPairGenerator initialized with"
- + " " + KeyGenParameterSpec.class.getName());
- }
-
- @Override
- protected Key engineTranslateKey(Key key) throws InvalidKeyException {
- if (key == null) {
- throw new InvalidKeyException("key == null");
- } else if ((!(key instanceof AndroidKeyStorePrivateKey))
- && (!(key instanceof AndroidKeyStorePublicKey))) {
- throw new InvalidKeyException(
- "To import a key into Android Keystore, use KeyStore.setEntry");
- }
- return key;
- }
-}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
deleted file mode 100644
index fedde42..0000000
--- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
+++ /dev/null
@@ -1,352 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.keystore;
-
-import android.security.Credentials;
-import android.security.KeyStore;
-import android.security.keymaster.KeyCharacteristics;
-import android.security.keymaster.KeymasterArguments;
-import android.security.keymaster.KeymasterDefs;
-import android.security.keystore.KeyGenParameterSpec;
-import android.security.keystore.KeyProperties;
-
-import libcore.util.EmptyArray;
-
-import java.security.InvalidAlgorithmParameterException;
-import java.security.ProviderException;
-import java.security.SecureRandom;
-import java.security.spec.AlgorithmParameterSpec;
-import java.util.Arrays;
-
-import javax.crypto.KeyGeneratorSpi;
-import javax.crypto.SecretKey;
-
-/**
- * {@link KeyGeneratorSpi} backed by Android KeyStore.
- *
- * @hide
- */
-public abstract class AndroidKeyStoreKeyGeneratorSpi extends KeyGeneratorSpi {
-
- public static class AES extends AndroidKeyStoreKeyGeneratorSpi {
- public AES() {
- super(KeymasterDefs.KM_ALGORITHM_AES, 128);
- }
-
- @Override
- protected void engineInit(AlgorithmParameterSpec params, SecureRandom random)
- throws InvalidAlgorithmParameterException {
- super.engineInit(params, random);
- if ((mKeySizeBits != 128) && (mKeySizeBits != 192) && (mKeySizeBits != 256)) {
- throw new InvalidAlgorithmParameterException(
- "Unsupported key size: " + mKeySizeBits
- + ". Supported: 128, 192, 256.");
- }
- }
- }
-
- public static class DESede extends AndroidKeyStoreKeyGeneratorSpi {
- public DESede() {
- super(KeymasterDefs.KM_ALGORITHM_3DES, 168);
- }
- }
-
- protected static abstract class HmacBase extends AndroidKeyStoreKeyGeneratorSpi {
- protected HmacBase(int keymasterDigest) {
- super(KeymasterDefs.KM_ALGORITHM_HMAC,
- keymasterDigest,
- KeymasterUtils.getDigestOutputSizeBits(keymasterDigest));
- }
- }
-
- public static class HmacSHA1 extends HmacBase {
- public HmacSHA1() {
- super(KeymasterDefs.KM_DIGEST_SHA1);
- }
- }
-
- public static class HmacSHA224 extends HmacBase {
- public HmacSHA224() {
- super(KeymasterDefs.KM_DIGEST_SHA_2_224);
- }
- }
-
- public static class HmacSHA256 extends HmacBase {
- public HmacSHA256() {
- super(KeymasterDefs.KM_DIGEST_SHA_2_256);
- }
- }
-
- public static class HmacSHA384 extends HmacBase {
- public HmacSHA384() {
- super(KeymasterDefs.KM_DIGEST_SHA_2_384);
- }
- }
-
- public static class HmacSHA512 extends HmacBase {
- public HmacSHA512() {
- super(KeymasterDefs.KM_DIGEST_SHA_2_512);
- }
- }
-
- private final KeyStore mKeyStore = KeyStore.getInstance();
- private final int mKeymasterAlgorithm;
- private final int mKeymasterDigest;
- private final int mDefaultKeySizeBits;
-
- private KeyGenParameterSpec mSpec;
- private SecureRandom mRng;
-
- protected int mKeySizeBits;
- private int[] mKeymasterPurposes;
- private int[] mKeymasterBlockModes;
- private int[] mKeymasterPaddings;
- private int[] mKeymasterDigests;
-
- protected AndroidKeyStoreKeyGeneratorSpi(
- int keymasterAlgorithm,
- int defaultKeySizeBits) {
- this(keymasterAlgorithm, -1, defaultKeySizeBits);
- }
-
- protected AndroidKeyStoreKeyGeneratorSpi(
- int keymasterAlgorithm,
- int keymasterDigest,
- int defaultKeySizeBits) {
- mKeymasterAlgorithm = keymasterAlgorithm;
- mKeymasterDigest = keymasterDigest;
- mDefaultKeySizeBits = defaultKeySizeBits;
- if (mDefaultKeySizeBits <= 0) {
- throw new IllegalArgumentException("Default key size must be positive");
- }
-
- if ((mKeymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_HMAC) && (mKeymasterDigest == -1)) {
- throw new IllegalArgumentException(
- "Digest algorithm must be specified for HMAC key");
- }
- }
-
- @Override
- protected void engineInit(SecureRandom random) {
- throw new UnsupportedOperationException("Cannot initialize without a "
- + KeyGenParameterSpec.class.getName() + " parameter");
- }
-
- @Override
- protected void engineInit(int keySize, SecureRandom random) {
- throw new UnsupportedOperationException("Cannot initialize without a "
- + KeyGenParameterSpec.class.getName() + " parameter");
- }
-
- @Override
- protected void engineInit(AlgorithmParameterSpec params, SecureRandom random)
- throws InvalidAlgorithmParameterException {
- resetAll();
-
- boolean success = false;
- try {
- if ((params == null) || (!(params instanceof KeyGenParameterSpec))) {
- throw new InvalidAlgorithmParameterException("Cannot initialize without a "
- + KeyGenParameterSpec.class.getName() + " parameter");
- }
- KeyGenParameterSpec spec = (KeyGenParameterSpec) params;
- if (spec.getKeystoreAlias() == null) {
- throw new InvalidAlgorithmParameterException("KeyStore entry alias not provided");
- }
-
- mRng = random;
- mSpec = spec;
-
- mKeySizeBits = (spec.getKeySize() != -1) ? spec.getKeySize() : mDefaultKeySizeBits;
- if (mKeySizeBits <= 0) {
- throw new InvalidAlgorithmParameterException(
- "Key size must be positive: " + mKeySizeBits);
- } else if ((mKeySizeBits % 8) != 0) {
- throw new InvalidAlgorithmParameterException(
- "Key size must be a multiple of 8: " + mKeySizeBits);
- }
-
- try {
- mKeymasterPurposes = KeyProperties.Purpose.allToKeymaster(spec.getPurposes());
- mKeymasterPaddings = KeyProperties.EncryptionPadding.allToKeymaster(
- spec.getEncryptionPaddings());
- if (spec.getSignaturePaddings().length > 0) {
- throw new InvalidAlgorithmParameterException(
- "Signature paddings not supported for symmetric key algorithms");
- }
- mKeymasterBlockModes = KeyProperties.BlockMode.allToKeymaster(spec.getBlockModes());
- if (((spec.getPurposes() & KeyProperties.PURPOSE_ENCRYPT) != 0)
- && (spec.isRandomizedEncryptionRequired())) {
- for (int keymasterBlockMode : mKeymasterBlockModes) {
- if (!KeymasterUtils.isKeymasterBlockModeIndCpaCompatibleWithSymmetricCrypto(
- keymasterBlockMode)) {
- throw new InvalidAlgorithmParameterException(
- "Randomized encryption (IND-CPA) required but may be violated"
- + " by block mode: "
- + KeyProperties.BlockMode.fromKeymaster(keymasterBlockMode)
- + ". See " + KeyGenParameterSpec.class.getName()
- + " documentation.");
- }
- }
- }
- if (mKeymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_3DES) {
- if (mKeySizeBits != 168) {
- throw new InvalidAlgorithmParameterException(
- "3DES key size must be 168 bits.");
- }
- }
- if (mKeymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_HMAC) {
- if (mKeySizeBits < 64 || mKeySizeBits > 512) {
- throw new InvalidAlgorithmParameterException(
- "HMAC key sizes must be within 64-512 bits, inclusive.");
- }
-
- // JCA HMAC key algorithm implies a digest (e.g., HmacSHA256 key algorithm
- // implies SHA-256 digest). Because keymaster HMAC key is authorized only for
- // one digest, we don't let algorithm parameter spec override the digest implied
- // by the key. If the spec specifies digests at all, it must specify only one
- // digest, the only implied by key algorithm.
- mKeymasterDigests = new int[] {mKeymasterDigest};
- if (spec.isDigestsSpecified()) {
- // Digest(s) explicitly specified in the spec. Check that the list
- // consists of exactly one digest, the one implied by key algorithm.
- int[] keymasterDigestsFromSpec =
- KeyProperties.Digest.allToKeymaster(spec.getDigests());
- if ((keymasterDigestsFromSpec.length != 1)
- || (keymasterDigestsFromSpec[0] != mKeymasterDigest)) {
- throw new InvalidAlgorithmParameterException(
- "Unsupported digests specification: "
- + Arrays.asList(spec.getDigests()) + ". Only "
- + KeyProperties.Digest.fromKeymaster(mKeymasterDigest)
- + " supported for this HMAC key algorithm");
- }
- }
- } else {
- // Key algorithm does not imply a digest.
- if (spec.isDigestsSpecified()) {
- mKeymasterDigests = KeyProperties.Digest.allToKeymaster(spec.getDigests());
- } else {
- mKeymasterDigests = EmptyArray.INT;
- }
- }
-
- // Check that user authentication related parameters are acceptable. This method
- // will throw an IllegalStateException if there are issues (e.g., secure lock screen
- // not set up).
- KeymasterUtils.addUserAuthArgs(new KeymasterArguments(), spec);
- } catch (IllegalStateException | IllegalArgumentException e) {
- throw new InvalidAlgorithmParameterException(e);
- }
-
- success = true;
- } finally {
- if (!success) {
- resetAll();
- }
- }
- }
-
- private void resetAll() {
- mSpec = null;
- mRng = null;
- mKeySizeBits = -1;
- mKeymasterPurposes = null;
- mKeymasterPaddings = null;
- mKeymasterBlockModes = null;
- }
-
- @Override
- protected SecretKey engineGenerateKey() {
- KeyGenParameterSpec spec = mSpec;
- if (spec == null) {
- throw new IllegalStateException("Not initialized");
- }
-
- KeymasterArguments args = new KeymasterArguments();
- args.addUnsignedInt(KeymasterDefs.KM_TAG_KEY_SIZE, mKeySizeBits);
- args.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, mKeymasterAlgorithm);
- args.addEnums(KeymasterDefs.KM_TAG_PURPOSE, mKeymasterPurposes);
- args.addEnums(KeymasterDefs.KM_TAG_BLOCK_MODE, mKeymasterBlockModes);
- args.addEnums(KeymasterDefs.KM_TAG_PADDING, mKeymasterPaddings);
- args.addEnums(KeymasterDefs.KM_TAG_DIGEST, mKeymasterDigests);
- KeymasterUtils.addUserAuthArgs(args, spec);
- KeymasterUtils.addMinMacLengthAuthorizationIfNecessary(
- args,
- mKeymasterAlgorithm,
- mKeymasterBlockModes,
- mKeymasterDigests);
- args.addDateIfNotNull(KeymasterDefs.KM_TAG_ACTIVE_DATETIME, spec.getKeyValidityStart());
- args.addDateIfNotNull(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME,
- spec.getKeyValidityForOriginationEnd());
- args.addDateIfNotNull(KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME,
- spec.getKeyValidityForConsumptionEnd());
-
- if (((spec.getPurposes() & KeyProperties.PURPOSE_ENCRYPT) != 0)
- && (!spec.isRandomizedEncryptionRequired())) {
- // Permit caller-provided IV when encrypting with this key
- args.addBoolean(KeymasterDefs.KM_TAG_CALLER_NONCE);
- }
-
- byte[] additionalEntropy =
- KeyStoreCryptoOperationUtils.getRandomBytesToMixIntoKeystoreRng(
- mRng, (mKeySizeBits + 7) / 8);
- int flags = 0;
- if (spec.isStrongBoxBacked()) {
- flags |= KeyStore.FLAG_STRONGBOX;
- }
- if (spec.isCriticalToDeviceEncryption()) {
- flags |= KeyStore.FLAG_CRITICAL_TO_DEVICE_ENCRYPTION;
- }
- String keyAliasInKeystore = Credentials.USER_PRIVATE_KEY + spec.getKeystoreAlias();
- KeyCharacteristics resultingKeyCharacteristics = new KeyCharacteristics();
- boolean success = false;
- try {
- Credentials.deleteAllTypesForAlias(mKeyStore, spec.getKeystoreAlias(), spec.getUid());
- int errorCode = mKeyStore.generateKey(
- keyAliasInKeystore,
- args,
- additionalEntropy,
- spec.getUid(),
- flags,
- resultingKeyCharacteristics);
- if (errorCode != KeyStore.NO_ERROR) {
- if (errorCode == KeyStore.HARDWARE_TYPE_UNAVAILABLE) {
- throw new StrongBoxUnavailableException("Failed to generate key");
- } else {
- throw new ProviderException(
- "Keystore operation failed", KeyStore.getKeyStoreException(errorCode));
- }
- }
- @KeyProperties.KeyAlgorithmEnum String keyAlgorithmJCA;
- try {
- keyAlgorithmJCA = KeyProperties.KeyAlgorithm.fromKeymasterSecretKeyAlgorithm(
- mKeymasterAlgorithm, mKeymasterDigest);
- } catch (IllegalArgumentException e) {
- throw new ProviderException("Failed to obtain JCA secret key algorithm name", e);
- }
- SecretKey result = new AndroidKeyStoreSecretKey(
- keyAliasInKeystore, spec.getUid(), keyAlgorithmJCA);
- success = true;
- return result;
- } finally {
- if (!success) {
- Credentials.deleteAllTypesForAlias(
- mKeyStore, spec.getKeystoreAlias(), spec.getUid());
- }
- }
- }
-}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
deleted file mode 100644
index 988838b..0000000
--- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
+++ /dev/null
@@ -1,986 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.keystore;
-
-import android.annotation.Nullable;
-import android.content.Context;
-import android.os.Build;
-import android.security.Credentials;
-import android.security.KeyPairGeneratorSpec;
-import android.security.KeyStore;
-import android.security.keymaster.KeyCharacteristics;
-import android.security.keymaster.KeymasterArguments;
-import android.security.keymaster.KeymasterCertificateChain;
-import android.security.keymaster.KeymasterDefs;
-import android.telephony.TelephonyManager;
-import android.util.ArraySet;
-
-import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
-import com.android.internal.org.bouncycastle.asn1.ASN1InputStream;
-import com.android.internal.org.bouncycastle.asn1.ASN1Integer;
-import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
-import com.android.internal.org.bouncycastle.asn1.DERBitString;
-import com.android.internal.org.bouncycastle.asn1.DERNull;
-import com.android.internal.org.bouncycastle.asn1.DERSequence;
-import com.android.internal.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
-import com.android.internal.org.bouncycastle.asn1.x509.AlgorithmIdentifier;
-import com.android.internal.org.bouncycastle.asn1.x509.Certificate;
-import com.android.internal.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
-import com.android.internal.org.bouncycastle.asn1.x509.TBSCertificate;
-import com.android.internal.org.bouncycastle.asn1.x509.Time;
-import com.android.internal.org.bouncycastle.asn1.x509.V3TBSCertificateGenerator;
-import com.android.internal.org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
-import com.android.internal.org.bouncycastle.jce.X509Principal;
-import com.android.internal.org.bouncycastle.jce.provider.X509CertificateObject;
-import com.android.internal.org.bouncycastle.x509.X509V3CertificateGenerator;
-
-import libcore.util.EmptyArray;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.math.BigInteger;
-import java.nio.charset.StandardCharsets;
-import java.security.InvalidAlgorithmParameterException;
-import java.security.KeyPair;
-import java.security.KeyPairGenerator;
-import java.security.KeyPairGeneratorSpi;
-import java.security.PrivateKey;
-import java.security.ProviderException;
-import java.security.PublicKey;
-import java.security.SecureRandom;
-import java.security.UnrecoverableKeyException;
-import java.security.cert.CertificateEncodingException;
-import java.security.cert.CertificateParsingException;
-import java.security.cert.X509Certificate;
-import java.security.spec.AlgorithmParameterSpec;
-import java.security.spec.ECGenParameterSpec;
-import java.security.spec.RSAKeyGenParameterSpec;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Provides a way to create instances of a KeyPair which will be placed in the
- * Android keystore service usable only by the application that called it. This
- * can be used in conjunction with
- * {@link java.security.KeyStore#getInstance(String)} using the
- * {@code "AndroidKeyStore"} type.
- * <p>
- * This class can not be directly instantiated and must instead be used via the
- * {@link KeyPairGenerator#getInstance(String)
- * KeyPairGenerator.getInstance("AndroidKeyStore")} API.
- *
- * @hide
- */
-public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGeneratorSpi {
-
- public static class RSA extends AndroidKeyStoreKeyPairGeneratorSpi {
- public RSA() {
- super(KeymasterDefs.KM_ALGORITHM_RSA);
- }
- }
-
- public static class EC extends AndroidKeyStoreKeyPairGeneratorSpi {
- public EC() {
- super(KeymasterDefs.KM_ALGORITHM_EC);
- }
- }
-
- /*
- * These must be kept in sync with system/security/keystore/defaults.h
- */
-
- /* EC */
- private static final int EC_DEFAULT_KEY_SIZE = 256;
-
- /* RSA */
- private static final int RSA_DEFAULT_KEY_SIZE = 2048;
- private static final int RSA_MIN_KEY_SIZE = 512;
- private static final int RSA_MAX_KEY_SIZE = 8192;
-
- private static final Map<String, Integer> SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE =
- new HashMap<String, Integer>();
- private static final List<String> SUPPORTED_EC_NIST_CURVE_NAMES = new ArrayList<String>();
- private static final List<Integer> SUPPORTED_EC_NIST_CURVE_SIZES = new ArrayList<Integer>();
- static {
- // Aliases for NIST P-224
- SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("p-224", 224);
- SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("secp224r1", 224);
-
-
- // Aliases for NIST P-256
- SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("p-256", 256);
- SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("secp256r1", 256);
- SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("prime256v1", 256);
-
- // Aliases for NIST P-384
- SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("p-384", 384);
- SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("secp384r1", 384);
-
- // Aliases for NIST P-521
- SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("p-521", 521);
- SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("secp521r1", 521);
-
- SUPPORTED_EC_NIST_CURVE_NAMES.addAll(SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.keySet());
- Collections.sort(SUPPORTED_EC_NIST_CURVE_NAMES);
-
- SUPPORTED_EC_NIST_CURVE_SIZES.addAll(
- new HashSet<Integer>(SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.values()));
- Collections.sort(SUPPORTED_EC_NIST_CURVE_SIZES);
- }
-
- private final int mOriginalKeymasterAlgorithm;
-
- private KeyStore mKeyStore;
-
- private KeyGenParameterSpec mSpec;
-
- private String mEntryAlias;
- private int mEntryUid;
- private boolean mEncryptionAtRestRequired;
- private @KeyProperties.KeyAlgorithmEnum String mJcaKeyAlgorithm;
- private int mKeymasterAlgorithm = -1;
- private int mKeySizeBits;
- private SecureRandom mRng;
-
- private int[] mKeymasterPurposes;
- private int[] mKeymasterBlockModes;
- private int[] mKeymasterEncryptionPaddings;
- private int[] mKeymasterSignaturePaddings;
- private int[] mKeymasterDigests;
-
- private BigInteger mRSAPublicExponent;
-
- protected AndroidKeyStoreKeyPairGeneratorSpi(int keymasterAlgorithm) {
- mOriginalKeymasterAlgorithm = keymasterAlgorithm;
- }
-
- @SuppressWarnings("deprecation")
- @Override
- public void initialize(int keysize, SecureRandom random) {
- throw new IllegalArgumentException(
- KeyGenParameterSpec.class.getName() + " or " + KeyPairGeneratorSpec.class.getName()
- + " required to initialize this KeyPairGenerator");
- }
-
- @SuppressWarnings("deprecation")
- @Override
- public void initialize(AlgorithmParameterSpec params, SecureRandom random)
- throws InvalidAlgorithmParameterException {
- resetAll();
-
- boolean success = false;
- try {
- if (params == null) {
- throw new InvalidAlgorithmParameterException(
- "Must supply params of type " + KeyGenParameterSpec.class.getName()
- + " or " + KeyPairGeneratorSpec.class.getName());
- }
-
- KeyGenParameterSpec spec;
- boolean encryptionAtRestRequired = false;
- int keymasterAlgorithm = mOriginalKeymasterAlgorithm;
- if (params instanceof KeyGenParameterSpec) {
- spec = (KeyGenParameterSpec) params;
- } else if (params instanceof KeyPairGeneratorSpec) {
- // Legacy/deprecated spec
- KeyPairGeneratorSpec legacySpec = (KeyPairGeneratorSpec) params;
- try {
- KeyGenParameterSpec.Builder specBuilder;
- String specKeyAlgorithm = legacySpec.getKeyType();
- if (specKeyAlgorithm != null) {
- // Spec overrides the generator's default key algorithm
- try {
- keymasterAlgorithm =
- KeyProperties.KeyAlgorithm.toKeymasterAsymmetricKeyAlgorithm(
- specKeyAlgorithm);
- } catch (IllegalArgumentException e) {
- throw new InvalidAlgorithmParameterException(
- "Invalid key type in parameters", e);
- }
- }
- switch (keymasterAlgorithm) {
- case KeymasterDefs.KM_ALGORITHM_EC:
- specBuilder = new KeyGenParameterSpec.Builder(
- legacySpec.getKeystoreAlias(),
- KeyProperties.PURPOSE_SIGN
- | KeyProperties.PURPOSE_VERIFY);
- // Authorized to be used with any digest (including no digest).
- // MD5 was never offered for Android Keystore for ECDSA.
- specBuilder.setDigests(
- KeyProperties.DIGEST_NONE,
- KeyProperties.DIGEST_SHA1,
- KeyProperties.DIGEST_SHA224,
- KeyProperties.DIGEST_SHA256,
- KeyProperties.DIGEST_SHA384,
- KeyProperties.DIGEST_SHA512);
- break;
- case KeymasterDefs.KM_ALGORITHM_RSA:
- specBuilder = new KeyGenParameterSpec.Builder(
- legacySpec.getKeystoreAlias(),
- KeyProperties.PURPOSE_ENCRYPT
- | KeyProperties.PURPOSE_DECRYPT
- | KeyProperties.PURPOSE_SIGN
- | KeyProperties.PURPOSE_VERIFY);
- // Authorized to be used with any digest (including no digest).
- specBuilder.setDigests(
- KeyProperties.DIGEST_NONE,
- KeyProperties.DIGEST_MD5,
- KeyProperties.DIGEST_SHA1,
- KeyProperties.DIGEST_SHA224,
- KeyProperties.DIGEST_SHA256,
- KeyProperties.DIGEST_SHA384,
- KeyProperties.DIGEST_SHA512);
- // Authorized to be used with any encryption and signature padding
- // schemes (including no padding).
- specBuilder.setEncryptionPaddings(
- KeyProperties.ENCRYPTION_PADDING_NONE,
- KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1,
- KeyProperties.ENCRYPTION_PADDING_RSA_OAEP);
- specBuilder.setSignaturePaddings(
- KeyProperties.SIGNATURE_PADDING_RSA_PKCS1,
- KeyProperties.SIGNATURE_PADDING_RSA_PSS);
- // Disable randomized encryption requirement to support encryption
- // padding NONE above.
- specBuilder.setRandomizedEncryptionRequired(false);
- break;
- default:
- throw new ProviderException(
- "Unsupported algorithm: " + mKeymasterAlgorithm);
- }
-
- if (legacySpec.getKeySize() != -1) {
- specBuilder.setKeySize(legacySpec.getKeySize());
- }
- if (legacySpec.getAlgorithmParameterSpec() != null) {
- specBuilder.setAlgorithmParameterSpec(
- legacySpec.getAlgorithmParameterSpec());
- }
- specBuilder.setCertificateSubject(legacySpec.getSubjectDN());
- specBuilder.setCertificateSerialNumber(legacySpec.getSerialNumber());
- specBuilder.setCertificateNotBefore(legacySpec.getStartDate());
- specBuilder.setCertificateNotAfter(legacySpec.getEndDate());
- encryptionAtRestRequired = legacySpec.isEncryptionRequired();
- specBuilder.setUserAuthenticationRequired(false);
-
- spec = specBuilder.build();
- } catch (NullPointerException | IllegalArgumentException e) {
- throw new InvalidAlgorithmParameterException(e);
- }
- } else {
- throw new InvalidAlgorithmParameterException(
- "Unsupported params class: " + params.getClass().getName()
- + ". Supported: " + KeyGenParameterSpec.class.getName()
- + ", " + KeyPairGeneratorSpec.class.getName());
- }
-
- mEntryAlias = spec.getKeystoreAlias();
- mEntryUid = spec.getUid();
- mSpec = spec;
- mKeymasterAlgorithm = keymasterAlgorithm;
- mEncryptionAtRestRequired = encryptionAtRestRequired;
- mKeySizeBits = spec.getKeySize();
- initAlgorithmSpecificParameters();
- if (mKeySizeBits == -1) {
- mKeySizeBits = getDefaultKeySize(keymasterAlgorithm);
- }
- checkValidKeySize(keymasterAlgorithm, mKeySizeBits, mSpec.isStrongBoxBacked());
-
- if (spec.getKeystoreAlias() == null) {
- throw new InvalidAlgorithmParameterException("KeyStore entry alias not provided");
- }
-
- String jcaKeyAlgorithm;
- try {
- jcaKeyAlgorithm = KeyProperties.KeyAlgorithm.fromKeymasterAsymmetricKeyAlgorithm(
- keymasterAlgorithm);
- mKeymasterPurposes = KeyProperties.Purpose.allToKeymaster(spec.getPurposes());
- mKeymasterBlockModes = KeyProperties.BlockMode.allToKeymaster(spec.getBlockModes());
- mKeymasterEncryptionPaddings = KeyProperties.EncryptionPadding.allToKeymaster(
- spec.getEncryptionPaddings());
- if (((spec.getPurposes() & KeyProperties.PURPOSE_ENCRYPT) != 0)
- && (spec.isRandomizedEncryptionRequired())) {
- for (int keymasterPadding : mKeymasterEncryptionPaddings) {
- if (!KeymasterUtils
- .isKeymasterPaddingSchemeIndCpaCompatibleWithAsymmetricCrypto(
- keymasterPadding)) {
- throw new InvalidAlgorithmParameterException(
- "Randomized encryption (IND-CPA) required but may be violated"
- + " by padding scheme: "
- + KeyProperties.EncryptionPadding.fromKeymaster(
- keymasterPadding)
- + ". See " + KeyGenParameterSpec.class.getName()
- + " documentation.");
- }
- }
- }
- mKeymasterSignaturePaddings = KeyProperties.SignaturePadding.allToKeymaster(
- spec.getSignaturePaddings());
- if (spec.isDigestsSpecified()) {
- mKeymasterDigests = KeyProperties.Digest.allToKeymaster(spec.getDigests());
- } else {
- mKeymasterDigests = EmptyArray.INT;
- }
-
- // Check that user authentication related parameters are acceptable. This method
- // will throw an IllegalStateException if there are issues (e.g., secure lock screen
- // not set up).
- KeymasterUtils.addUserAuthArgs(new KeymasterArguments(), mSpec);
- } catch (IllegalArgumentException | IllegalStateException e) {
- throw new InvalidAlgorithmParameterException(e);
- }
-
- mJcaKeyAlgorithm = jcaKeyAlgorithm;
- mRng = random;
- mKeyStore = KeyStore.getInstance();
- success = true;
- } finally {
- if (!success) {
- resetAll();
- }
- }
- }
-
- private void resetAll() {
- mEntryAlias = null;
- mEntryUid = KeyStore.UID_SELF;
- mJcaKeyAlgorithm = null;
- mKeymasterAlgorithm = -1;
- mKeymasterPurposes = null;
- mKeymasterBlockModes = null;
- mKeymasterEncryptionPaddings = null;
- mKeymasterSignaturePaddings = null;
- mKeymasterDigests = null;
- mKeySizeBits = 0;
- mSpec = null;
- mRSAPublicExponent = null;
- mEncryptionAtRestRequired = false;
- mRng = null;
- mKeyStore = null;
- }
-
- private void initAlgorithmSpecificParameters() throws InvalidAlgorithmParameterException {
- AlgorithmParameterSpec algSpecificSpec = mSpec.getAlgorithmParameterSpec();
- switch (mKeymasterAlgorithm) {
- case KeymasterDefs.KM_ALGORITHM_RSA:
- {
- BigInteger publicExponent = null;
- if (algSpecificSpec instanceof RSAKeyGenParameterSpec) {
- RSAKeyGenParameterSpec rsaSpec = (RSAKeyGenParameterSpec) algSpecificSpec;
- if (mKeySizeBits == -1) {
- mKeySizeBits = rsaSpec.getKeysize();
- } else if (mKeySizeBits != rsaSpec.getKeysize()) {
- throw new InvalidAlgorithmParameterException("RSA key size must match "
- + " between " + mSpec + " and " + algSpecificSpec
- + ": " + mKeySizeBits + " vs " + rsaSpec.getKeysize());
- }
- publicExponent = rsaSpec.getPublicExponent();
- } else if (algSpecificSpec != null) {
- throw new InvalidAlgorithmParameterException(
- "RSA may only use RSAKeyGenParameterSpec");
- }
- if (publicExponent == null) {
- publicExponent = RSAKeyGenParameterSpec.F4;
- }
- if (publicExponent.compareTo(BigInteger.ZERO) < 1) {
- throw new InvalidAlgorithmParameterException(
- "RSA public exponent must be positive: " + publicExponent);
- }
- if (publicExponent.compareTo(KeymasterArguments.UINT64_MAX_VALUE) > 0) {
- throw new InvalidAlgorithmParameterException(
- "Unsupported RSA public exponent: " + publicExponent
- + ". Maximum supported value: " + KeymasterArguments.UINT64_MAX_VALUE);
- }
- mRSAPublicExponent = publicExponent;
- break;
- }
- case KeymasterDefs.KM_ALGORITHM_EC:
- if (algSpecificSpec instanceof ECGenParameterSpec) {
- ECGenParameterSpec ecSpec = (ECGenParameterSpec) algSpecificSpec;
- String curveName = ecSpec.getName();
- Integer ecSpecKeySizeBits = SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.get(
- curveName.toLowerCase(Locale.US));
- if (ecSpecKeySizeBits == null) {
- throw new InvalidAlgorithmParameterException(
- "Unsupported EC curve name: " + curveName
- + ". Supported: " + SUPPORTED_EC_NIST_CURVE_NAMES);
- }
- if (mKeySizeBits == -1) {
- mKeySizeBits = ecSpecKeySizeBits;
- } else if (mKeySizeBits != ecSpecKeySizeBits) {
- throw new InvalidAlgorithmParameterException("EC key size must match "
- + " between " + mSpec + " and " + algSpecificSpec
- + ": " + mKeySizeBits + " vs " + ecSpecKeySizeBits);
- }
- } else if (algSpecificSpec != null) {
- throw new InvalidAlgorithmParameterException(
- "EC may only use ECGenParameterSpec");
- }
- break;
- default:
- throw new ProviderException("Unsupported algorithm: " + mKeymasterAlgorithm);
- }
- }
-
- @Override
- public KeyPair generateKeyPair() {
- if (mKeyStore == null || mSpec == null) {
- throw new IllegalStateException("Not initialized");
- }
-
- int flags = (mEncryptionAtRestRequired) ? KeyStore.FLAG_ENCRYPTED : 0;
- if (((flags & KeyStore.FLAG_ENCRYPTED) != 0)
- && (mKeyStore.state() != KeyStore.State.UNLOCKED)) {
- throw new IllegalStateException(
- "Encryption at rest using secure lock screen credential requested for key pair"
- + ", but the user has not yet entered the credential");
- }
-
- if (mSpec.isStrongBoxBacked()) {
- flags |= KeyStore.FLAG_STRONGBOX;
- }
- if (mSpec.isCriticalToDeviceEncryption()) {
- flags |= KeyStore.FLAG_CRITICAL_TO_DEVICE_ENCRYPTION;
- }
-
- byte[] additionalEntropy =
- KeyStoreCryptoOperationUtils.getRandomBytesToMixIntoKeystoreRng(
- mRng, (mKeySizeBits + 7) / 8);
-
- Credentials.deleteAllTypesForAlias(mKeyStore, mEntryAlias, mEntryUid);
- final String privateKeyAlias = Credentials.USER_PRIVATE_KEY + mEntryAlias;
- boolean success = false;
- try {
- generateKeystoreKeyPair(
- privateKeyAlias, constructKeyGenerationArguments(), additionalEntropy, flags);
- KeyPair keyPair = loadKeystoreKeyPair(privateKeyAlias);
-
- storeCertificateChain(flags, createCertificateChain(privateKeyAlias, keyPair));
-
- success = true;
- return keyPair;
- } catch (ProviderException | IllegalArgumentException | DeviceIdAttestationException e) {
- if ((mSpec.getPurposes() & KeyProperties.PURPOSE_WRAP_KEY) != 0) {
- throw new SecureKeyImportUnavailableException(e);
- } else {
- throw new ProviderException(e);
- }
- } finally {
- if (!success) {
- Credentials.deleteAllTypesForAlias(mKeyStore, mEntryAlias, mEntryUid);
- }
- }
- }
-
- private Iterable<byte[]> createCertificateChain(final String privateKeyAlias, KeyPair keyPair)
- throws ProviderException, DeviceIdAttestationException {
- byte[] challenge = mSpec.getAttestationChallenge();
- if (challenge != null) {
- KeymasterArguments args = new KeymasterArguments();
- args.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_CHALLENGE, challenge);
-
- if (mSpec.isDevicePropertiesAttestationIncluded()) {
- args.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_BRAND,
- Build.BRAND.getBytes(StandardCharsets.UTF_8));
- args.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_DEVICE,
- Build.DEVICE.getBytes(StandardCharsets.UTF_8));
- args.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_PRODUCT,
- Build.PRODUCT.getBytes(StandardCharsets.UTF_8));
- args.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_MANUFACTURER,
- Build.MANUFACTURER.getBytes(StandardCharsets.UTF_8));
- args.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_MODEL,
- Build.MODEL.getBytes(StandardCharsets.UTF_8));
- }
-
- int[] idTypes = mSpec.getAttestationIds();
- if (idTypes != null) {
- final Set<Integer> idTypesSet = new ArraySet<>(idTypes.length);
- for (int idType : idTypes) {
- idTypesSet.add(idType);
- }
- TelephonyManager telephonyService = null;
- if (idTypesSet.contains(AttestationUtils.ID_TYPE_IMEI)
- || idTypesSet.contains(AttestationUtils.ID_TYPE_MEID)) {
- telephonyService =
- (TelephonyManager) KeyStore.getApplicationContext().getSystemService(
- Context.TELEPHONY_SERVICE);
- if (telephonyService == null) {
- throw new DeviceIdAttestationException(
- "Unable to access telephony service");
- }
- }
- for (final Integer idType : idTypesSet) {
- switch (idType) {
- case AttestationUtils.ID_TYPE_SERIAL:
- args.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_SERIAL,
- Build.getSerial().getBytes(StandardCharsets.UTF_8)
- );
- break;
- case AttestationUtils.ID_TYPE_IMEI: {
- final String imei = telephonyService.getImei(0);
- if (imei == null) {
- throw new DeviceIdAttestationException("Unable to retrieve IMEI");
- }
- args.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_IMEI,
- imei.getBytes(StandardCharsets.UTF_8)
- );
- break;
- }
- case AttestationUtils.ID_TYPE_MEID: {
- final String meid = telephonyService.getMeid(0);
- if (meid == null) {
- throw new DeviceIdAttestationException("Unable to retrieve MEID");
- }
- args.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_MEID,
- meid.getBytes(StandardCharsets.UTF_8)
- );
- break;
- }
- case AttestationUtils.USE_INDIVIDUAL_ATTESTATION: {
- args.addBoolean(KeymasterDefs.KM_TAG_DEVICE_UNIQUE_ATTESTATION);
- break;
- }
- default:
- throw new IllegalArgumentException("Unknown device ID type " + idType);
- }
- }
- }
-
- return getAttestationChain(privateKeyAlias, keyPair, args);
- }
-
- // Very short certificate chain in the non-attestation case.
- return Collections.singleton(generateSelfSignedCertificateBytes(keyPair));
- }
-
- private void generateKeystoreKeyPair(final String privateKeyAlias, KeymasterArguments args,
- byte[] additionalEntropy, final int flags) throws ProviderException {
- KeyCharacteristics resultingKeyCharacteristics = new KeyCharacteristics();
- int errorCode = mKeyStore.generateKey(privateKeyAlias, args, additionalEntropy,
- mEntryUid, flags, resultingKeyCharacteristics);
- if (errorCode != KeyStore.NO_ERROR) {
- if (errorCode == KeyStore.HARDWARE_TYPE_UNAVAILABLE) {
- throw new StrongBoxUnavailableException("Failed to generate key pair");
- } else {
- throw new ProviderException(
- "Failed to generate key pair", KeyStore.getKeyStoreException(errorCode));
- }
- }
- }
-
- private KeyPair loadKeystoreKeyPair(final String privateKeyAlias) throws ProviderException {
- try {
- KeyPair result = AndroidKeyStoreProvider.loadAndroidKeyStoreKeyPairFromKeystore(
- mKeyStore, privateKeyAlias, mEntryUid);
- if (!mJcaKeyAlgorithm.equalsIgnoreCase(result.getPrivate().getAlgorithm())) {
- throw new ProviderException(
- "Generated key pair algorithm does not match requested algorithm: "
- + result.getPrivate().getAlgorithm() + " vs " + mJcaKeyAlgorithm);
- }
- return result;
- } catch (UnrecoverableKeyException | KeyPermanentlyInvalidatedException e) {
- throw new ProviderException("Failed to load generated key pair from keystore", e);
- }
- }
-
- private KeymasterArguments constructKeyGenerationArguments()
- throws IllegalArgumentException, DeviceIdAttestationException {
- KeymasterArguments args = new KeymasterArguments();
- args.addUnsignedInt(KeymasterDefs.KM_TAG_KEY_SIZE, mKeySizeBits);
- args.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, mKeymasterAlgorithm);
- args.addEnums(KeymasterDefs.KM_TAG_PURPOSE, mKeymasterPurposes);
- args.addEnums(KeymasterDefs.KM_TAG_BLOCK_MODE, mKeymasterBlockModes);
- args.addEnums(KeymasterDefs.KM_TAG_PADDING, mKeymasterEncryptionPaddings);
- args.addEnums(KeymasterDefs.KM_TAG_PADDING, mKeymasterSignaturePaddings);
- args.addEnums(KeymasterDefs.KM_TAG_DIGEST, mKeymasterDigests);
-
- KeymasterUtils.addUserAuthArgs(args, mSpec);
- args.addDateIfNotNull(KeymasterDefs.KM_TAG_ACTIVE_DATETIME, mSpec.getKeyValidityStart());
- args.addDateIfNotNull(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME,
- mSpec.getKeyValidityForOriginationEnd());
- args.addDateIfNotNull(KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME,
- mSpec.getKeyValidityForConsumptionEnd());
- addAlgorithmSpecificParameters(args);
-
- if (mSpec.isUniqueIdIncluded()) {
- args.addBoolean(KeymasterDefs.KM_TAG_INCLUDE_UNIQUE_ID);
- }
- return args;
- }
-
- private void storeCertificateChain(final int flags, Iterable<byte[]> iterable)
- throws ProviderException {
- Iterator<byte[]> iter = iterable.iterator();
- storeCertificate(
- Credentials.USER_CERTIFICATE, iter.next(), flags, "Failed to store certificate");
-
- if (!iter.hasNext()) {
- return;
- }
-
- ByteArrayOutputStream certificateConcatenationStream = new ByteArrayOutputStream();
- while (iter.hasNext()) {
- byte[] data = iter.next();
- certificateConcatenationStream.write(data, 0, data.length);
- }
-
- storeCertificate(Credentials.CA_CERTIFICATE, certificateConcatenationStream.toByteArray(),
- flags, "Failed to store attestation CA certificate");
- }
-
- private void storeCertificate(String prefix, byte[] certificateBytes, final int flags,
- String failureMessage) throws ProviderException {
- int insertErrorCode = mKeyStore.insert(
- prefix + mEntryAlias,
- certificateBytes,
- mEntryUid,
- flags);
- if (insertErrorCode != KeyStore.NO_ERROR) {
- throw new ProviderException(failureMessage,
- KeyStore.getKeyStoreException(insertErrorCode));
- }
- }
-
- private byte[] generateSelfSignedCertificateBytes(KeyPair keyPair) throws ProviderException {
- try {
- return generateSelfSignedCertificate(keyPair.getPrivate(), keyPair.getPublic())
- .getEncoded();
- } catch (IOException | CertificateParsingException e) {
- throw new ProviderException("Failed to generate self-signed certificate", e);
- } catch (CertificateEncodingException e) {
- throw new ProviderException(
- "Failed to obtain encoded form of self-signed certificate", e);
- }
- }
-
- private Iterable<byte[]> getAttestationChain(String privateKeyAlias,
- KeyPair keyPair, KeymasterArguments args)
- throws ProviderException {
- final KeymasterCertificateChain outChain = new KeymasterCertificateChain();
- final int errorCode;
- if (mSpec.isDevicePropertiesAttestationIncluded()
- && mSpec.getAttestationChallenge() == null) {
- throw new ProviderException("An attestation challenge must be provided when requesting "
- + "device properties attestation.");
- }
- errorCode = mKeyStore.attestKey(privateKeyAlias, args, outChain);
- if (errorCode != KeyStore.NO_ERROR) {
- throw new ProviderException("Failed to generate attestation certificate chain",
- KeyStore.getKeyStoreException(errorCode));
- }
- Collection<byte[]> chain = outChain.getCertificates();
- if (chain.size() < 2) {
- throw new ProviderException("Attestation certificate chain contained "
- + chain.size() + " entries. At least two are required.");
- }
- return chain;
- }
-
- private void addAlgorithmSpecificParameters(KeymasterArguments keymasterArgs) {
- switch (mKeymasterAlgorithm) {
- case KeymasterDefs.KM_ALGORITHM_RSA:
- keymasterArgs.addUnsignedLong(
- KeymasterDefs.KM_TAG_RSA_PUBLIC_EXPONENT, mRSAPublicExponent);
- break;
- case KeymasterDefs.KM_ALGORITHM_EC:
- break;
- default:
- throw new ProviderException("Unsupported algorithm: " + mKeymasterAlgorithm);
- }
- }
-
- private X509Certificate generateSelfSignedCertificate(PrivateKey privateKey,
- PublicKey publicKey) throws CertificateParsingException, IOException {
- String signatureAlgorithm =
- getCertificateSignatureAlgorithm(mKeymasterAlgorithm, mKeySizeBits, mSpec);
- if (signatureAlgorithm == null) {
- // Key cannot be used to sign a certificate
- return generateSelfSignedCertificateWithFakeSignature(publicKey);
- } else {
- // Key can be used to sign a certificate
- try {
- return generateSelfSignedCertificateWithValidSignature(
- privateKey, publicKey, signatureAlgorithm);
- } catch (Exception e) {
- // Failed to generate the self-signed certificate with valid signature. Fall back
- // to generating a self-signed certificate with a fake signature. This is done for
- // all exception types because we prefer key pair generation to succeed and end up
- // producing a self-signed certificate with an invalid signature to key pair
- // generation failing.
- return generateSelfSignedCertificateWithFakeSignature(publicKey);
- }
- }
- }
-
- @SuppressWarnings("deprecation")
- private X509Certificate generateSelfSignedCertificateWithValidSignature(
- PrivateKey privateKey, PublicKey publicKey, String signatureAlgorithm) throws Exception {
- final X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();
- certGen.setPublicKey(publicKey);
- certGen.setSerialNumber(mSpec.getCertificateSerialNumber());
- certGen.setSubjectDN(mSpec.getCertificateSubject());
- certGen.setIssuerDN(mSpec.getCertificateSubject());
- certGen.setNotBefore(mSpec.getCertificateNotBefore());
- certGen.setNotAfter(mSpec.getCertificateNotAfter());
- certGen.setSignatureAlgorithm(signatureAlgorithm);
- return certGen.generate(privateKey);
- }
-
- @SuppressWarnings("deprecation")
- private X509Certificate generateSelfSignedCertificateWithFakeSignature(
- PublicKey publicKey) throws IOException, CertificateParsingException {
- V3TBSCertificateGenerator tbsGenerator = new V3TBSCertificateGenerator();
- ASN1ObjectIdentifier sigAlgOid;
- AlgorithmIdentifier sigAlgId;
- byte[] signature;
- switch (mKeymasterAlgorithm) {
- case KeymasterDefs.KM_ALGORITHM_EC:
- sigAlgOid = X9ObjectIdentifiers.ecdsa_with_SHA256;
- sigAlgId = new AlgorithmIdentifier(sigAlgOid);
- ASN1EncodableVector v = new ASN1EncodableVector();
- v.add(new ASN1Integer(BigInteger.valueOf(0)));
- v.add(new ASN1Integer(BigInteger.valueOf(0)));
- signature = new DERSequence().getEncoded();
- break;
- case KeymasterDefs.KM_ALGORITHM_RSA:
- sigAlgOid = PKCSObjectIdentifiers.sha256WithRSAEncryption;
- sigAlgId = new AlgorithmIdentifier(sigAlgOid, DERNull.INSTANCE);
- signature = new byte[1];
- break;
- default:
- throw new ProviderException("Unsupported key algorithm: " + mKeymasterAlgorithm);
- }
-
- try (ASN1InputStream publicKeyInfoIn = new ASN1InputStream(publicKey.getEncoded())) {
- tbsGenerator.setSubjectPublicKeyInfo(
- SubjectPublicKeyInfo.getInstance(publicKeyInfoIn.readObject()));
- }
- tbsGenerator.setSerialNumber(new ASN1Integer(mSpec.getCertificateSerialNumber()));
- X509Principal subject =
- new X509Principal(mSpec.getCertificateSubject().getEncoded());
- tbsGenerator.setSubject(subject);
- tbsGenerator.setIssuer(subject);
- tbsGenerator.setStartDate(new Time(mSpec.getCertificateNotBefore()));
- tbsGenerator.setEndDate(new Time(mSpec.getCertificateNotAfter()));
- tbsGenerator.setSignature(sigAlgId);
- TBSCertificate tbsCertificate = tbsGenerator.generateTBSCertificate();
-
- ASN1EncodableVector result = new ASN1EncodableVector();
- result.add(tbsCertificate);
- result.add(sigAlgId);
- result.add(new DERBitString(signature));
- return new X509CertificateObject(Certificate.getInstance(new DERSequence(result)));
- }
-
- private static int getDefaultKeySize(int keymasterAlgorithm) {
- switch (keymasterAlgorithm) {
- case KeymasterDefs.KM_ALGORITHM_EC:
- return EC_DEFAULT_KEY_SIZE;
- case KeymasterDefs.KM_ALGORITHM_RSA:
- return RSA_DEFAULT_KEY_SIZE;
- default:
- throw new ProviderException("Unsupported algorithm: " + keymasterAlgorithm);
- }
- }
-
- private static void checkValidKeySize(
- int keymasterAlgorithm,
- int keySize,
- boolean isStrongBoxBacked)
- throws InvalidAlgorithmParameterException {
- switch (keymasterAlgorithm) {
- case KeymasterDefs.KM_ALGORITHM_EC:
- if (isStrongBoxBacked && keySize != 256) {
- throw new InvalidAlgorithmParameterException(
- "Unsupported StrongBox EC key size: "
- + keySize + " bits. Supported: 256");
- }
- if (!SUPPORTED_EC_NIST_CURVE_SIZES.contains(keySize)) {
- throw new InvalidAlgorithmParameterException("Unsupported EC key size: "
- + keySize + " bits. Supported: " + SUPPORTED_EC_NIST_CURVE_SIZES);
- }
- break;
- case KeymasterDefs.KM_ALGORITHM_RSA:
- if (keySize < RSA_MIN_KEY_SIZE || keySize > RSA_MAX_KEY_SIZE) {
- throw new InvalidAlgorithmParameterException("RSA key size must be >= "
- + RSA_MIN_KEY_SIZE + " and <= " + RSA_MAX_KEY_SIZE);
- }
- break;
- default:
- throw new ProviderException("Unsupported algorithm: " + keymasterAlgorithm);
- }
- }
-
- /**
- * Returns the {@code Signature} algorithm to be used for signing a certificate using the
- * specified key or {@code null} if the key cannot be used for signing a certificate.
- */
- @Nullable
- private static String getCertificateSignatureAlgorithm(
- int keymasterAlgorithm,
- int keySizeBits,
- KeyGenParameterSpec spec) {
- // Constraints:
- // 1. Key must be authorized for signing without user authentication.
- // 2. Signature digest must be one of key's authorized digests.
- // 3. For RSA keys, the digest output size must not exceed modulus size minus space overhead
- // of RSA PKCS#1 signature padding scheme (about 30 bytes).
- // 4. For EC keys, the there is no point in using a digest whose output size is longer than
- // key/field size because the digest will be truncated to that size.
-
- if ((spec.getPurposes() & KeyProperties.PURPOSE_SIGN) == 0) {
- // Key not authorized for signing
- return null;
- }
- if (spec.isUserAuthenticationRequired()) {
- // Key not authorized for use without user authentication
- return null;
- }
- if (!spec.isDigestsSpecified()) {
- // Key not authorized for any digests -- can't sign
- return null;
- }
- switch (keymasterAlgorithm) {
- case KeymasterDefs.KM_ALGORITHM_EC:
- {
- Set<Integer> availableKeymasterDigests = getAvailableKeymasterSignatureDigests(
- spec.getDigests(),
- AndroidKeyStoreBCWorkaroundProvider.getSupportedEcdsaSignatureDigests());
-
- int bestKeymasterDigest = -1;
- int bestDigestOutputSizeBits = -1;
- for (int keymasterDigest : availableKeymasterDigests) {
- int outputSizeBits = KeymasterUtils.getDigestOutputSizeBits(keymasterDigest);
- if (outputSizeBits == keySizeBits) {
- // Perfect match -- use this digest
- bestKeymasterDigest = keymasterDigest;
- bestDigestOutputSizeBits = outputSizeBits;
- break;
- }
- // Not a perfect match -- check against the best digest so far
- if (bestKeymasterDigest == -1) {
- // First digest tested -- definitely the best so far
- bestKeymasterDigest = keymasterDigest;
- bestDigestOutputSizeBits = outputSizeBits;
- } else {
- // Prefer output size to be as close to key size as possible, with output
- // sizes larger than key size preferred to those smaller than key size.
- if (bestDigestOutputSizeBits < keySizeBits) {
- // Output size of the best digest so far is smaller than key size.
- // Anything larger is a win.
- if (outputSizeBits > bestDigestOutputSizeBits) {
- bestKeymasterDigest = keymasterDigest;
- bestDigestOutputSizeBits = outputSizeBits;
- }
- } else {
- // Output size of the best digest so far is larger than key size.
- // Anything smaller is a win, as long as it's not smaller than key size.
- if ((outputSizeBits < bestDigestOutputSizeBits)
- && (outputSizeBits >= keySizeBits)) {
- bestKeymasterDigest = keymasterDigest;
- bestDigestOutputSizeBits = outputSizeBits;
- }
- }
- }
- }
- if (bestKeymasterDigest == -1) {
- return null;
- }
- return KeyProperties.Digest.fromKeymasterToSignatureAlgorithmDigest(
- bestKeymasterDigest) + "WithECDSA";
- }
- case KeymasterDefs.KM_ALGORITHM_RSA:
- {
- // Check whether this key is authorized for PKCS#1 signature padding.
- // We use Bouncy Castle to generate self-signed RSA certificates. Bouncy Castle
- // only supports RSA certificates signed using PKCS#1 padding scheme. The key needs
- // to be authorized for PKCS#1 padding or padding NONE which means any padding.
- boolean pkcs1SignaturePaddingSupported =
- com.android.internal.util.ArrayUtils.contains(
- KeyProperties.SignaturePadding.allToKeymaster(
- spec.getSignaturePaddings()),
- KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_SIGN);
- if (!pkcs1SignaturePaddingSupported) {
- // Key not authorized for PKCS#1 signature padding -- can't sign
- return null;
- }
-
- Set<Integer> availableKeymasterDigests = getAvailableKeymasterSignatureDigests(
- spec.getDigests(),
- AndroidKeyStoreBCWorkaroundProvider.getSupportedEcdsaSignatureDigests());
-
- // The amount of space available for the digest is less than modulus size by about
- // 30 bytes because padding must be at least 11 bytes long (00 || 01 || PS || 00,
- // where PS must be at least 8 bytes long), and then there's also the 15--19 bytes
- // overhead (depending the on chosen digest) for encoding digest OID and digest
- // value in DER.
- int maxDigestOutputSizeBits = keySizeBits - 30 * 8;
- int bestKeymasterDigest = -1;
- int bestDigestOutputSizeBits = -1;
- for (int keymasterDigest : availableKeymasterDigests) {
- int outputSizeBits = KeymasterUtils.getDigestOutputSizeBits(keymasterDigest);
- if (outputSizeBits > maxDigestOutputSizeBits) {
- // Digest too long (signature generation will fail) -- skip
- continue;
- }
- if (bestKeymasterDigest == -1) {
- // First digest tested -- definitely the best so far
- bestKeymasterDigest = keymasterDigest;
- bestDigestOutputSizeBits = outputSizeBits;
- } else {
- // The longer the better
- if (outputSizeBits > bestDigestOutputSizeBits) {
- bestKeymasterDigest = keymasterDigest;
- bestDigestOutputSizeBits = outputSizeBits;
- }
- }
- }
- if (bestKeymasterDigest == -1) {
- return null;
- }
- return KeyProperties.Digest.fromKeymasterToSignatureAlgorithmDigest(
- bestKeymasterDigest) + "WithRSA";
- }
- default:
- throw new ProviderException("Unsupported algorithm: " + keymasterAlgorithm);
- }
- }
-
- private static Set<Integer> getAvailableKeymasterSignatureDigests(
- @KeyProperties.DigestEnum String[] authorizedKeyDigests,
- @KeyProperties.DigestEnum String[] supportedSignatureDigests) {
- Set<Integer> authorizedKeymasterKeyDigests = new HashSet<Integer>();
- for (int keymasterDigest : KeyProperties.Digest.allToKeymaster(authorizedKeyDigests)) {
- authorizedKeymasterKeyDigests.add(keymasterDigest);
- }
- Set<Integer> supportedKeymasterSignatureDigests = new HashSet<Integer>();
- for (int keymasterDigest
- : KeyProperties.Digest.allToKeymaster(supportedSignatureDigests)) {
- supportedKeymasterSignatureDigests.add(keymasterDigest);
- }
- Set<Integer> result = new HashSet<Integer>(supportedKeymasterSignatureDigests);
- result.retainAll(authorizedKeymasterKeyDigests);
- return result;
- }
-}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreLoadStoreParameter.java b/keystore/java/android/security/keystore/AndroidKeyStoreLoadStoreParameter.java
deleted file mode 100644
index 45d579e..0000000
--- a/keystore/java/android/security/keystore/AndroidKeyStoreLoadStoreParameter.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.keystore;
-
-import java.security.KeyStore;
-import java.security.KeyStore.ProtectionParameter;
-
-class AndroidKeyStoreLoadStoreParameter implements KeyStore.LoadStoreParameter {
-
- private final int mUid;
-
- AndroidKeyStoreLoadStoreParameter(int uid) {
- mUid = uid;
- }
-
- @Override
- public ProtectionParameter getProtectionParameter() {
- return null;
- }
-
- int getUid() {
- return mUid;
- }
-}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStorePrivateKey.java b/keystore/java/android/security/keystore/AndroidKeyStorePrivateKey.java
deleted file mode 100644
index 06e4c88..0000000
--- a/keystore/java/android/security/keystore/AndroidKeyStorePrivateKey.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.keystore;
-
-import java.security.PrivateKey;
-
-/**
- * {@link PrivateKey} backed by Android Keystore.
- *
- * @hide
- */
-public class AndroidKeyStorePrivateKey extends AndroidKeyStoreKey implements PrivateKey {
-
- public AndroidKeyStorePrivateKey(String alias, int uid, String algorithm) {
- super(alias, uid, algorithm);
- }
-}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java b/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
index 0871517..ecb082e 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
@@ -20,30 +20,13 @@
import android.annotation.SystemApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.security.KeyStore;
-import android.security.keymaster.ExportResult;
-import android.security.keymaster.KeyCharacteristics;
-import android.security.keymaster.KeymasterDefs;
import java.io.IOException;
-import java.security.KeyFactory;
-import java.security.KeyPair;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.Provider;
-import java.security.ProviderException;
-import java.security.PublicKey;
-import java.security.Security;
-import java.security.Signature;
-import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
-import java.security.interfaces.ECKey;
-import java.security.interfaces.ECPublicKey;
-import java.security.interfaces.RSAKey;
-import java.security.interfaces.RSAPublicKey;
-import java.security.spec.InvalidKeySpecException;
-import java.security.spec.X509EncodedKeySpec;
-import java.util.List;
import javax.crypto.Cipher;
import javax.crypto.Mac;
@@ -57,117 +40,10 @@
public class AndroidKeyStoreProvider extends Provider {
private static final String PROVIDER_NAME = "AndroidKeyStore";
- // IMPLEMENTATION NOTE: Class names are hard-coded in this provider to avoid loading these
- // classes when this provider is instantiated and installed early on during each app's
- // initialization process.
- //
- // Crypto operations operating on the AndroidKeyStore keys must not be offered by this provider.
- // Instead, they need to be offered by AndroidKeyStoreBCWorkaroundProvider. See its Javadoc
- // for details.
-
- private static final String PACKAGE_NAME = "android.security.keystore";
-
- private static final String DESEDE_SYSTEM_PROPERTY =
- "ro.hardware.keystore_desede";
-
/** @hide */
- public AndroidKeyStoreProvider() {
- this(PROVIDER_NAME);
- }
-
- /** @hide **/
- public AndroidKeyStoreProvider(String providerName) {
- super(providerName, 1.0, "Android KeyStore security provider");
-
- boolean supports3DES = "true".equals(android.os.SystemProperties.get(DESEDE_SYSTEM_PROPERTY));
-
- // java.security.KeyStore
- put("KeyStore." + providerName, PACKAGE_NAME + ".AndroidKeyStoreSpi");
-
- // java.security.KeyPairGenerator
- put("KeyPairGenerator.EC", PACKAGE_NAME + ".AndroidKeyStoreKeyPairGeneratorSpi$EC");
- put("KeyPairGenerator.RSA", PACKAGE_NAME + ".AndroidKeyStoreKeyPairGeneratorSpi$RSA");
-
- // java.security.KeyFactory
- putKeyFactoryImpl("EC");
- putKeyFactoryImpl("RSA");
-
- // javax.crypto.KeyGenerator
- put("KeyGenerator.AES", PACKAGE_NAME + ".AndroidKeyStoreKeyGeneratorSpi$AES");
- put("KeyGenerator.HmacSHA1", PACKAGE_NAME + ".AndroidKeyStoreKeyGeneratorSpi$HmacSHA1");
- put("KeyGenerator.HmacSHA224", PACKAGE_NAME + ".AndroidKeyStoreKeyGeneratorSpi$HmacSHA224");
- put("KeyGenerator.HmacSHA256", PACKAGE_NAME + ".AndroidKeyStoreKeyGeneratorSpi$HmacSHA256");
- put("KeyGenerator.HmacSHA384", PACKAGE_NAME + ".AndroidKeyStoreKeyGeneratorSpi$HmacSHA384");
- put("KeyGenerator.HmacSHA512", PACKAGE_NAME + ".AndroidKeyStoreKeyGeneratorSpi$HmacSHA512");
-
- if (supports3DES) {
- put("KeyGenerator.DESede", PACKAGE_NAME + ".AndroidKeyStoreKeyGeneratorSpi$DESede");
- }
-
- // java.security.SecretKeyFactory
- putSecretKeyFactoryImpl("AES");
- if (supports3DES) {
- putSecretKeyFactoryImpl("DESede");
- }
- putSecretKeyFactoryImpl("HmacSHA1");
- putSecretKeyFactoryImpl("HmacSHA224");
- putSecretKeyFactoryImpl("HmacSHA256");
- putSecretKeyFactoryImpl("HmacSHA384");
- putSecretKeyFactoryImpl("HmacSHA512");
- }
-
- /**
- * This function indicates whether or not Keystore 2.0 is enabled. Some parts of the
- * Keystore SPI must behave subtly differently when Keystore 2.0 is enabled. However,
- * the platform property that indicates that Keystore 2.0 is enabled is not readable
- * by applications. So we set this value when {@code install()} is called because it
- * is called by zygote, which can access Keystore2Properties.
- *
- * This function can be removed once the transition to Keystore 2.0 is complete.
- * b/171305684
- *
- * @return true if Keystore 2.0 is enabled.
- * @hide
- */
- public static boolean isKeystore2Enabled() {
- return android.security.keystore2.AndroidKeyStoreProvider.isInstalled();
- }
-
- /**
- * Installs a new instance of this provider (and the
- * {@link AndroidKeyStoreBCWorkaroundProvider}).
- * @hide
- */
- public static void install() {
- Provider[] providers = Security.getProviders();
- int bcProviderIndex = -1;
- for (int i = 0; i < providers.length; i++) {
- Provider provider = providers[i];
- if ("BC".equals(provider.getName())) {
- bcProviderIndex = i;
- break;
- }
- }
-
- Security.addProvider(new AndroidKeyStoreProvider());
- Provider workaroundProvider = new AndroidKeyStoreBCWorkaroundProvider();
- if (bcProviderIndex != -1) {
- // Bouncy Castle provider found -- install the workaround provider above it.
- // insertProviderAt uses 1-based positions.
- Security.insertProviderAt(workaroundProvider, bcProviderIndex + 1);
- } else {
- // Bouncy Castle provider not found -- install the workaround provider at lowest
- // priority.
- Security.addProvider(workaroundProvider);
- }
- }
-
- private void putSecretKeyFactoryImpl(String algorithm) {
- put("SecretKeyFactory." + algorithm, PACKAGE_NAME + ".AndroidKeyStoreSecretKeyFactorySpi");
- }
-
- private void putKeyFactoryImpl(String algorithm) {
- put("KeyFactory." + algorithm, PACKAGE_NAME + ".AndroidKeyStoreKeyFactorySpi");
+ public AndroidKeyStoreProvider(@NonNull String name) {
+ super(name, 1.0, "Android KeyStore security provider");
+ throw new IllegalStateException("Should not be instantiated.");
}
/**
@@ -189,229 +65,7 @@
if (cryptoPrimitive == null) {
throw new NullPointerException();
}
- Object spi;
- if (cryptoPrimitive instanceof Signature) {
- spi = ((Signature) cryptoPrimitive).getCurrentSpi();
- } else if (cryptoPrimitive instanceof Mac) {
- spi = ((Mac) cryptoPrimitive).getCurrentSpi();
- } else if (cryptoPrimitive instanceof Cipher) {
- spi = ((Cipher) cryptoPrimitive).getCurrentSpi();
- } else {
- throw new IllegalArgumentException("Unsupported crypto primitive: " + cryptoPrimitive
- + ". Supported: Signature, Mac, Cipher");
- }
- if (spi == null) {
- throw new IllegalStateException("Crypto primitive not initialized");
- } else if (!(spi instanceof KeyStoreCryptoOperation)) {
- throw new IllegalArgumentException(
- "Crypto primitive not backed by AndroidKeyStore provider: " + cryptoPrimitive
- + ", spi: " + spi);
- }
- return ((KeyStoreCryptoOperation) spi).getOperationHandle();
- }
-
- /** @hide **/
- @NonNull
- public static AndroidKeyStorePublicKey getAndroidKeyStorePublicKey(
- @NonNull String alias,
- int uid,
- @NonNull @KeyProperties.KeyAlgorithmEnum String keyAlgorithm,
- @NonNull byte[] x509EncodedForm) {
- PublicKey publicKey;
- try {
- KeyFactory keyFactory = KeyFactory.getInstance(keyAlgorithm);
- publicKey = keyFactory.generatePublic(new X509EncodedKeySpec(x509EncodedForm));
- } catch (NoSuchAlgorithmException e) {
- throw new ProviderException(
- "Failed to obtain " + keyAlgorithm + " KeyFactory", e);
- } catch (InvalidKeySpecException e) {
- throw new ProviderException("Invalid X.509 encoding of public key", e);
- }
- if (KeyProperties.KEY_ALGORITHM_EC.equalsIgnoreCase(keyAlgorithm)) {
- return new AndroidKeyStoreECPublicKey(alias, uid, (ECPublicKey) publicKey);
- } else if (KeyProperties.KEY_ALGORITHM_RSA.equalsIgnoreCase(keyAlgorithm)) {
- return new AndroidKeyStoreRSAPublicKey(alias, uid, (RSAPublicKey) publicKey);
- } else {
- throw new ProviderException("Unsupported Android Keystore public key algorithm: "
- + keyAlgorithm);
- }
- }
-
- @NonNull
- private static AndroidKeyStorePrivateKey getAndroidKeyStorePrivateKey(
- @NonNull AndroidKeyStorePublicKey publicKey) {
- String keyAlgorithm = publicKey.getAlgorithm();
- if (KeyProperties.KEY_ALGORITHM_EC.equalsIgnoreCase(keyAlgorithm)) {
- return new AndroidKeyStoreECPrivateKey(
- publicKey.getAlias(), publicKey.getUid(), ((ECKey) publicKey).getParams());
- } else if (KeyProperties.KEY_ALGORITHM_RSA.equalsIgnoreCase(keyAlgorithm)) {
- return new AndroidKeyStoreRSAPrivateKey(
- publicKey.getAlias(), publicKey.getUid(), ((RSAKey) publicKey).getModulus());
- } else {
- throw new ProviderException("Unsupported Android Keystore public key algorithm: "
- + keyAlgorithm);
- }
- }
-
- @NonNull
- private static KeyCharacteristics getKeyCharacteristics(@NonNull KeyStore keyStore,
- @NonNull String alias, int uid)
- throws UnrecoverableKeyException, KeyPermanentlyInvalidatedException {
- KeyCharacteristics keyCharacteristics = new KeyCharacteristics();
- int errorCode = keyStore.getKeyCharacteristics(
- alias, null, null, uid, keyCharacteristics);
- if (errorCode == KeyStore.KEY_PERMANENTLY_INVALIDATED) {
- throw (KeyPermanentlyInvalidatedException)
- new KeyPermanentlyInvalidatedException(
- "User changed or deleted their auth credentials",
- KeyStore.getKeyStoreException(errorCode));
- }
- if (errorCode != KeyStore.NO_ERROR) {
- throw (UnrecoverableKeyException)
- new UnrecoverableKeyException("Failed to obtain information about key")
- .initCause(KeyStore.getKeyStoreException(errorCode));
- }
- return keyCharacteristics;
- }
-
- @NonNull
- private static AndroidKeyStorePublicKey loadAndroidKeyStorePublicKeyFromKeystore(
- @NonNull KeyStore keyStore, @NonNull String privateKeyAlias, int uid,
- KeyCharacteristics keyCharacteristics)
- throws UnrecoverableKeyException {
- ExportResult exportResult = keyStore.exportKey(
- privateKeyAlias, KeymasterDefs.KM_KEY_FORMAT_X509, null, null, uid);
- if (exportResult.resultCode != KeyStore.NO_ERROR) {
- throw (UnrecoverableKeyException)
- new UnrecoverableKeyException("Failed to obtain X.509 form of public key")
- .initCause(KeyStore.getKeyStoreException(exportResult.resultCode));
- }
- final byte[] x509EncodedPublicKey = exportResult.exportData;
-
- Integer keymasterAlgorithm = keyCharacteristics.getEnum(KeymasterDefs.KM_TAG_ALGORITHM);
- if (keymasterAlgorithm == null) {
- throw new UnrecoverableKeyException("Key algorithm unknown");
- }
-
- String jcaKeyAlgorithm;
- try {
- jcaKeyAlgorithm = KeyProperties.KeyAlgorithm.fromKeymasterAsymmetricKeyAlgorithm(
- keymasterAlgorithm);
- } catch (IllegalArgumentException e) {
- throw (UnrecoverableKeyException)
- new UnrecoverableKeyException("Failed to load private key")
- .initCause(e);
- }
-
- return AndroidKeyStoreProvider.getAndroidKeyStorePublicKey(
- privateKeyAlias, uid, jcaKeyAlgorithm, x509EncodedPublicKey);
- }
-
- /** @hide **/
- @NonNull
- public static AndroidKeyStorePublicKey loadAndroidKeyStorePublicKeyFromKeystore(
- @NonNull KeyStore keyStore, @NonNull String privateKeyAlias, int uid)
- throws UnrecoverableKeyException, KeyPermanentlyInvalidatedException {
- return loadAndroidKeyStorePublicKeyFromKeystore(keyStore, privateKeyAlias, uid,
- getKeyCharacteristics(keyStore, privateKeyAlias, uid));
- }
-
- @NonNull
- private static KeyPair loadAndroidKeyStoreKeyPairFromKeystore(
- @NonNull KeyStore keyStore, @NonNull String privateKeyAlias, int uid,
- @NonNull KeyCharacteristics keyCharacteristics)
- throws UnrecoverableKeyException {
- AndroidKeyStorePublicKey publicKey =
- loadAndroidKeyStorePublicKeyFromKeystore(keyStore, privateKeyAlias, uid,
- keyCharacteristics);
- AndroidKeyStorePrivateKey privateKey =
- AndroidKeyStoreProvider.getAndroidKeyStorePrivateKey(publicKey);
- return new KeyPair(publicKey, privateKey);
- }
-
- /** @hide **/
- @NonNull
- public static KeyPair loadAndroidKeyStoreKeyPairFromKeystore(
- @NonNull KeyStore keyStore, @NonNull String privateKeyAlias, int uid)
- throws UnrecoverableKeyException, KeyPermanentlyInvalidatedException {
- return loadAndroidKeyStoreKeyPairFromKeystore(keyStore, privateKeyAlias, uid,
- getKeyCharacteristics(keyStore, privateKeyAlias, uid));
- }
-
- @NonNull
- private static AndroidKeyStorePrivateKey loadAndroidKeyStorePrivateKeyFromKeystore(
- @NonNull KeyStore keyStore, @NonNull String privateKeyAlias, int uid,
- @NonNull KeyCharacteristics keyCharacteristics)
- throws UnrecoverableKeyException {
- KeyPair keyPair = loadAndroidKeyStoreKeyPairFromKeystore(keyStore, privateKeyAlias, uid,
- keyCharacteristics);
- return (AndroidKeyStorePrivateKey) keyPair.getPrivate();
- }
-
- /** @hide **/
- @NonNull
- public static AndroidKeyStorePrivateKey loadAndroidKeyStorePrivateKeyFromKeystore(
- @NonNull KeyStore keyStore, @NonNull String privateKeyAlias, int uid)
- throws UnrecoverableKeyException, KeyPermanentlyInvalidatedException {
- return loadAndroidKeyStorePrivateKeyFromKeystore(keyStore, privateKeyAlias, uid,
- getKeyCharacteristics(keyStore, privateKeyAlias, uid));
- }
-
- @NonNull
- private static AndroidKeyStoreSecretKey loadAndroidKeyStoreSecretKeyFromKeystore(
- @NonNull String secretKeyAlias, int uid, @NonNull KeyCharacteristics keyCharacteristics)
- throws UnrecoverableKeyException {
- Integer keymasterAlgorithm = keyCharacteristics.getEnum(KeymasterDefs.KM_TAG_ALGORITHM);
- if (keymasterAlgorithm == null) {
- throw new UnrecoverableKeyException("Key algorithm unknown");
- }
-
- List<Integer> keymasterDigests = keyCharacteristics.getEnums(KeymasterDefs.KM_TAG_DIGEST);
- int keymasterDigest;
- if (keymasterDigests.isEmpty()) {
- keymasterDigest = -1;
- } else {
- // More than one digest can be permitted for this key. Use the first one to form the
- // JCA key algorithm name.
- keymasterDigest = keymasterDigests.get(0);
- }
-
- @KeyProperties.KeyAlgorithmEnum String keyAlgorithmString;
- try {
- keyAlgorithmString = KeyProperties.KeyAlgorithm.fromKeymasterSecretKeyAlgorithm(
- keymasterAlgorithm, keymasterDigest);
- } catch (IllegalArgumentException e) {
- throw (UnrecoverableKeyException)
- new UnrecoverableKeyException("Unsupported secret key type").initCause(e);
- }
-
- return new AndroidKeyStoreSecretKey(secretKeyAlias, uid, keyAlgorithmString);
- }
-
- /** @hide **/
- @NonNull
- public static AndroidKeyStoreKey loadAndroidKeyStoreKeyFromKeystore(
- @NonNull KeyStore keyStore, @NonNull String userKeyAlias, int uid)
- throws UnrecoverableKeyException, KeyPermanentlyInvalidatedException {
- KeyCharacteristics keyCharacteristics = getKeyCharacteristics(keyStore, userKeyAlias, uid);
-
- Integer keymasterAlgorithm = keyCharacteristics.getEnum(KeymasterDefs.KM_TAG_ALGORITHM);
- if (keymasterAlgorithm == null) {
- throw new UnrecoverableKeyException("Key algorithm unknown");
- }
-
- if (keymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_HMAC ||
- keymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_AES ||
- keymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_3DES) {
- return loadAndroidKeyStoreSecretKeyFromKeystore(userKeyAlias, uid,
- keyCharacteristics);
- } else if (keymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_RSA ||
- keymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_EC) {
- return loadAndroidKeyStorePrivateKeyFromKeystore(keyStore, userKeyAlias, uid,
- keyCharacteristics);
- } else {
- throw new UnrecoverableKeyException("Key algorithm unknown");
- }
+ return 0;
}
/**
@@ -434,13 +88,9 @@
@NonNull
public static java.security.KeyStore getKeyStoreForUid(int uid)
throws KeyStoreException, NoSuchProviderException {
- final java.security.KeyStore.LoadStoreParameter loadParameter;
- if (android.security.keystore2.AndroidKeyStoreProvider.isInstalled()) {
- loadParameter = new android.security.keystore2.AndroidKeyStoreLoadStoreParameter(
- KeyProperties.legacyUidToNamespace(uid));
- } else {
- loadParameter = new AndroidKeyStoreLoadStoreParameter(uid);
- }
+ final java.security.KeyStore.LoadStoreParameter loadParameter =
+ new android.security.keystore2.AndroidKeyStoreLoadStoreParameter(
+ KeyProperties.legacyUidToNamespace(uid));
java.security.KeyStore result = java.security.KeyStore.getInstance(PROVIDER_NAME);
try {
result.load(loadParameter);
diff --git a/keystore/java/android/security/keystore/AndroidKeyStorePublicKey.java b/keystore/java/android/security/keystore/AndroidKeyStorePublicKey.java
deleted file mode 100644
index 4194780..0000000
--- a/keystore/java/android/security/keystore/AndroidKeyStorePublicKey.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.keystore;
-
-import java.security.PublicKey;
-import java.util.Arrays;
-
-/**
- * {@link PublicKey} backed by Android Keystore.
- *
- * @hide
- */
-public class AndroidKeyStorePublicKey extends AndroidKeyStoreKey implements PublicKey {
-
- private final byte[] mEncoded;
-
- public AndroidKeyStorePublicKey(String alias, int uid, String algorithm, byte[] x509EncodedForm) {
- super(alias, uid, algorithm);
- mEncoded = ArrayUtils.cloneIfNotEmpty(x509EncodedForm);
- }
-
- @Override
- public String getFormat() {
- return "X.509";
- }
-
- @Override
- public byte[] getEncoded() {
- return ArrayUtils.cloneIfNotEmpty(mEncoded);
- }
-
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = super.hashCode();
- result = prime * result + Arrays.hashCode(mEncoded);
- return result;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
- if (!super.equals(obj)) {
- return false;
- }
- if (getClass() != obj.getClass()) {
- return false;
- }
- AndroidKeyStorePublicKey other = (AndroidKeyStorePublicKey) obj;
- if (!Arrays.equals(mEncoded, other.mEncoded)) {
- return false;
- }
- return true;
- }
-}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreRSACipherSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreRSACipherSpi.java
deleted file mode 100644
index 2ae68fa..0000000
--- a/keystore/java/android/security/keystore/AndroidKeyStoreRSACipherSpi.java
+++ /dev/null
@@ -1,515 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.keystore;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.security.KeyStore;
-import android.security.keymaster.KeyCharacteristics;
-import android.security.keymaster.KeymasterArguments;
-import android.security.keymaster.KeymasterDefs;
-
-import java.security.AlgorithmParameters;
-import java.security.InvalidAlgorithmParameterException;
-import java.security.InvalidKeyException;
-import java.security.Key;
-import java.security.NoSuchAlgorithmException;
-import java.security.PrivateKey;
-import java.security.ProviderException;
-import java.security.spec.AlgorithmParameterSpec;
-import java.security.spec.InvalidParameterSpecException;
-import java.security.spec.MGF1ParameterSpec;
-
-import javax.crypto.Cipher;
-import javax.crypto.CipherSpi;
-import javax.crypto.spec.OAEPParameterSpec;
-import javax.crypto.spec.PSource;
-
-/**
- * Base class for {@link CipherSpi} providing Android KeyStore backed RSA encryption/decryption.
- *
- * @hide
- */
-abstract class AndroidKeyStoreRSACipherSpi extends AndroidKeyStoreCipherSpiBase {
-
- /**
- * Raw RSA cipher without any padding.
- */
- public static final class NoPadding extends AndroidKeyStoreRSACipherSpi {
- public NoPadding() {
- super(KeymasterDefs.KM_PAD_NONE);
- }
-
- @Override
- protected boolean adjustConfigForEncryptingWithPrivateKey() {
- // RSA encryption with no padding using private key is a way to implement raw RSA
- // signatures which JCA does not expose via Signature. We thus have to support this.
- setKeymasterPurposeOverride(KeymasterDefs.KM_PURPOSE_SIGN);
- return true;
- }
-
- @Override
- protected void initAlgorithmSpecificParameters() throws InvalidKeyException {}
-
- @Override
- protected void initAlgorithmSpecificParameters(@Nullable AlgorithmParameterSpec params)
- throws InvalidAlgorithmParameterException {
- if (params != null) {
- throw new InvalidAlgorithmParameterException(
- "Unexpected parameters: " + params + ". No parameters supported");
- }
- }
-
- @Override
- protected void initAlgorithmSpecificParameters(@Nullable AlgorithmParameters params)
- throws InvalidAlgorithmParameterException {
-
- if (params != null) {
- throw new InvalidAlgorithmParameterException(
- "Unexpected parameters: " + params + ". No parameters supported");
- }
- }
-
- @Override
- protected AlgorithmParameters engineGetParameters() {
- return null;
- }
-
- @Override
- protected final int getAdditionalEntropyAmountForBegin() {
- return 0;
- }
-
- @Override
- protected final int getAdditionalEntropyAmountForFinish() {
- return 0;
- }
- }
-
- /**
- * RSA cipher with PKCS#1 v1.5 encryption padding.
- */
- public static final class PKCS1Padding extends AndroidKeyStoreRSACipherSpi {
- public PKCS1Padding() {
- super(KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_ENCRYPT);
- }
-
- @Override
- protected boolean adjustConfigForEncryptingWithPrivateKey() {
- // RSA encryption with PCKS#1 padding using private key is a way to implement RSA
- // signatures with PKCS#1 padding. We have to support this for legacy reasons.
- setKeymasterPurposeOverride(KeymasterDefs.KM_PURPOSE_SIGN);
- setKeymasterPaddingOverride(KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_SIGN);
- return true;
- }
-
- @Override
- protected void initAlgorithmSpecificParameters() throws InvalidKeyException {}
-
- @Override
- protected void initAlgorithmSpecificParameters(@Nullable AlgorithmParameterSpec params)
- throws InvalidAlgorithmParameterException {
- if (params != null) {
- throw new InvalidAlgorithmParameterException(
- "Unexpected parameters: " + params + ". No parameters supported");
- }
- }
-
- @Override
- protected void initAlgorithmSpecificParameters(@Nullable AlgorithmParameters params)
- throws InvalidAlgorithmParameterException {
-
- if (params != null) {
- throw new InvalidAlgorithmParameterException(
- "Unexpected parameters: " + params + ". No parameters supported");
- }
- }
-
- @Override
- protected AlgorithmParameters engineGetParameters() {
- return null;
- }
-
- @Override
- protected final int getAdditionalEntropyAmountForBegin() {
- return 0;
- }
-
- @Override
- protected final int getAdditionalEntropyAmountForFinish() {
- return (isEncrypting()) ? getModulusSizeBytes() : 0;
- }
- }
-
- /**
- * RSA cipher with OAEP encryption padding. Only SHA-1 based MGF1 is supported as MGF.
- */
- abstract static class OAEPWithMGF1Padding extends AndroidKeyStoreRSACipherSpi {
-
- private static final String MGF_ALGORITGM_MGF1 = "MGF1";
-
- private int mKeymasterDigest = -1;
- private int mDigestOutputSizeBytes;
-
- OAEPWithMGF1Padding(int keymasterDigest) {
- super(KeymasterDefs.KM_PAD_RSA_OAEP);
- mKeymasterDigest = keymasterDigest;
- mDigestOutputSizeBytes =
- (KeymasterUtils.getDigestOutputSizeBits(keymasterDigest) + 7) / 8;
- }
-
- @Override
- protected final void initAlgorithmSpecificParameters() throws InvalidKeyException {}
-
- @Override
- protected final void initAlgorithmSpecificParameters(
- @Nullable AlgorithmParameterSpec params) throws InvalidAlgorithmParameterException {
- if (params == null) {
- return;
- }
-
- if (!(params instanceof OAEPParameterSpec)) {
- throw new InvalidAlgorithmParameterException(
- "Unsupported parameter spec: " + params
- + ". Only OAEPParameterSpec supported");
- }
- OAEPParameterSpec spec = (OAEPParameterSpec) params;
- if (!MGF_ALGORITGM_MGF1.equalsIgnoreCase(spec.getMGFAlgorithm())) {
- throw new InvalidAlgorithmParameterException(
- "Unsupported MGF: " + spec.getMGFAlgorithm()
- + ". Only " + MGF_ALGORITGM_MGF1 + " supported");
- }
- String jcaDigest = spec.getDigestAlgorithm();
- int keymasterDigest;
- try {
- keymasterDigest = KeyProperties.Digest.toKeymaster(jcaDigest);
- } catch (IllegalArgumentException e) {
- throw new InvalidAlgorithmParameterException(
- "Unsupported digest: " + jcaDigest, e);
- }
- switch (keymasterDigest) {
- case KeymasterDefs.KM_DIGEST_SHA1:
- case KeymasterDefs.KM_DIGEST_SHA_2_224:
- case KeymasterDefs.KM_DIGEST_SHA_2_256:
- case KeymasterDefs.KM_DIGEST_SHA_2_384:
- case KeymasterDefs.KM_DIGEST_SHA_2_512:
- // Permitted.
- break;
- default:
- throw new InvalidAlgorithmParameterException(
- "Unsupported digest: " + jcaDigest);
- }
- AlgorithmParameterSpec mgfParams = spec.getMGFParameters();
- if (mgfParams == null) {
- throw new InvalidAlgorithmParameterException("MGF parameters must be provided");
- }
- // Check whether MGF parameters match the OAEPParameterSpec
- if (!(mgfParams instanceof MGF1ParameterSpec)) {
- throw new InvalidAlgorithmParameterException("Unsupported MGF parameters"
- + ": " + mgfParams + ". Only MGF1ParameterSpec supported");
- }
- MGF1ParameterSpec mgfSpec = (MGF1ParameterSpec) mgfParams;
- String mgf1JcaDigest = mgfSpec.getDigestAlgorithm();
- if (!KeyProperties.DIGEST_SHA1.equalsIgnoreCase(mgf1JcaDigest)) {
- throw new InvalidAlgorithmParameterException(
- "Unsupported MGF1 digest: " + mgf1JcaDigest
- + ". Only " + KeyProperties.DIGEST_SHA1 + " supported");
- }
- PSource pSource = spec.getPSource();
- if (!(pSource instanceof PSource.PSpecified)) {
- throw new InvalidAlgorithmParameterException(
- "Unsupported source of encoding input P: " + pSource
- + ". Only pSpecifiedEmpty (PSource.PSpecified.DEFAULT) supported");
- }
- PSource.PSpecified pSourceSpecified = (PSource.PSpecified) pSource;
- byte[] pSourceValue = pSourceSpecified.getValue();
- if ((pSourceValue != null) && (pSourceValue.length > 0)) {
- throw new InvalidAlgorithmParameterException(
- "Unsupported source of encoding input P: " + pSource
- + ". Only pSpecifiedEmpty (PSource.PSpecified.DEFAULT) supported");
- }
- mKeymasterDigest = keymasterDigest;
- mDigestOutputSizeBytes =
- (KeymasterUtils.getDigestOutputSizeBits(keymasterDigest) + 7) / 8;
- }
-
- @Override
- protected final void initAlgorithmSpecificParameters(@Nullable AlgorithmParameters params)
- throws InvalidAlgorithmParameterException {
- if (params == null) {
- return;
- }
-
- OAEPParameterSpec spec;
- try {
- spec = params.getParameterSpec(OAEPParameterSpec.class);
- } catch (InvalidParameterSpecException e) {
- throw new InvalidAlgorithmParameterException("OAEP parameters required"
- + ", but not found in parameters: " + params, e);
- }
- if (spec == null) {
- throw new InvalidAlgorithmParameterException("OAEP parameters required"
- + ", but not provided in parameters: " + params);
- }
- initAlgorithmSpecificParameters(spec);
- }
-
- @Override
- protected final AlgorithmParameters engineGetParameters() {
- OAEPParameterSpec spec =
- new OAEPParameterSpec(
- KeyProperties.Digest.fromKeymaster(mKeymasterDigest),
- MGF_ALGORITGM_MGF1,
- MGF1ParameterSpec.SHA1,
- PSource.PSpecified.DEFAULT);
- try {
- AlgorithmParameters params = AlgorithmParameters.getInstance("OAEP");
- params.init(spec);
- return params;
- } catch (NoSuchAlgorithmException e) {
- throw new ProviderException(
- "Failed to obtain OAEP AlgorithmParameters", e);
- } catch (InvalidParameterSpecException e) {
- throw new ProviderException(
- "Failed to initialize OAEP AlgorithmParameters with an IV",
- e);
- }
- }
-
- @Override
- protected final void addAlgorithmSpecificParametersToBegin(
- KeymasterArguments keymasterArgs) {
- super.addAlgorithmSpecificParametersToBegin(keymasterArgs);
- keymasterArgs.addEnum(KeymasterDefs.KM_TAG_DIGEST, mKeymasterDigest);
- }
-
- @Override
- protected final void loadAlgorithmSpecificParametersFromBeginResult(
- @NonNull KeymasterArguments keymasterArgs) {
- super.loadAlgorithmSpecificParametersFromBeginResult(keymasterArgs);
- }
-
- @Override
- protected final int getAdditionalEntropyAmountForBegin() {
- return 0;
- }
-
- @Override
- protected final int getAdditionalEntropyAmountForFinish() {
- return (isEncrypting()) ? mDigestOutputSizeBytes : 0;
- }
- }
-
- public static class OAEPWithSHA1AndMGF1Padding extends OAEPWithMGF1Padding {
- public OAEPWithSHA1AndMGF1Padding() {
- super(KeymasterDefs.KM_DIGEST_SHA1);
- }
- }
-
- public static class OAEPWithSHA224AndMGF1Padding extends OAEPWithMGF1Padding {
- public OAEPWithSHA224AndMGF1Padding() {
- super(KeymasterDefs.KM_DIGEST_SHA_2_224);
- }
- }
-
- public static class OAEPWithSHA256AndMGF1Padding extends OAEPWithMGF1Padding {
- public OAEPWithSHA256AndMGF1Padding() {
- super(KeymasterDefs.KM_DIGEST_SHA_2_256);
- }
- }
-
- public static class OAEPWithSHA384AndMGF1Padding extends OAEPWithMGF1Padding {
- public OAEPWithSHA384AndMGF1Padding() {
- super(KeymasterDefs.KM_DIGEST_SHA_2_384);
- }
- }
-
- public static class OAEPWithSHA512AndMGF1Padding extends OAEPWithMGF1Padding {
- public OAEPWithSHA512AndMGF1Padding() {
- super(KeymasterDefs.KM_DIGEST_SHA_2_512);
- }
- }
-
- private final int mKeymasterPadding;
- private int mKeymasterPaddingOverride;
-
- private int mModulusSizeBytes = -1;
-
- AndroidKeyStoreRSACipherSpi(int keymasterPadding) {
- mKeymasterPadding = keymasterPadding;
- }
-
- @Override
- protected final void initKey(int opmode, Key key) throws InvalidKeyException {
- if (key == null) {
- throw new InvalidKeyException("Unsupported key: null");
- }
- if (!KeyProperties.KEY_ALGORITHM_RSA.equalsIgnoreCase(key.getAlgorithm())) {
- throw new InvalidKeyException("Unsupported key algorithm: " + key.getAlgorithm()
- + ". Only " + KeyProperties.KEY_ALGORITHM_RSA + " supported");
- }
- AndroidKeyStoreKey keystoreKey;
- if (key instanceof AndroidKeyStorePrivateKey) {
- keystoreKey = (AndroidKeyStoreKey) key;
- } else if (key instanceof AndroidKeyStorePublicKey) {
- keystoreKey = (AndroidKeyStoreKey) key;
- } else {
- throw new InvalidKeyException("Unsupported key type: " + key);
- }
-
- if (keystoreKey instanceof PrivateKey) {
- // Private key
- switch (opmode) {
- case Cipher.DECRYPT_MODE:
- case Cipher.UNWRAP_MODE:
- // Permitted
- break;
- case Cipher.ENCRYPT_MODE:
- case Cipher.WRAP_MODE:
- if (!adjustConfigForEncryptingWithPrivateKey()) {
- throw new InvalidKeyException(
- "RSA private keys cannot be used with " + opmodeToString(opmode)
- + " and padding "
- + KeyProperties.EncryptionPadding.fromKeymaster(mKeymasterPadding)
- + ". Only RSA public keys supported for this mode");
- }
- break;
- default:
- throw new InvalidKeyException(
- "RSA private keys cannot be used with opmode: " + opmode);
- }
- } else {
- // Public key
- switch (opmode) {
- case Cipher.ENCRYPT_MODE:
- case Cipher.WRAP_MODE:
- // Permitted
- break;
- case Cipher.DECRYPT_MODE:
- case Cipher.UNWRAP_MODE:
- throw new InvalidKeyException(
- "RSA public keys cannot be used with " + opmodeToString(opmode)
- + " and padding "
- + KeyProperties.EncryptionPadding.fromKeymaster(mKeymasterPadding)
- + ". Only RSA private keys supported for this opmode.");
- // break;
- default:
- throw new InvalidKeyException(
- "RSA public keys cannot be used with " + opmodeToString(opmode));
- }
- }
-
- KeyCharacteristics keyCharacteristics = new KeyCharacteristics();
- int errorCode = getKeyStore().getKeyCharacteristics(
- keystoreKey.getAlias(), null, null, keystoreKey.getUid(), keyCharacteristics);
- if (errorCode != KeyStore.NO_ERROR) {
- throw getKeyStore().getInvalidKeyException(
- keystoreKey.getAlias(), keystoreKey.getUid(), errorCode);
- }
- long keySizeBits = keyCharacteristics.getUnsignedInt(KeymasterDefs.KM_TAG_KEY_SIZE, -1);
- if (keySizeBits == -1) {
- throw new InvalidKeyException("Size of key not known");
- } else if (keySizeBits > Integer.MAX_VALUE) {
- throw new InvalidKeyException("Key too large: " + keySizeBits + " bits");
- }
- mModulusSizeBytes = (int) ((keySizeBits + 7) / 8);
-
- setKey(keystoreKey);
- }
-
- /**
- * Adjusts the configuration of this cipher for encrypting using the private key.
- *
- * <p>The default implementation does nothing and refuses to adjust the configuration.
- *
- * @return {@code true} if the configuration has been adjusted, {@code false} if encrypting
- * using private key is not permitted for this cipher.
- */
- protected boolean adjustConfigForEncryptingWithPrivateKey() {
- return false;
- }
-
- @Override
- protected final void resetAll() {
- mModulusSizeBytes = -1;
- mKeymasterPaddingOverride = -1;
- super.resetAll();
- }
-
- @Override
- protected final void resetWhilePreservingInitState() {
- super.resetWhilePreservingInitState();
- }
-
- @Override
- protected void addAlgorithmSpecificParametersToBegin(
- @NonNull KeymasterArguments keymasterArgs) {
- keymasterArgs.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_RSA);
- int keymasterPadding = getKeymasterPaddingOverride();
- if (keymasterPadding == -1) {
- keymasterPadding = mKeymasterPadding;
- }
- keymasterArgs.addEnum(KeymasterDefs.KM_TAG_PADDING, keymasterPadding);
- int purposeOverride = getKeymasterPurposeOverride();
- if ((purposeOverride != -1)
- && ((purposeOverride == KeymasterDefs.KM_PURPOSE_SIGN)
- || (purposeOverride == KeymasterDefs.KM_PURPOSE_VERIFY))) {
- // Keymaster sign/verify requires digest to be specified. For raw sign/verify it's NONE.
- keymasterArgs.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_NONE);
- }
- }
-
- @Override
- protected void loadAlgorithmSpecificParametersFromBeginResult(
- @NonNull KeymasterArguments keymasterArgs) {
- }
-
- @Override
- protected final int engineGetBlockSize() {
- // Not a block cipher, according to the RI
- return 0;
- }
-
- @Override
- protected final byte[] engineGetIV() {
- // IV never used
- return null;
- }
-
- @Override
- protected final int engineGetOutputSize(int inputLen) {
- return getModulusSizeBytes();
- }
-
- protected final int getModulusSizeBytes() {
- if (mModulusSizeBytes == -1) {
- throw new IllegalStateException("Not initialized");
- }
- return mModulusSizeBytes;
- }
-
- /**
- * Overrides the default padding of the crypto operation.
- */
- protected final void setKeymasterPaddingOverride(int keymasterPadding) {
- mKeymasterPaddingOverride = keymasterPadding;
- }
-
- protected final int getKeymasterPaddingOverride() {
- return mKeymasterPaddingOverride;
- }
-}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreRSAPrivateKey.java b/keystore/java/android/security/keystore/AndroidKeyStoreRSAPrivateKey.java
deleted file mode 100644
index adb3922..0000000
--- a/keystore/java/android/security/keystore/AndroidKeyStoreRSAPrivateKey.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.keystore;
-
-import java.math.BigInteger;
-import java.security.PrivateKey;
-import java.security.interfaces.RSAKey;
-
-/**
- * RSA private key (instance of {@link PrivateKey} and {@link RSAKey}) backed by keystore.
- *
- * @hide
- */
-public class AndroidKeyStoreRSAPrivateKey extends AndroidKeyStorePrivateKey implements RSAKey {
-
- private final BigInteger mModulus;
-
- public AndroidKeyStoreRSAPrivateKey(String alias, int uid, BigInteger modulus) {
- super(alias, uid, KeyProperties.KEY_ALGORITHM_RSA);
- mModulus = modulus;
- }
-
- @Override
- public BigInteger getModulus() {
- return mModulus;
- }
-}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreRSAPublicKey.java b/keystore/java/android/security/keystore/AndroidKeyStoreRSAPublicKey.java
deleted file mode 100644
index d85aace..0000000
--- a/keystore/java/android/security/keystore/AndroidKeyStoreRSAPublicKey.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.keystore;
-
-import java.math.BigInteger;
-import java.security.interfaces.RSAPublicKey;
-
-/**
- * {@link RSAPublicKey} backed by Android Keystore.
- *
- * @hide
- */
-public class AndroidKeyStoreRSAPublicKey extends AndroidKeyStorePublicKey implements RSAPublicKey {
- private final BigInteger mModulus;
- private final BigInteger mPublicExponent;
-
- public AndroidKeyStoreRSAPublicKey(String alias, int uid, byte[] x509EncodedForm, BigInteger modulus,
- BigInteger publicExponent) {
- super(alias, uid, KeyProperties.KEY_ALGORITHM_RSA, x509EncodedForm);
- mModulus = modulus;
- mPublicExponent = publicExponent;
- }
-
- public AndroidKeyStoreRSAPublicKey(String alias, int uid, RSAPublicKey info) {
- this(alias, uid, info.getEncoded(), info.getModulus(), info.getPublicExponent());
- if (!"X.509".equalsIgnoreCase(info.getFormat())) {
- throw new IllegalArgumentException(
- "Unsupported key export format: " + info.getFormat());
- }
- }
-
- @Override
- public BigInteger getModulus() {
- return mModulus;
- }
-
- @Override
- public BigInteger getPublicExponent() {
- return mPublicExponent;
- }
-}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreRSASignatureSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreRSASignatureSpi.java
deleted file mode 100644
index ecfc97e..0000000
--- a/keystore/java/android/security/keystore/AndroidKeyStoreRSASignatureSpi.java
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.keystore;
-
-import android.annotation.NonNull;
-import android.security.keymaster.KeymasterArguments;
-import android.security.keymaster.KeymasterDefs;
-
-import java.security.InvalidKeyException;
-import java.security.SignatureSpi;
-
-/**
- * Base class for {@link SignatureSpi} providing Android KeyStore backed RSA signatures.
- *
- * @hide
- */
-abstract class AndroidKeyStoreRSASignatureSpi extends AndroidKeyStoreSignatureSpiBase {
-
- abstract static class PKCS1Padding extends AndroidKeyStoreRSASignatureSpi {
- PKCS1Padding(int keymasterDigest) {
- super(keymasterDigest, KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_SIGN);
- }
-
- @Override
- protected final int getAdditionalEntropyAmountForSign() {
- // No entropy required for this deterministic signature scheme.
- return 0;
- }
- }
-
- public static final class NONEWithPKCS1Padding extends PKCS1Padding {
- public NONEWithPKCS1Padding() {
- super(KeymasterDefs.KM_DIGEST_NONE);
- }
- }
-
- public static final class MD5WithPKCS1Padding extends PKCS1Padding {
- public MD5WithPKCS1Padding() {
- super(KeymasterDefs.KM_DIGEST_MD5);
- }
- }
-
- public static final class SHA1WithPKCS1Padding extends PKCS1Padding {
- public SHA1WithPKCS1Padding() {
- super(KeymasterDefs.KM_DIGEST_SHA1);
- }
- }
-
- public static final class SHA224WithPKCS1Padding extends PKCS1Padding {
- public SHA224WithPKCS1Padding() {
- super(KeymasterDefs.KM_DIGEST_SHA_2_224);
- }
- }
-
- public static final class SHA256WithPKCS1Padding extends PKCS1Padding {
- public SHA256WithPKCS1Padding() {
- super(KeymasterDefs.KM_DIGEST_SHA_2_256);
- }
- }
-
- public static final class SHA384WithPKCS1Padding extends PKCS1Padding {
- public SHA384WithPKCS1Padding() {
- super(KeymasterDefs.KM_DIGEST_SHA_2_384);
- }
- }
-
- public static final class SHA512WithPKCS1Padding extends PKCS1Padding {
- public SHA512WithPKCS1Padding() {
- super(KeymasterDefs.KM_DIGEST_SHA_2_512);
- }
- }
-
- abstract static class PSSPadding extends AndroidKeyStoreRSASignatureSpi {
- private static final int SALT_LENGTH_BYTES = 20;
-
- PSSPadding(int keymasterDigest) {
- super(keymasterDigest, KeymasterDefs.KM_PAD_RSA_PSS);
- }
-
- @Override
- protected final int getAdditionalEntropyAmountForSign() {
- return SALT_LENGTH_BYTES;
- }
- }
-
- public static final class SHA1WithPSSPadding extends PSSPadding {
- public SHA1WithPSSPadding() {
- super(KeymasterDefs.KM_DIGEST_SHA1);
- }
- }
-
- public static final class SHA224WithPSSPadding extends PSSPadding {
- public SHA224WithPSSPadding() {
- super(KeymasterDefs.KM_DIGEST_SHA_2_224);
- }
- }
-
- public static final class SHA256WithPSSPadding extends PSSPadding {
- public SHA256WithPSSPadding() {
- super(KeymasterDefs.KM_DIGEST_SHA_2_256);
- }
- }
-
- public static final class SHA384WithPSSPadding extends PSSPadding {
- public SHA384WithPSSPadding() {
- super(KeymasterDefs.KM_DIGEST_SHA_2_384);
- }
- }
-
- public static final class SHA512WithPSSPadding extends PSSPadding {
- public SHA512WithPSSPadding() {
- super(KeymasterDefs.KM_DIGEST_SHA_2_512);
- }
- }
-
- private final int mKeymasterDigest;
- private final int mKeymasterPadding;
-
- AndroidKeyStoreRSASignatureSpi(int keymasterDigest, int keymasterPadding) {
- mKeymasterDigest = keymasterDigest;
- mKeymasterPadding = keymasterPadding;
- }
-
- @Override
- protected final void initKey(AndroidKeyStoreKey key) throws InvalidKeyException {
- if (!KeyProperties.KEY_ALGORITHM_RSA.equalsIgnoreCase(key.getAlgorithm())) {
- throw new InvalidKeyException("Unsupported key algorithm: " + key.getAlgorithm()
- + ". Only" + KeyProperties.KEY_ALGORITHM_RSA + " supported");
- }
- super.initKey(key);
- }
-
- @Override
- protected final void resetAll() {
- super.resetAll();
- }
-
- @Override
- protected final void resetWhilePreservingInitState() {
- super.resetWhilePreservingInitState();
- }
-
- @Override
- protected final void addAlgorithmSpecificParametersToBegin(
- @NonNull KeymasterArguments keymasterArgs) {
- keymasterArgs.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_RSA);
- keymasterArgs.addEnum(KeymasterDefs.KM_TAG_DIGEST, mKeymasterDigest);
- keymasterArgs.addEnum(KeymasterDefs.KM_TAG_PADDING, mKeymasterPadding);
- }
-}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreSecretKey.java b/keystore/java/android/security/keystore/AndroidKeyStoreSecretKey.java
deleted file mode 100644
index b8e6af7..0000000
--- a/keystore/java/android/security/keystore/AndroidKeyStoreSecretKey.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.keystore;
-
-import javax.crypto.SecretKey;
-
-/**
- * {@link SecretKey} backed by Android Keystore.
- *
- * @hide
- */
-public class AndroidKeyStoreSecretKey extends AndroidKeyStoreKey implements SecretKey {
-
- public AndroidKeyStoreSecretKey(String alias, int uid, String algorithm) {
- super(alias, uid, algorithm);
- }
-}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreSecretKeyFactorySpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreSecretKeyFactorySpi.java
deleted file mode 100644
index d2678c7..0000000
--- a/keystore/java/android/security/keystore/AndroidKeyStoreSecretKeyFactorySpi.java
+++ /dev/null
@@ -1,248 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.keystore;
-
-import android.security.Credentials;
-import android.security.GateKeeper;
-import android.security.KeyStore;
-import android.security.keymaster.KeyCharacteristics;
-import android.security.keymaster.KeymasterDefs;
-
-import java.math.BigInteger;
-import java.security.InvalidKeyException;
-import java.security.ProviderException;
-import java.security.spec.InvalidKeySpecException;
-import java.security.spec.KeySpec;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
-
-import javax.crypto.SecretKey;
-import javax.crypto.SecretKeyFactorySpi;
-import javax.crypto.spec.SecretKeySpec;
-
-/**
- * {@link SecretKeyFactorySpi} backed by Android Keystore.
- *
- * @hide
- */
-public class AndroidKeyStoreSecretKeyFactorySpi extends SecretKeyFactorySpi {
-
- private final KeyStore mKeyStore = KeyStore.getInstance();
-
- @Override
- protected KeySpec engineGetKeySpec(SecretKey key,
- @SuppressWarnings("rawtypes") Class keySpecClass) throws InvalidKeySpecException {
- if (keySpecClass == null) {
- throw new InvalidKeySpecException("keySpecClass == null");
- }
- if (!(key instanceof AndroidKeyStoreSecretKey)) {
- throw new InvalidKeySpecException("Only Android KeyStore secret keys supported: " +
- ((key != null) ? key.getClass().getName() : "null"));
- }
- if (SecretKeySpec.class.isAssignableFrom(keySpecClass)) {
- throw new InvalidKeySpecException(
- "Key material export of Android KeyStore keys is not supported");
- }
- if (!KeyInfo.class.equals(keySpecClass)) {
- throw new InvalidKeySpecException("Unsupported key spec: " + keySpecClass.getName());
- }
- AndroidKeyStoreKey keystoreKey = (AndroidKeyStoreKey) key;
- String keyAliasInKeystore = keystoreKey.getAlias();
- String entryAlias;
- if (keyAliasInKeystore.startsWith(Credentials.USER_PRIVATE_KEY)) {
- entryAlias = keyAliasInKeystore.substring(Credentials.USER_PRIVATE_KEY.length());
- } else if (keyAliasInKeystore.startsWith(Credentials.USER_SECRET_KEY)){
- // key has legacy prefix
- entryAlias = keyAliasInKeystore.substring(Credentials.USER_SECRET_KEY.length());
- } else {
- throw new InvalidKeySpecException("Invalid key alias: " + keyAliasInKeystore);
- }
-
- return getKeyInfo(mKeyStore, entryAlias, keyAliasInKeystore, keystoreKey.getUid());
- }
-
- static KeyInfo getKeyInfo(KeyStore keyStore, String entryAlias, String keyAliasInKeystore,
- int keyUid) {
- KeyCharacteristics keyCharacteristics = new KeyCharacteristics();
- int errorCode = keyStore.getKeyCharacteristics(
- keyAliasInKeystore, null, null, keyUid, keyCharacteristics);
- if (errorCode != KeyStore.NO_ERROR) {
- throw new ProviderException("Failed to obtain information about key."
- + " Keystore error: " + errorCode);
- }
-
- boolean insideSecureHardware;
- @KeyProperties.OriginEnum int origin;
- int keySize;
- @KeyProperties.PurposeEnum int purposes;
- String[] encryptionPaddings;
- String[] signaturePaddings;
- @KeyProperties.DigestEnum String[] digests;
- @KeyProperties.BlockModeEnum String[] blockModes;
- int keymasterSwEnforcedUserAuthenticators;
- int keymasterHwEnforcedUserAuthenticators;
- List<BigInteger> keymasterSecureUserIds;
- try {
- if (keyCharacteristics.hwEnforced.containsTag(KeymasterDefs.KM_TAG_ORIGIN)) {
- insideSecureHardware = true;
- origin = KeyProperties.Origin.fromKeymaster(
- keyCharacteristics.hwEnforced.getEnum(KeymasterDefs.KM_TAG_ORIGIN, -1));
- } else if (keyCharacteristics.swEnforced.containsTag(KeymasterDefs.KM_TAG_ORIGIN)) {
- insideSecureHardware = false;
- origin = KeyProperties.Origin.fromKeymaster(
- keyCharacteristics.swEnforced.getEnum(KeymasterDefs.KM_TAG_ORIGIN, -1));
- } else {
- throw new ProviderException("Key origin not available");
- }
- long keySizeUnsigned =
- keyCharacteristics.getUnsignedInt(KeymasterDefs.KM_TAG_KEY_SIZE, -1);
- if (keySizeUnsigned == -1) {
- throw new ProviderException("Key size not available");
- } else if (keySizeUnsigned > Integer.MAX_VALUE) {
- throw new ProviderException("Key too large: " + keySizeUnsigned + " bits");
- }
- keySize = (int) keySizeUnsigned;
- purposes = KeyProperties.Purpose.allFromKeymaster(
- keyCharacteristics.getEnums(KeymasterDefs.KM_TAG_PURPOSE));
-
- List<String> encryptionPaddingsList = new ArrayList<String>();
- List<String> signaturePaddingsList = new ArrayList<String>();
- // Keymaster stores both types of paddings in the same array -- we split it into two.
- for (int keymasterPadding : keyCharacteristics.getEnums(KeymasterDefs.KM_TAG_PADDING)) {
- try {
- @KeyProperties.EncryptionPaddingEnum String jcaPadding =
- KeyProperties.EncryptionPadding.fromKeymaster(keymasterPadding);
- encryptionPaddingsList.add(jcaPadding);
- } catch (IllegalArgumentException e) {
- try {
- @KeyProperties.SignaturePaddingEnum String padding =
- KeyProperties.SignaturePadding.fromKeymaster(keymasterPadding);
- signaturePaddingsList.add(padding);
- } catch (IllegalArgumentException e2) {
- throw new ProviderException(
- "Unsupported encryption padding: " + keymasterPadding);
- }
- }
-
- }
- encryptionPaddings =
- encryptionPaddingsList.toArray(new String[encryptionPaddingsList.size()]);
- signaturePaddings =
- signaturePaddingsList.toArray(new String[signaturePaddingsList.size()]);
-
- digests = KeyProperties.Digest.allFromKeymaster(
- keyCharacteristics.getEnums(KeymasterDefs.KM_TAG_DIGEST));
- blockModes = KeyProperties.BlockMode.allFromKeymaster(
- keyCharacteristics.getEnums(KeymasterDefs.KM_TAG_BLOCK_MODE));
- keymasterSwEnforcedUserAuthenticators =
- keyCharacteristics.swEnforced.getEnum(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, 0);
- keymasterHwEnforcedUserAuthenticators =
- keyCharacteristics.hwEnforced.getEnum(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, 0);
- keymasterSecureUserIds =
- keyCharacteristics.getUnsignedLongs(KeymasterDefs.KM_TAG_USER_SECURE_ID);
- } catch (IllegalArgumentException e) {
- throw new ProviderException("Unsupported key characteristic", e);
- }
-
- Date keyValidityStart = keyCharacteristics.getDate(KeymasterDefs.KM_TAG_ACTIVE_DATETIME);
- Date keyValidityForOriginationEnd =
- keyCharacteristics.getDate(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME);
- Date keyValidityForConsumptionEnd =
- keyCharacteristics.getDate(KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME);
- boolean userAuthenticationRequired =
- !keyCharacteristics.getBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
- long userAuthenticationValidityDurationSeconds =
- keyCharacteristics.getUnsignedInt(KeymasterDefs.KM_TAG_AUTH_TIMEOUT, 0);
- if (userAuthenticationValidityDurationSeconds > Integer.MAX_VALUE) {
- throw new ProviderException("User authentication timeout validity too long: "
- + userAuthenticationValidityDurationSeconds + " seconds");
- }
- boolean userAuthenticationRequirementEnforcedBySecureHardware = (userAuthenticationRequired)
- && (keymasterHwEnforcedUserAuthenticators != 0)
- && (keymasterSwEnforcedUserAuthenticators == 0);
- boolean userAuthenticationValidWhileOnBody =
- keyCharacteristics.hwEnforced.getBoolean(KeymasterDefs.KM_TAG_ALLOW_WHILE_ON_BODY);
- boolean trustedUserPresenceRequired =
- keyCharacteristics.hwEnforced.getBoolean(
- KeymasterDefs.KM_TAG_TRUSTED_USER_PRESENCE_REQUIRED);
-
- boolean invalidatedByBiometricEnrollment = false;
- if (keymasterSwEnforcedUserAuthenticators == KeymasterDefs.HW_AUTH_BIOMETRIC
- || keymasterHwEnforcedUserAuthenticators == KeymasterDefs.HW_AUTH_BIOMETRIC) {
- // Fingerprint-only key; will be invalidated if the root SID isn't in the SID list.
- invalidatedByBiometricEnrollment = keymasterSecureUserIds != null
- && !keymasterSecureUserIds.isEmpty()
- && !keymasterSecureUserIds.contains(getGateKeeperSecureUserId());
- }
-
- boolean userConfirmationRequired = keyCharacteristics.hwEnforced.getBoolean(KeymasterDefs.KM_TAG_TRUSTED_CONFIRMATION_REQUIRED);
-
- return new KeyInfo(entryAlias,
- insideSecureHardware,
- origin,
- keySize,
- keyValidityStart,
- keyValidityForOriginationEnd,
- keyValidityForConsumptionEnd,
- purposes,
- encryptionPaddings,
- signaturePaddings,
- digests,
- blockModes,
- userAuthenticationRequired,
- (int) userAuthenticationValidityDurationSeconds,
- keymasterHwEnforcedUserAuthenticators,
- userAuthenticationRequirementEnforcedBySecureHardware,
- userAuthenticationValidWhileOnBody,
- trustedUserPresenceRequired,
- invalidatedByBiometricEnrollment,
- userConfirmationRequired,
- // Keystore 1.0 does not tell us the exact security level of the key
- // so we report an unknown but secure security level.
- insideSecureHardware ? KeyProperties.SECURITY_LEVEL_UNKNOWN_SECURE
- : KeyProperties.SECURITY_LEVEL_SOFTWARE,
- KeyProperties.UNRESTRICTED_USAGE_COUNT);
- }
-
- private static BigInteger getGateKeeperSecureUserId() throws ProviderException {
- try {
- return BigInteger.valueOf(GateKeeper.getSecureUserId());
- } catch (IllegalStateException e) {
- throw new ProviderException("Failed to get GateKeeper secure user ID", e);
- }
- }
-
- @Override
- protected SecretKey engineGenerateSecret(KeySpec keySpec) throws InvalidKeySpecException {
- throw new InvalidKeySpecException(
- "To generate secret key in Android Keystore, use KeyGenerator initialized with "
- + KeyGenParameterSpec.class.getName());
- }
-
- @Override
- protected SecretKey engineTranslateKey(SecretKey key) throws InvalidKeyException {
- if (key == null) {
- throw new InvalidKeyException("key == null");
- } else if (!(key instanceof AndroidKeyStoreSecretKey)) {
- throw new InvalidKeyException(
- "To import a secret key into Android Keystore, use KeyStore.setEntry");
- }
-
- return key;
- }
-}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreSignatureSpiBase.java b/keystore/java/android/security/keystore/AndroidKeyStoreSignatureSpiBase.java
deleted file mode 100644
index da47b6b..0000000
--- a/keystore/java/android/security/keystore/AndroidKeyStoreSignatureSpiBase.java
+++ /dev/null
@@ -1,431 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.keystore;
-
-import android.annotation.CallSuper;
-import android.annotation.NonNull;
-import android.os.IBinder;
-import android.security.KeyStore;
-import android.security.KeyStoreException;
-import android.security.keymaster.KeymasterArguments;
-import android.security.keymaster.KeymasterDefs;
-import android.security.keymaster.OperationResult;
-
-import libcore.util.EmptyArray;
-
-import java.nio.ByteBuffer;
-import java.security.InvalidKeyException;
-import java.security.InvalidParameterException;
-import java.security.PrivateKey;
-import java.security.ProviderException;
-import java.security.PublicKey;
-import java.security.SecureRandom;
-import java.security.SignatureException;
-import java.security.SignatureSpi;
-
-/**
- * Base class for {@link SignatureSpi} implementations of Android KeyStore backed ciphers.
- *
- * @hide
- */
-abstract class AndroidKeyStoreSignatureSpiBase extends SignatureSpi
- implements KeyStoreCryptoOperation {
- private final KeyStore mKeyStore;
-
- // Fields below are populated by SignatureSpi.engineInitSign/engineInitVerify and KeyStore.begin
- // and should be preserved after SignatureSpi.engineSign/engineVerify finishes.
- private boolean mSigning;
- private AndroidKeyStoreKey mKey;
-
- /**
- * Token referencing this operation inside keystore service. It is initialized by
- * {@code engineInitSign}/{@code engineInitVerify} and is invalidated when
- * {@code engineSign}/{@code engineVerify} succeeds and on some error conditions in between.
- */
- private IBinder mOperationToken;
- private long mOperationHandle;
- private KeyStoreCryptoOperationStreamer mMessageStreamer;
-
- /**
- * Encountered exception which could not be immediately thrown because it was encountered inside
- * a method that does not throw checked exception. This exception will be thrown from
- * {@code engineSign} or {@code engineVerify}. Once such an exception is encountered,
- * {@code engineUpdate} starts ignoring input data.
- */
- private Exception mCachedException;
-
- AndroidKeyStoreSignatureSpiBase() {
- mKeyStore = KeyStore.getInstance();
- }
-
- @Override
- protected final void engineInitSign(PrivateKey key) throws InvalidKeyException {
- engineInitSign(key, null);
- }
-
- @Override
- protected final void engineInitSign(PrivateKey privateKey, SecureRandom random)
- throws InvalidKeyException {
- resetAll();
-
- boolean success = false;
- try {
- if (privateKey == null) {
- throw new InvalidKeyException("Unsupported key: null");
- }
- AndroidKeyStoreKey keystoreKey;
- if (privateKey instanceof AndroidKeyStorePrivateKey) {
- keystoreKey = (AndroidKeyStoreKey) privateKey;
- } else {
- throw new InvalidKeyException("Unsupported private key type: " + privateKey);
- }
- mSigning = true;
- initKey(keystoreKey);
- appRandom = random;
- ensureKeystoreOperationInitialized();
- success = true;
- } finally {
- if (!success) {
- resetAll();
- }
- }
- }
-
- @Override
- protected final void engineInitVerify(PublicKey publicKey) throws InvalidKeyException {
- resetAll();
-
- boolean success = false;
- try {
- if (publicKey == null) {
- throw new InvalidKeyException("Unsupported key: null");
- }
- AndroidKeyStoreKey keystoreKey;
- if (publicKey instanceof AndroidKeyStorePublicKey) {
- keystoreKey = (AndroidKeyStorePublicKey) publicKey;
- } else {
- throw new InvalidKeyException("Unsupported public key type: " + publicKey);
- }
- mSigning = false;
- initKey(keystoreKey);
- appRandom = null;
- ensureKeystoreOperationInitialized();
- success = true;
- } finally {
- if (!success) {
- resetAll();
- }
- }
- }
-
- /**
- * Configures this signature instance to use the provided key.
- *
- * @throws InvalidKeyException if the {@code key} is not suitable.
- */
- @CallSuper
- protected void initKey(AndroidKeyStoreKey key) throws InvalidKeyException {
- mKey = key;
- }
-
- /**
- * Resets this cipher to its pristine pre-init state. This must be equivalent to obtaining a new
- * cipher instance.
- *
- * <p>Subclasses storing additional state should override this method, reset the additional
- * state, and then chain to superclass.
- */
- @CallSuper
- protected void resetAll() {
- IBinder operationToken = mOperationToken;
- if (operationToken != null) {
- mOperationToken = null;
- mKeyStore.abort(operationToken);
- }
- mSigning = false;
- mKey = null;
- appRandom = null;
- mOperationToken = null;
- mOperationHandle = 0;
- mMessageStreamer = null;
- mCachedException = null;
- }
-
- /**
- * Resets this cipher while preserving the initialized state. This must be equivalent to
- * rolling back the cipher's state to just after the most recent {@code engineInit} completed
- * successfully.
- *
- * <p>Subclasses storing additional post-init state should override this method, reset the
- * additional state, and then chain to superclass.
- */
- @CallSuper
- protected void resetWhilePreservingInitState() {
- IBinder operationToken = mOperationToken;
- if (operationToken != null) {
- mOperationToken = null;
- mKeyStore.abort(operationToken);
- }
- mOperationHandle = 0;
- mMessageStreamer = null;
- mCachedException = null;
- }
-
- private void ensureKeystoreOperationInitialized() throws InvalidKeyException {
- if (mMessageStreamer != null) {
- return;
- }
- if (mCachedException != null) {
- return;
- }
- if (mKey == null) {
- throw new IllegalStateException("Not initialized");
- }
-
- KeymasterArguments keymasterInputArgs = new KeymasterArguments();
- addAlgorithmSpecificParametersToBegin(keymasterInputArgs);
-
- OperationResult opResult = mKeyStore.begin(
- mKey.getAlias(),
- mSigning ? KeymasterDefs.KM_PURPOSE_SIGN : KeymasterDefs.KM_PURPOSE_VERIFY,
- true, // permit aborting this operation if keystore runs out of resources
- keymasterInputArgs,
- null, // no additional entropy for begin -- only finish might need some
- mKey.getUid());
- if (opResult == null) {
- throw new KeyStoreConnectException();
- }
-
- // Store operation token and handle regardless of the error code returned by KeyStore to
- // ensure that the operation gets aborted immediately if the code below throws an exception.
- mOperationToken = opResult.token;
- mOperationHandle = opResult.operationHandle;
-
- // If necessary, throw an exception due to KeyStore operation having failed.
- InvalidKeyException e = KeyStoreCryptoOperationUtils.getInvalidKeyExceptionForInit(
- mKeyStore, mKey, opResult.resultCode);
- if (e != null) {
- throw e;
- }
-
- if (mOperationToken == null) {
- throw new ProviderException("Keystore returned null operation token");
- }
- if (mOperationHandle == 0) {
- throw new ProviderException("Keystore returned invalid operation handle");
- }
-
- mMessageStreamer = createMainDataStreamer(mKeyStore, opResult.token);
- }
-
- /**
- * Creates a streamer which sends the message to be signed/verified into the provided KeyStore
- *
- * <p>This implementation returns a working streamer.
- */
- @NonNull
- protected KeyStoreCryptoOperationStreamer createMainDataStreamer(
- KeyStore keyStore, IBinder operationToken) {
- return new KeyStoreCryptoOperationChunkedStreamer(
- new KeyStoreCryptoOperationChunkedStreamer.MainDataStream(
- keyStore, operationToken));
- }
-
- @Override
- public final long getOperationHandle() {
- return mOperationHandle;
- }
-
- @Override
- protected final void engineUpdate(byte[] b, int off, int len) throws SignatureException {
- if (mCachedException != null) {
- throw new SignatureException(mCachedException);
- }
-
- try {
- ensureKeystoreOperationInitialized();
- } catch (InvalidKeyException e) {
- throw new SignatureException(e);
- }
-
- if (len == 0) {
- return;
- }
-
- byte[] output;
- try {
- output = mMessageStreamer.update(b, off, len);
- } catch (KeyStoreException e) {
- throw new SignatureException(e);
- }
-
- if (output.length != 0) {
- throw new ProviderException(
- "Update operation unexpectedly produced output: " + output.length + " bytes");
- }
- }
-
- @Override
- protected final void engineUpdate(byte b) throws SignatureException {
- engineUpdate(new byte[] {b}, 0, 1);
- }
-
- @Override
- protected final void engineUpdate(ByteBuffer input) {
- byte[] b;
- int off;
- int len = input.remaining();
- if (input.hasArray()) {
- b = input.array();
- off = input.arrayOffset() + input.position();
- input.position(input.limit());
- } else {
- b = new byte[len];
- off = 0;
- input.get(b);
- }
-
- try {
- engineUpdate(b, off, len);
- } catch (SignatureException e) {
- mCachedException = e;
- }
- }
-
- @Override
- protected final int engineSign(byte[] out, int outOffset, int outLen)
- throws SignatureException {
- return super.engineSign(out, outOffset, outLen);
- }
-
- @Override
- protected final byte[] engineSign() throws SignatureException {
- if (mCachedException != null) {
- throw new SignatureException(mCachedException);
- }
-
- byte[] signature;
- try {
- ensureKeystoreOperationInitialized();
-
- byte[] additionalEntropy =
- KeyStoreCryptoOperationUtils.getRandomBytesToMixIntoKeystoreRng(
- appRandom, getAdditionalEntropyAmountForSign());
- signature = mMessageStreamer.doFinal(
- EmptyArray.BYTE, 0, 0,
- null, // no signature provided -- it'll be generated by this invocation
- additionalEntropy);
- } catch (InvalidKeyException | KeyStoreException e) {
- throw new SignatureException(e);
- }
-
- resetWhilePreservingInitState();
- return signature;
- }
-
- @Override
- protected final boolean engineVerify(byte[] signature) throws SignatureException {
- if (mCachedException != null) {
- throw new SignatureException(mCachedException);
- }
-
- try {
- ensureKeystoreOperationInitialized();
- } catch (InvalidKeyException e) {
- throw new SignatureException(e);
- }
-
- boolean verified;
- try {
- byte[] output = mMessageStreamer.doFinal(
- EmptyArray.BYTE, 0, 0,
- signature,
- null // no additional entropy needed -- verification is deterministic
- );
- if (output.length != 0) {
- throw new ProviderException(
- "Signature verification unexpected produced output: " + output.length
- + " bytes");
- }
- verified = true;
- } catch (KeyStoreException e) {
- switch (e.getErrorCode()) {
- case KeymasterDefs.KM_ERROR_VERIFICATION_FAILED:
- verified = false;
- break;
- default:
- throw new SignatureException(e);
- }
- }
-
- resetWhilePreservingInitState();
- return verified;
- }
-
- @Override
- protected final boolean engineVerify(byte[] sigBytes, int offset, int len)
- throws SignatureException {
- return engineVerify(ArrayUtils.subarray(sigBytes, offset, len));
- }
-
- @Deprecated
- @Override
- protected final Object engineGetParameter(String param) throws InvalidParameterException {
- throw new InvalidParameterException();
- }
-
- @Deprecated
- @Override
- protected final void engineSetParameter(String param, Object value)
- throws InvalidParameterException {
- throw new InvalidParameterException();
- }
-
- protected final KeyStore getKeyStore() {
- return mKeyStore;
- }
-
- /**
- * Returns {@code true} if this signature is initialized for signing, {@code false} if this
- * signature is initialized for verification.
- */
- protected final boolean isSigning() {
- return mSigning;
- }
-
- // The methods below need to be implemented by subclasses.
-
- /**
- * Returns the amount of additional entropy (in bytes) to be provided to the KeyStore's
- * {@code finish} operation when generating a signature.
- *
- * <p>This value should match (or exceed) the amount of Shannon entropy of the produced
- * signature assuming the key and the message are known. For example, for ECDSA signature this
- * should be the size of {@code R}, whereas for the RSA signature with PKCS#1 padding this
- * should be {@code 0}.
- */
- protected abstract int getAdditionalEntropyAmountForSign();
-
- /**
- * Invoked to add algorithm-specific parameters for the KeyStore's {@code begin} operation.
- *
- * @param keymasterArgs keystore/keymaster arguments to be populated with algorithm-specific
- * parameters.
- */
- protected abstract void addAlgorithmSpecificParametersToBegin(
- @NonNull KeymasterArguments keymasterArgs);
-}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
deleted file mode 100644
index 51c4252..0000000
--- a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
+++ /dev/null
@@ -1,1112 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.keystore;
-
-import android.security.Credentials;
-import android.security.GateKeeper;
-import android.security.KeyStore;
-import android.security.KeyStoreParameter;
-import android.security.keymaster.KeyCharacteristics;
-import android.security.keymaster.KeymasterArguments;
-import android.security.keymaster.KeymasterDefs;
-import android.security.keystore.KeyPermanentlyInvalidatedException;
-import android.security.keystore.KeyProperties;
-import android.security.keystore.KeyProtection;
-import android.security.keystore.SecureKeyImportUnavailableException;
-import android.security.keystore.WrappedKeyEntry;
-import android.util.Log;
-
-import libcore.util.EmptyArray;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.security.Key;
-import java.security.KeyStore.Entry;
-import java.security.KeyStore.LoadStoreParameter;
-import java.security.KeyStore.PrivateKeyEntry;
-import java.security.KeyStore.ProtectionParameter;
-import java.security.KeyStore.SecretKeyEntry;
-import java.security.KeyStoreException;
-import java.security.KeyStoreSpi;
-import java.security.NoSuchAlgorithmException;
-import java.security.PrivateKey;
-import java.security.ProviderException;
-import java.security.PublicKey;
-import java.security.UnrecoverableKeyException;
-import java.security.cert.Certificate;
-import java.security.cert.CertificateEncodingException;
-import java.security.cert.CertificateException;
-import java.security.cert.CertificateFactory;
-import java.security.cert.X509Certificate;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Date;
-import java.util.Enumeration;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Set;
-
-import javax.crypto.SecretKey;
-
-/**
- * A java.security.KeyStore interface for the Android KeyStore. An instance of
- * it can be created via the {@link java.security.KeyStore#getInstance(String)
- * KeyStore.getInstance("AndroidKeyStore")} interface. This returns a
- * java.security.KeyStore backed by this "AndroidKeyStore" implementation.
- * <p>
- * This is built on top of Android's keystore daemon. The convention of alias
- * use is:
- * <p>
- * PrivateKeyEntry will have a Credentials.USER_PRIVATE_KEY as the private key,
- * Credentials.USER_CERTIFICATE as the first certificate in the chain (the one
- * that corresponds to the private key), and then a Credentials.CA_CERTIFICATE
- * entry which will have the rest of the chain concatenated in BER format.
- * <p>
- * TrustedCertificateEntry will just have a Credentials.CA_CERTIFICATE entry
- * with a single certificate.
- *
- * @hide
- */
-public class AndroidKeyStoreSpi extends KeyStoreSpi {
- public static final String NAME = "AndroidKeyStore";
-
- private KeyStore mKeyStore;
- private int mUid = KeyStore.UID_SELF;
-
- @Override
- public Key engineGetKey(String alias, char[] password) throws NoSuchAlgorithmException,
- UnrecoverableKeyException {
- String userKeyAlias = Credentials.USER_PRIVATE_KEY + alias;
- AndroidKeyStoreKey key;
- if (!mKeyStore.contains(userKeyAlias, mUid)) {
- // try legacy prefix for backward compatibility
- userKeyAlias = Credentials.USER_SECRET_KEY + alias;
- if (!mKeyStore.contains(userKeyAlias, mUid)) return null;
- }
- try {
- key = AndroidKeyStoreProvider.loadAndroidKeyStoreKeyFromKeystore(mKeyStore,
- userKeyAlias,
- mUid);
- } catch (KeyPermanentlyInvalidatedException e) {
- throw new UnrecoverableKeyException(e.getMessage());
- }
- return key;
- }
-
- @Override
- public Certificate[] engineGetCertificateChain(String alias) {
- if (alias == null) {
- throw new NullPointerException("alias == null");
- }
-
- final X509Certificate leaf = (X509Certificate) engineGetCertificate(alias);
- if (leaf == null) {
- return null;
- }
-
- final Certificate[] caList;
-
- // Suppress the key not found warning for this call. It seems that this error is exclusively
- // being thrown when there is a self signed certificate chain, so when the keystore service
- // attempts to query for the CA details, it obviously fails to find them and returns a
- // key not found exception. This is WAI, and throwing a stack trace here can be very
- // misleading since the trace is not clear.
- final byte[] caBytes = mKeyStore.get(Credentials.CA_CERTIFICATE + alias,
- mUid,
- true /* suppressKeyNotFoundWarning */);
- if (caBytes != null) {
- final Collection<X509Certificate> caChain = toCertificates(caBytes);
-
- caList = new Certificate[caChain.size() + 1];
-
- final Iterator<X509Certificate> it = caChain.iterator();
- int i = 1;
- while (it.hasNext()) {
- caList[i++] = it.next();
- }
- } else {
- caList = new Certificate[1];
- }
-
- caList[0] = leaf;
-
- return caList;
- }
-
- @Override
- public Certificate engineGetCertificate(String alias) {
- if (alias == null) {
- throw new NullPointerException("alias == null");
- }
-
- byte[] encodedCert = mKeyStore.get(Credentials.USER_CERTIFICATE + alias, mUid);
- if (encodedCert != null) {
- return getCertificateForPrivateKeyEntry(alias, encodedCert);
- }
-
- encodedCert = mKeyStore.get(Credentials.CA_CERTIFICATE + alias, mUid);
- if (encodedCert != null) {
- return getCertificateForTrustedCertificateEntry(encodedCert);
- }
-
- // This entry/alias does not contain a certificate.
- return null;
- }
-
- private Certificate getCertificateForTrustedCertificateEntry(byte[] encodedCert) {
- // For this certificate there shouldn't be a private key in this KeyStore entry. Thus,
- // there's no need to wrap this certificate as opposed to the certificate associated with
- // a private key entry.
- return toCertificate(encodedCert);
- }
-
- private Certificate getCertificateForPrivateKeyEntry(String alias, byte[] encodedCert) {
- // All crypto algorithms offered by Android Keystore for its private keys must also
- // be offered for the corresponding public keys stored in the Android Keystore. The
- // complication is that the underlying keystore service operates only on full key pairs,
- // rather than just public keys or private keys. As a result, Android Keystore-backed
- // crypto can only be offered for public keys for which keystore contains the
- // corresponding private key. This is not the case for certificate-only entries (e.g.,
- // trusted certificates).
- //
- // getCertificate().getPublicKey() is the only way to obtain the public key
- // corresponding to the private key stored in the KeyStore. Thus, we need to make sure
- // that the returned public key points to the underlying key pair / private key
- // when available.
-
- X509Certificate cert = toCertificate(encodedCert);
- if (cert == null) {
- // Failed to parse the certificate.
- return null;
- }
-
- String privateKeyAlias = Credentials.USER_PRIVATE_KEY + alias;
- if (mKeyStore.contains(privateKeyAlias, mUid)) {
- // As expected, keystore contains the private key corresponding to this public key. Wrap
- // the certificate so that its getPublicKey method returns an Android Keystore
- // PublicKey. This key will delegate crypto operations involving this public key to
- // Android Keystore when higher-priority providers do not offer these crypto
- // operations for this key.
- return wrapIntoKeyStoreCertificate(privateKeyAlias, mUid, cert);
- } else {
- // This KeyStore entry/alias is supposed to contain the private key corresponding to
- // the public key in this certificate, but it does not for some reason. It's probably a
- // bug. Let other providers handle crypto operations involving the public key returned
- // by this certificate's getPublicKey.
- return cert;
- }
- }
-
- /**
- * Wraps the provided cerificate into {@link KeyStoreX509Certificate} so that the public key
- * returned by the certificate contains information about the alias of the private key in
- * keystore. This is needed so that Android Keystore crypto operations using public keys can
- * find out which key alias to use. These operations cannot work without an alias.
- */
- private static KeyStoreX509Certificate wrapIntoKeyStoreCertificate(
- String privateKeyAlias, int uid, X509Certificate certificate) {
- return (certificate != null)
- ? new KeyStoreX509Certificate(privateKeyAlias, uid, certificate) : null;
- }
-
- private static X509Certificate toCertificate(byte[] bytes) {
- try {
- final CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
- return (X509Certificate) certFactory.generateCertificate(
- new ByteArrayInputStream(bytes));
- } catch (CertificateException e) {
- Log.w(NAME, "Couldn't parse certificate in keystore", e);
- return null;
- }
- }
-
- @SuppressWarnings("unchecked")
- private static Collection<X509Certificate> toCertificates(byte[] bytes) {
- try {
- final CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
- return (Collection<X509Certificate>) certFactory.generateCertificates(
- new ByteArrayInputStream(bytes));
- } catch (CertificateException e) {
- Log.w(NAME, "Couldn't parse certificates in keystore", e);
- return new ArrayList<X509Certificate>();
- }
- }
-
- private Date getModificationDate(String alias) {
- final long epochMillis = mKeyStore.getmtime(alias, mUid);
- if (epochMillis == -1L) {
- return null;
- }
-
- return new Date(epochMillis);
- }
-
- @Override
- public Date engineGetCreationDate(String alias) {
- if (alias == null) {
- throw new NullPointerException("alias == null");
- }
-
- Date d = getModificationDate(Credentials.USER_PRIVATE_KEY + alias);
- if (d != null) {
- return d;
- }
-
- d = getModificationDate(Credentials.USER_SECRET_KEY + alias);
- if (d != null) {
- return d;
- }
-
- d = getModificationDate(Credentials.USER_CERTIFICATE + alias);
- if (d != null) {
- return d;
- }
-
- return getModificationDate(Credentials.CA_CERTIFICATE + alias);
- }
-
- @Override
- public void engineSetKeyEntry(String alias, Key key, char[] password, Certificate[] chain)
- throws KeyStoreException {
- if ((password != null) && (password.length > 0)) {
- throw new KeyStoreException("entries cannot be protected with passwords");
- }
-
- if (key instanceof PrivateKey) {
- setPrivateKeyEntry(alias, (PrivateKey) key, chain, null);
- } else if (key instanceof SecretKey) {
- setSecretKeyEntry(alias, (SecretKey) key, null);
- } else {
- throw new KeyStoreException("Only PrivateKey and SecretKey are supported");
- }
- }
-
- private static KeyProtection getLegacyKeyProtectionParameter(PrivateKey key)
- throws KeyStoreException {
- String keyAlgorithm = key.getAlgorithm();
- KeyProtection.Builder specBuilder;
- if (KeyProperties.KEY_ALGORITHM_EC.equalsIgnoreCase(keyAlgorithm)) {
- specBuilder =
- new KeyProtection.Builder(
- KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY);
- // Authorized to be used with any digest (including no digest).
- // MD5 was never offered for Android Keystore for ECDSA.
- specBuilder.setDigests(
- KeyProperties.DIGEST_NONE,
- KeyProperties.DIGEST_SHA1,
- KeyProperties.DIGEST_SHA224,
- KeyProperties.DIGEST_SHA256,
- KeyProperties.DIGEST_SHA384,
- KeyProperties.DIGEST_SHA512);
- } else if (KeyProperties.KEY_ALGORITHM_RSA.equalsIgnoreCase(keyAlgorithm)) {
- specBuilder =
- new KeyProtection.Builder(
- KeyProperties.PURPOSE_ENCRYPT
- | KeyProperties.PURPOSE_DECRYPT
- | KeyProperties.PURPOSE_SIGN
- | KeyProperties.PURPOSE_VERIFY);
- // Authorized to be used with any digest (including no digest).
- specBuilder.setDigests(
- KeyProperties.DIGEST_NONE,
- KeyProperties.DIGEST_MD5,
- KeyProperties.DIGEST_SHA1,
- KeyProperties.DIGEST_SHA224,
- KeyProperties.DIGEST_SHA256,
- KeyProperties.DIGEST_SHA384,
- KeyProperties.DIGEST_SHA512);
- // Authorized to be used with any encryption and signature padding
- // schemes (including no padding).
- specBuilder.setEncryptionPaddings(
- KeyProperties.ENCRYPTION_PADDING_NONE,
- KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1,
- KeyProperties.ENCRYPTION_PADDING_RSA_OAEP);
- specBuilder.setSignaturePaddings(
- KeyProperties.SIGNATURE_PADDING_RSA_PKCS1,
- KeyProperties.SIGNATURE_PADDING_RSA_PSS);
- // Disable randomized encryption requirement to support encryption
- // padding NONE above.
- specBuilder.setRandomizedEncryptionRequired(false);
- } else {
- throw new KeyStoreException("Unsupported key algorithm: " + keyAlgorithm);
- }
- specBuilder.setUserAuthenticationRequired(false);
-
- return specBuilder.build();
- }
-
- private void setPrivateKeyEntry(String alias, PrivateKey key, Certificate[] chain,
- java.security.KeyStore.ProtectionParameter param) throws KeyStoreException {
- int flags = 0;
- KeyProtection spec;
- if (param == null) {
- spec = getLegacyKeyProtectionParameter(key);
- } else if (param instanceof KeyStoreParameter) {
- spec = getLegacyKeyProtectionParameter(key);
- KeyStoreParameter legacySpec = (KeyStoreParameter) param;
- if (legacySpec.isEncryptionRequired()) {
- flags = KeyStore.FLAG_ENCRYPTED;
- }
- } else if (param instanceof KeyProtection) {
- spec = (KeyProtection) param;
- if (spec.isCriticalToDeviceEncryption()) {
- flags |= KeyStore.FLAG_CRITICAL_TO_DEVICE_ENCRYPTION;
- }
-
- if (spec.isStrongBoxBacked()) {
- flags |= KeyStore.FLAG_STRONGBOX;
- }
- } else {
- throw new KeyStoreException(
- "Unsupported protection parameter class:" + param.getClass().getName()
- + ". Supported: " + KeyProtection.class.getName() + ", "
- + KeyStoreParameter.class.getName());
- }
-
- // Make sure the chain exists since this is a PrivateKey
- if ((chain == null) || (chain.length == 0)) {
- throw new KeyStoreException("Must supply at least one Certificate with PrivateKey");
- }
-
- // Do chain type checking.
- X509Certificate[] x509chain = new X509Certificate[chain.length];
- for (int i = 0; i < chain.length; i++) {
- if (!"X.509".equals(chain[i].getType())) {
- throw new KeyStoreException("Certificates must be in X.509 format: invalid cert #"
- + i);
- }
-
- if (!(chain[i] instanceof X509Certificate)) {
- throw new KeyStoreException("Certificates must be in X.509 format: invalid cert #"
- + i);
- }
-
- x509chain[i] = (X509Certificate) chain[i];
- }
-
- final byte[] userCertBytes;
- try {
- userCertBytes = x509chain[0].getEncoded();
- } catch (CertificateEncodingException e) {
- throw new KeyStoreException("Failed to encode certificate #0", e);
- }
-
- /*
- * If we have a chain, store it in the CA certificate slot for this
- * alias as concatenated DER-encoded certificates. These can be
- * deserialized by {@link CertificateFactory#generateCertificates}.
- */
- final byte[] chainBytes;
- if (chain.length > 1) {
- /*
- * The chain is passed in as {user_cert, ca_cert_1, ca_cert_2, ...}
- * so we only need the certificates starting at index 1.
- */
- final byte[][] certsBytes = new byte[x509chain.length - 1][];
- int totalCertLength = 0;
- for (int i = 0; i < certsBytes.length; i++) {
- try {
- certsBytes[i] = x509chain[i + 1].getEncoded();
- totalCertLength += certsBytes[i].length;
- } catch (CertificateEncodingException e) {
- throw new KeyStoreException("Failed to encode certificate #" + i, e);
- }
- }
-
- /*
- * Serialize this into one byte array so we can later call
- * CertificateFactory#generateCertificates to recover them.
- */
- chainBytes = new byte[totalCertLength];
- int outputOffset = 0;
- for (int i = 0; i < certsBytes.length; i++) {
- final int certLength = certsBytes[i].length;
- System.arraycopy(certsBytes[i], 0, chainBytes, outputOffset, certLength);
- outputOffset += certLength;
- certsBytes[i] = null;
- }
- } else {
- chainBytes = null;
- }
-
- final String pkeyAlias;
- if (key instanceof AndroidKeyStorePrivateKey) {
- pkeyAlias = ((AndroidKeyStoreKey) key).getAlias();
- } else {
- pkeyAlias = null;
- }
-
- byte[] pkcs8EncodedPrivateKeyBytes;
- KeymasterArguments importArgs;
- final boolean shouldReplacePrivateKey;
- if (pkeyAlias != null && pkeyAlias.startsWith(Credentials.USER_PRIVATE_KEY)) {
- final String keySubalias = pkeyAlias.substring(Credentials.USER_PRIVATE_KEY.length());
- if (!alias.equals(keySubalias)) {
- throw new KeyStoreException("Can only replace keys with same alias: " + alias
- + " != " + keySubalias);
- }
- shouldReplacePrivateKey = false;
- importArgs = null;
- pkcs8EncodedPrivateKeyBytes = null;
- } else {
- shouldReplacePrivateKey = true;
- // Make sure the PrivateKey format is the one we support.
- final String keyFormat = key.getFormat();
- if ((keyFormat == null) || (!"PKCS#8".equals(keyFormat))) {
- throw new KeyStoreException(
- "Unsupported private key export format: " + keyFormat
- + ". Only private keys which export their key material in PKCS#8 format are"
- + " supported.");
- }
-
- // Make sure we can actually encode the key.
- pkcs8EncodedPrivateKeyBytes = key.getEncoded();
- if (pkcs8EncodedPrivateKeyBytes == null) {
- throw new KeyStoreException("Private key did not export any key material");
- }
-
- importArgs = new KeymasterArguments();
- try {
- importArgs.addEnum(KeymasterDefs.KM_TAG_ALGORITHM,
- KeyProperties.KeyAlgorithm.toKeymasterAsymmetricKeyAlgorithm(
- key.getAlgorithm()));
- @KeyProperties.PurposeEnum int purposes = spec.getPurposes();
- importArgs.addEnums(KeymasterDefs.KM_TAG_PURPOSE,
- KeyProperties.Purpose.allToKeymaster(purposes));
- if (spec.isDigestsSpecified()) {
- importArgs.addEnums(KeymasterDefs.KM_TAG_DIGEST,
- KeyProperties.Digest.allToKeymaster(spec.getDigests()));
- }
-
- importArgs.addEnums(KeymasterDefs.KM_TAG_BLOCK_MODE,
- KeyProperties.BlockMode.allToKeymaster(spec.getBlockModes()));
- int[] keymasterEncryptionPaddings =
- KeyProperties.EncryptionPadding.allToKeymaster(
- spec.getEncryptionPaddings());
- if (((purposes & KeyProperties.PURPOSE_ENCRYPT) != 0)
- && (spec.isRandomizedEncryptionRequired())) {
- for (int keymasterPadding : keymasterEncryptionPaddings) {
- if (!KeymasterUtils
- .isKeymasterPaddingSchemeIndCpaCompatibleWithAsymmetricCrypto(
- keymasterPadding)) {
- throw new KeyStoreException(
- "Randomized encryption (IND-CPA) required but is violated by"
- + " encryption padding mode: "
- + KeyProperties.EncryptionPadding.fromKeymaster(
- keymasterPadding)
- + ". See KeyProtection documentation.");
- }
- }
- }
- importArgs.addEnums(KeymasterDefs.KM_TAG_PADDING, keymasterEncryptionPaddings);
- importArgs.addEnums(KeymasterDefs.KM_TAG_PADDING,
- KeyProperties.SignaturePadding.allToKeymaster(spec.getSignaturePaddings()));
- KeymasterUtils.addUserAuthArgs(importArgs, spec);
- importArgs.addDateIfNotNull(KeymasterDefs.KM_TAG_ACTIVE_DATETIME,
- spec.getKeyValidityStart());
- importArgs.addDateIfNotNull(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME,
- spec.getKeyValidityForOriginationEnd());
- importArgs.addDateIfNotNull(KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME,
- spec.getKeyValidityForConsumptionEnd());
- } catch (IllegalArgumentException | IllegalStateException e) {
- throw new KeyStoreException(e);
- }
- }
-
-
- boolean success = false;
- try {
- // Store the private key, if necessary
- if (shouldReplacePrivateKey) {
- // Delete the stored private key and any related entries before importing the
- // provided key
- Credentials.deleteAllTypesForAlias(mKeyStore, alias, mUid);
- KeyCharacteristics resultingKeyCharacteristics = new KeyCharacteristics();
- int errorCode = mKeyStore.importKey(
- Credentials.USER_PRIVATE_KEY + alias,
- importArgs,
- KeymasterDefs.KM_KEY_FORMAT_PKCS8,
- pkcs8EncodedPrivateKeyBytes,
- mUid,
- flags,
- resultingKeyCharacteristics);
- if (errorCode != KeyStore.NO_ERROR) {
- throw new KeyStoreException("Failed to store private key",
- KeyStore.getKeyStoreException(errorCode));
- }
- } else {
- // Keep the stored private key around -- delete all other entry types
- Credentials.deleteCertificateTypesForAlias(mKeyStore, alias, mUid);
- Credentials.deleteLegacyKeyForAlias(mKeyStore, alias, mUid);
- }
-
- // Store the leaf certificate
- int errorCode = mKeyStore.insert(Credentials.USER_CERTIFICATE + alias, userCertBytes,
- mUid, flags);
- if (errorCode != KeyStore.NO_ERROR) {
- throw new KeyStoreException("Failed to store certificate #0",
- KeyStore.getKeyStoreException(errorCode));
- }
-
- // Store the certificate chain
- errorCode = mKeyStore.insert(Credentials.CA_CERTIFICATE + alias, chainBytes,
- mUid, flags);
- if (errorCode != KeyStore.NO_ERROR) {
- throw new KeyStoreException("Failed to store certificate chain",
- KeyStore.getKeyStoreException(errorCode));
- }
- success = true;
- } finally {
- if (!success) {
- if (shouldReplacePrivateKey) {
- Credentials.deleteAllTypesForAlias(mKeyStore, alias, mUid);
- } else {
- Credentials.deleteCertificateTypesForAlias(mKeyStore, alias, mUid);
- Credentials.deleteLegacyKeyForAlias(mKeyStore, alias, mUid);
- }
- }
- }
- }
-
- private void setSecretKeyEntry(String entryAlias, SecretKey key,
- java.security.KeyStore.ProtectionParameter param)
- throws KeyStoreException {
- if ((param != null) && (!(param instanceof KeyProtection))) {
- throw new KeyStoreException(
- "Unsupported protection parameter class: " + param.getClass().getName()
- + ". Supported: " + KeyProtection.class.getName());
- }
- KeyProtection params = (KeyProtection) param;
-
- if (key instanceof AndroidKeyStoreSecretKey) {
- // KeyStore-backed secret key. It cannot be duplicated into another entry and cannot
- // overwrite its own entry.
- String keyAliasInKeystore = ((AndroidKeyStoreSecretKey) key).getAlias();
- if (keyAliasInKeystore == null) {
- throw new KeyStoreException("KeyStore-backed secret key does not have an alias");
- }
- String keyAliasPrefix = Credentials.USER_PRIVATE_KEY;
- if (!keyAliasInKeystore.startsWith(keyAliasPrefix)) {
- // try legacy prefix
- keyAliasPrefix = Credentials.USER_SECRET_KEY;
- if (!keyAliasInKeystore.startsWith(keyAliasPrefix)) {
- throw new KeyStoreException("KeyStore-backed secret key has invalid alias: "
- + keyAliasInKeystore);
- }
- }
- String keyEntryAlias =
- keyAliasInKeystore.substring(keyAliasPrefix.length());
- if (!entryAlias.equals(keyEntryAlias)) {
- throw new KeyStoreException("Can only replace KeyStore-backed keys with same"
- + " alias: " + entryAlias + " != " + keyEntryAlias);
- }
- // This is the entry where this key is already stored. No need to do anything.
- if (params != null) {
- throw new KeyStoreException("Modifying KeyStore-backed key using protection"
- + " parameters not supported");
- }
- return;
- }
-
- if (params == null) {
- throw new KeyStoreException(
- "Protection parameters must be specified when importing a symmetric key");
- }
-
- // Not a KeyStore-backed secret key -- import its key material into keystore.
- String keyExportFormat = key.getFormat();
- if (keyExportFormat == null) {
- throw new KeyStoreException(
- "Only secret keys that export their key material are supported");
- } else if (!"RAW".equals(keyExportFormat)) {
- throw new KeyStoreException(
- "Unsupported secret key material export format: " + keyExportFormat);
- }
- byte[] keyMaterial = key.getEncoded();
- if (keyMaterial == null) {
- throw new KeyStoreException("Key did not export its key material despite supporting"
- + " RAW format export");
- }
-
- KeymasterArguments args = new KeymasterArguments();
- try {
- int keymasterAlgorithm =
- KeyProperties.KeyAlgorithm.toKeymasterSecretKeyAlgorithm(key.getAlgorithm());
- args.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, keymasterAlgorithm);
-
- int[] keymasterDigests;
- if (keymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_HMAC) {
- // JCA HMAC key algorithm implies a digest (e.g., HmacSHA256 key algorithm
- // implies SHA-256 digest). Because keymaster HMAC key is authorized only for one
- // digest, we don't let import parameters override the digest implied by the key.
- // If the parameters specify digests at all, they must specify only one digest, the
- // only implied by key algorithm.
- int keymasterImpliedDigest =
- KeyProperties.KeyAlgorithm.toKeymasterDigest(key.getAlgorithm());
- if (keymasterImpliedDigest == -1) {
- throw new ProviderException(
- "HMAC key algorithm digest unknown for key algorithm "
- + key.getAlgorithm());
- }
- keymasterDigests = new int[] {keymasterImpliedDigest};
- if (params.isDigestsSpecified()) {
- // Digest(s) explicitly specified in params -- check that the list consists of
- // exactly one digest, the one implied by key algorithm.
- int[] keymasterDigestsFromParams =
- KeyProperties.Digest.allToKeymaster(params.getDigests());
- if ((keymasterDigestsFromParams.length != 1)
- || (keymasterDigestsFromParams[0] != keymasterImpliedDigest)) {
- throw new KeyStoreException(
- "Unsupported digests specification: "
- + Arrays.asList(params.getDigests()) + ". Only "
- + KeyProperties.Digest.fromKeymaster(keymasterImpliedDigest)
- + " supported for HMAC key algorithm " + key.getAlgorithm());
- }
- }
- } else {
- // Key algorithm does not imply a digest.
- if (params.isDigestsSpecified()) {
- keymasterDigests = KeyProperties.Digest.allToKeymaster(params.getDigests());
- } else {
- keymasterDigests = EmptyArray.INT;
- }
- }
- args.addEnums(KeymasterDefs.KM_TAG_DIGEST, keymasterDigests);
-
- @KeyProperties.PurposeEnum int purposes = params.getPurposes();
- int[] keymasterBlockModes =
- KeyProperties.BlockMode.allToKeymaster(params.getBlockModes());
- if (((purposes & KeyProperties.PURPOSE_ENCRYPT) != 0)
- && (params.isRandomizedEncryptionRequired())) {
- for (int keymasterBlockMode : keymasterBlockModes) {
- if (!KeymasterUtils.isKeymasterBlockModeIndCpaCompatibleWithSymmetricCrypto(
- keymasterBlockMode)) {
- throw new KeyStoreException(
- "Randomized encryption (IND-CPA) required but may be violated by"
- + " block mode: "
- + KeyProperties.BlockMode.fromKeymaster(keymasterBlockMode)
- + ". See KeyProtection documentation.");
- }
- }
- }
- args.addEnums(KeymasterDefs.KM_TAG_PURPOSE,
- KeyProperties.Purpose.allToKeymaster(purposes));
- args.addEnums(KeymasterDefs.KM_TAG_BLOCK_MODE, keymasterBlockModes);
- if (params.getSignaturePaddings().length > 0) {
- throw new KeyStoreException("Signature paddings not supported for symmetric keys");
- }
- int[] keymasterPaddings = KeyProperties.EncryptionPadding.allToKeymaster(
- params.getEncryptionPaddings());
- args.addEnums(KeymasterDefs.KM_TAG_PADDING, keymasterPaddings);
- KeymasterUtils.addUserAuthArgs(args, params);
- KeymasterUtils.addMinMacLengthAuthorizationIfNecessary(
- args,
- keymasterAlgorithm,
- keymasterBlockModes,
- keymasterDigests);
- args.addDateIfNotNull(KeymasterDefs.KM_TAG_ACTIVE_DATETIME,
- params.getKeyValidityStart());
- args.addDateIfNotNull(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME,
- params.getKeyValidityForOriginationEnd());
- args.addDateIfNotNull(KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME,
- params.getKeyValidityForConsumptionEnd());
-
- if (((purposes & KeyProperties.PURPOSE_ENCRYPT) != 0)
- && (!params.isRandomizedEncryptionRequired())) {
- // Permit caller-provided IV when encrypting with this key
- args.addBoolean(KeymasterDefs.KM_TAG_CALLER_NONCE);
- }
- } catch (IllegalArgumentException | IllegalStateException e) {
- throw new KeyStoreException(e);
- }
- int flags = 0;
- if (params.isCriticalToDeviceEncryption()) {
- flags |= KeyStore.FLAG_CRITICAL_TO_DEVICE_ENCRYPTION;
- }
- if (params.isStrongBoxBacked()) {
- flags |= KeyStore.FLAG_STRONGBOX;
- }
-
- Credentials.deleteAllTypesForAlias(mKeyStore, entryAlias, mUid);
- String keyAliasInKeystore = Credentials.USER_PRIVATE_KEY + entryAlias;
- int errorCode = mKeyStore.importKey(
- keyAliasInKeystore,
- args,
- KeymasterDefs.KM_KEY_FORMAT_RAW,
- keyMaterial,
- mUid,
- flags,
- new KeyCharacteristics());
- if (errorCode != KeyStore.NO_ERROR) {
- throw new KeyStoreException("Failed to import secret key. Keystore error code: "
- + errorCode);
- }
- }
-
- private void setWrappedKeyEntry(String alias, WrappedKeyEntry entry,
- java.security.KeyStore.ProtectionParameter param) throws KeyStoreException {
- if (param != null) {
- throw new KeyStoreException("Protection parameters are specified inside wrapped keys");
- }
-
- byte[] maskingKey = new byte[32];
-
-
- KeymasterArguments args = new KeymasterArguments();
- String[] parts = entry.getTransformation().split("/");
-
- String algorithm = parts[0];
- if (KeyProperties.KEY_ALGORITHM_RSA.equalsIgnoreCase(algorithm)) {
- args.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_RSA);
- } else if (KeyProperties.KEY_ALGORITHM_EC.equalsIgnoreCase(algorithm)) {
- args.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_RSA);
- }
-
- if (parts.length > 1) {
- String mode = parts[1];
- if (KeyProperties.BLOCK_MODE_ECB.equalsIgnoreCase(mode)) {
- args.addEnums(KeymasterDefs.KM_TAG_BLOCK_MODE, KeymasterDefs.KM_MODE_ECB);
- } else if (KeyProperties.BLOCK_MODE_CBC.equalsIgnoreCase(mode)) {
- args.addEnums(KeymasterDefs.KM_TAG_BLOCK_MODE, KeymasterDefs.KM_MODE_CBC);
- } else if (KeyProperties.BLOCK_MODE_CTR.equalsIgnoreCase(mode)) {
- args.addEnums(KeymasterDefs.KM_TAG_BLOCK_MODE, KeymasterDefs.KM_MODE_CTR);
- } else if (KeyProperties.BLOCK_MODE_GCM.equalsIgnoreCase(mode)) {
- args.addEnums(KeymasterDefs.KM_TAG_BLOCK_MODE, KeymasterDefs.KM_MODE_GCM);
- }
- }
-
- if (parts.length > 2) {
- String padding = parts[2];
- if (KeyProperties.ENCRYPTION_PADDING_NONE.equalsIgnoreCase(padding)) {
- // Noop
- } else if (KeyProperties.ENCRYPTION_PADDING_PKCS7.equalsIgnoreCase(padding)) {
- args.addEnums(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_PKCS7);
- } else if (KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1.equalsIgnoreCase(padding)) {
- args.addEnums(KeymasterDefs.KM_TAG_PADDING,
- KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_ENCRYPT);
- } else if (KeyProperties.ENCRYPTION_PADDING_RSA_OAEP.equalsIgnoreCase(padding)) {
- args.addEnums(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_RSA_OAEP);
- }
- }
-
- KeyGenParameterSpec spec = (KeyGenParameterSpec) entry.getAlgorithmParameterSpec();
- if (spec.isDigestsSpecified()) {
- String digest = spec.getDigests()[0];
- if (KeyProperties.DIGEST_NONE.equalsIgnoreCase(digest)) {
- // Noop
- } else if (KeyProperties.DIGEST_MD5.equalsIgnoreCase(digest)) {
- args.addEnums(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_MD5);
- } else if (KeyProperties.DIGEST_SHA1.equalsIgnoreCase(digest)) {
- args.addEnums(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA1);
- } else if (KeyProperties.DIGEST_SHA224.equalsIgnoreCase(digest)) {
- args.addEnums(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA_2_224);
- } else if (KeyProperties.DIGEST_SHA256.equalsIgnoreCase(digest)) {
- args.addEnums(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA_2_256);
- } else if (KeyProperties.DIGEST_SHA384.equalsIgnoreCase(digest)) {
- args.addEnums(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA_2_384);
- } else if (KeyProperties.DIGEST_SHA512.equalsIgnoreCase(digest)) {
- args.addEnums(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA_2_512);
- }
- }
-
- int errorCode = mKeyStore.importWrappedKey(
- Credentials.USER_PRIVATE_KEY + alias,
- entry.getWrappedKeyBytes(),
- Credentials.USER_PRIVATE_KEY + entry.getWrappingKeyAlias(),
- maskingKey,
- args,
- GateKeeper.getSecureUserId(),
- 0, // FIXME fingerprint id?
- mUid,
- new KeyCharacteristics());
- if (errorCode == KeymasterDefs.KM_ERROR_UNIMPLEMENTED) {
- throw new SecureKeyImportUnavailableException("Could not import wrapped key");
- } else if (errorCode != KeyStore.NO_ERROR) {
- throw new KeyStoreException("Failed to import wrapped key. Keystore error code: "
- + errorCode);
- }
- }
-
- @Override
- public void engineSetKeyEntry(String alias, byte[] userKey, Certificate[] chain)
- throws KeyStoreException {
- throw new KeyStoreException("Operation not supported because key encoding is unknown");
- }
-
- @Override
- public void engineSetCertificateEntry(String alias, Certificate cert) throws KeyStoreException {
- if (isKeyEntry(alias)) {
- throw new KeyStoreException("Entry exists and is not a trusted certificate");
- }
-
- // We can't set something to null.
- if (cert == null) {
- throw new NullPointerException("cert == null");
- }
-
- final byte[] encoded;
- try {
- encoded = cert.getEncoded();
- } catch (CertificateEncodingException e) {
- throw new KeyStoreException(e);
- }
-
- if (!mKeyStore.put(Credentials.CA_CERTIFICATE + alias, encoded, mUid, KeyStore.FLAG_NONE)) {
- throw new KeyStoreException("Couldn't insert certificate; is KeyStore initialized?");
- }
- }
-
- @Override
- public void engineDeleteEntry(String alias) throws KeyStoreException {
- if (!Credentials.deleteAllTypesForAlias(mKeyStore, alias, mUid)) {
- throw new KeyStoreException("Failed to delete entry: " + alias);
- }
- }
-
- private Set<String> getUniqueAliases() {
- final String[] rawAliases = mKeyStore.list("", mUid);
- if (rawAliases == null) {
- return new HashSet<String>();
- }
-
- final Set<String> aliases = new HashSet<String>(rawAliases.length);
- for (String alias : rawAliases) {
- final int idx = alias.indexOf('_');
- if ((idx == -1) || (alias.length() <= idx)) {
- Log.e(NAME, "invalid alias: " + alias);
- continue;
- }
-
- aliases.add(new String(alias.substring(idx + 1)));
- }
-
- return aliases;
- }
-
- @Override
- public Enumeration<String> engineAliases() {
- return Collections.enumeration(getUniqueAliases());
- }
-
- @Override
- public boolean engineContainsAlias(String alias) {
- if (alias == null) {
- throw new NullPointerException("alias == null");
- }
-
- return mKeyStore.contains(Credentials.USER_PRIVATE_KEY + alias, mUid)
- || mKeyStore.contains(Credentials.USER_SECRET_KEY + alias, mUid)
- || mKeyStore.contains(Credentials.USER_CERTIFICATE + alias, mUid)
- || mKeyStore.contains(Credentials.CA_CERTIFICATE + alias, mUid);
- }
-
- @Override
- public int engineSize() {
- return getUniqueAliases().size();
- }
-
- @Override
- public boolean engineIsKeyEntry(String alias) {
- return isKeyEntry(alias);
- }
-
- private boolean isKeyEntry(String alias) {
- return mKeyStore.contains(Credentials.USER_PRIVATE_KEY + alias, mUid) ||
- mKeyStore.contains(Credentials.USER_SECRET_KEY + alias, mUid);
- }
-
-
- private boolean isCertificateEntry(String alias) {
- if (alias == null) {
- throw new NullPointerException("alias == null");
- }
-
- return mKeyStore.contains(Credentials.CA_CERTIFICATE + alias, mUid);
- }
-
- @Override
- public boolean engineIsCertificateEntry(String alias) {
- return !isKeyEntry(alias) && isCertificateEntry(alias);
- }
-
- @Override
- public String engineGetCertificateAlias(Certificate cert) {
- if (cert == null) {
- return null;
- }
- if (!"X.509".equalsIgnoreCase(cert.getType())) {
- // Only X.509 certificates supported
- return null;
- }
- byte[] targetCertBytes;
- try {
- targetCertBytes = cert.getEncoded();
- } catch (CertificateEncodingException e) {
- return null;
- }
- if (targetCertBytes == null) {
- return null;
- }
-
- final Set<String> nonCaEntries = new HashSet<String>();
-
- /*
- * First scan the PrivateKeyEntry types. The KeyStoreSpi documentation
- * says to only compare the first certificate in the chain which is
- * equivalent to the USER_CERTIFICATE prefix for the Android keystore
- * convention.
- */
- final String[] certAliases = mKeyStore.list(Credentials.USER_CERTIFICATE, mUid);
- if (certAliases != null) {
- for (String alias : certAliases) {
- final byte[] certBytes = mKeyStore.get(Credentials.USER_CERTIFICATE + alias, mUid);
- if (certBytes == null) {
- continue;
- }
-
- nonCaEntries.add(alias);
-
- if (Arrays.equals(certBytes, targetCertBytes)) {
- return alias;
- }
- }
- }
-
- /*
- * Look at all the TrustedCertificateEntry types. Skip all the
- * PrivateKeyEntry we looked at above.
- */
- final String[] caAliases = mKeyStore.list(Credentials.CA_CERTIFICATE, mUid);
- if (certAliases != null) {
- for (String alias : caAliases) {
- if (nonCaEntries.contains(alias)) {
- continue;
- }
-
- final byte[] certBytes = mKeyStore.get(Credentials.CA_CERTIFICATE + alias, mUid);
- if (certBytes == null) {
- continue;
- }
-
- if (Arrays.equals(certBytes, targetCertBytes)) {
- return alias;
- }
- }
- }
-
- return null;
- }
-
- @Override
- public void engineStore(OutputStream stream, char[] password) throws IOException,
- NoSuchAlgorithmException, CertificateException {
- throw new UnsupportedOperationException("Can not serialize AndroidKeyStore to OutputStream");
- }
-
- @Override
- public void engineLoad(InputStream stream, char[] password) throws IOException,
- NoSuchAlgorithmException, CertificateException {
- if (stream != null) {
- throw new IllegalArgumentException("InputStream not supported");
- }
-
- if (password != null) {
- throw new IllegalArgumentException("password not supported");
- }
-
- // Unfortunate name collision.
- mKeyStore = KeyStore.getInstance();
- mUid = KeyStore.UID_SELF;
- }
-
- @Override
- public void engineLoad(LoadStoreParameter param) throws IOException,
- NoSuchAlgorithmException, CertificateException {
- int uid = KeyStore.UID_SELF;
- if (param != null) {
- if (param instanceof AndroidKeyStoreLoadStoreParameter) {
- uid = ((AndroidKeyStoreLoadStoreParameter) param).getUid();
- } else {
- throw new IllegalArgumentException(
- "Unsupported param type: " + param.getClass());
- }
- }
- mKeyStore = KeyStore.getInstance();
- mUid = uid;
- }
-
- @Override
- public void engineSetEntry(String alias, Entry entry, ProtectionParameter param)
- throws KeyStoreException {
- if (entry == null) {
- throw new KeyStoreException("entry == null");
- }
-
- Credentials.deleteAllTypesForAlias(mKeyStore, alias, mUid);
-
- if (entry instanceof java.security.KeyStore.TrustedCertificateEntry) {
- java.security.KeyStore.TrustedCertificateEntry trE =
- (java.security.KeyStore.TrustedCertificateEntry) entry;
- engineSetCertificateEntry(alias, trE.getTrustedCertificate());
- return;
- }
-
- if (entry instanceof PrivateKeyEntry) {
- PrivateKeyEntry prE = (PrivateKeyEntry) entry;
- setPrivateKeyEntry(alias, prE.getPrivateKey(), prE.getCertificateChain(), param);
- } else if (entry instanceof SecretKeyEntry) {
- SecretKeyEntry secE = (SecretKeyEntry) entry;
- setSecretKeyEntry(alias, secE.getSecretKey(), param);
- } else if (entry instanceof WrappedKeyEntry) {
- WrappedKeyEntry wke = (WrappedKeyEntry) entry;
- setWrappedKeyEntry(alias, wke, param);
- } else {
- throw new KeyStoreException(
- "Entry must be a PrivateKeyEntry, SecretKeyEntry or TrustedCertificateEntry"
- + "; was " + entry);
- }
- }
-
- /**
- * {@link X509Certificate} which returns {@link AndroidKeyStorePublicKey} from
- * {@link #getPublicKey()}. This is so that crypto operations on these public keys contain
- * can find out which keystore private key entry to use. This is needed so that Android Keystore
- * crypto operations using public keys can find out which key alias to use. These operations
- * require an alias.
- */
- static class KeyStoreX509Certificate extends DelegatingX509Certificate {
- private final String mPrivateKeyAlias;
- private final int mPrivateKeyUid;
- KeyStoreX509Certificate(String privateKeyAlias, int privateKeyUid,
- X509Certificate delegate) {
- super(delegate);
- mPrivateKeyAlias = privateKeyAlias;
- mPrivateKeyUid = privateKeyUid;
- }
-
- @Override
- public PublicKey getPublicKey() {
- PublicKey original = super.getPublicKey();
- return AndroidKeyStoreProvider.getAndroidKeyStorePublicKey(
- mPrivateKeyAlias, mPrivateKeyUid,
- original.getAlgorithm(), original.getEncoded());
- }
- }
-}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreUnauthenticatedAESCipherSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreUnauthenticatedAESCipherSpi.java
deleted file mode 100644
index 1f1d36f..0000000
--- a/keystore/java/android/security/keystore/AndroidKeyStoreUnauthenticatedAESCipherSpi.java
+++ /dev/null
@@ -1,319 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.keystore;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.security.keymaster.KeymasterArguments;
-import android.security.keymaster.KeymasterDefs;
-
-import java.security.AlgorithmParameters;
-import java.security.InvalidAlgorithmParameterException;
-import java.security.InvalidKeyException;
-import java.security.Key;
-import java.security.NoSuchAlgorithmException;
-import java.security.ProviderException;
-import java.security.spec.AlgorithmParameterSpec;
-import java.security.spec.InvalidParameterSpecException;
-import java.util.Arrays;
-
-import javax.crypto.CipherSpi;
-import javax.crypto.spec.IvParameterSpec;
-
-/**
- * Base class for Android Keystore unauthenticated AES {@link CipherSpi} implementations.
- *
- * @hide
- */
-class AndroidKeyStoreUnauthenticatedAESCipherSpi extends AndroidKeyStoreCipherSpiBase {
-
- abstract static class ECB extends AndroidKeyStoreUnauthenticatedAESCipherSpi {
- protected ECB(int keymasterPadding) {
- super(KeymasterDefs.KM_MODE_ECB, keymasterPadding, false);
- }
-
- public static class NoPadding extends ECB {
- public NoPadding() {
- super(KeymasterDefs.KM_PAD_NONE);
- }
- }
-
- public static class PKCS7Padding extends ECB {
- public PKCS7Padding() {
- super(KeymasterDefs.KM_PAD_PKCS7);
- }
- }
- }
-
- abstract static class CBC extends AndroidKeyStoreUnauthenticatedAESCipherSpi {
- protected CBC(int keymasterPadding) {
- super(KeymasterDefs.KM_MODE_CBC, keymasterPadding, true);
- }
-
- public static class NoPadding extends CBC {
- public NoPadding() {
- super(KeymasterDefs.KM_PAD_NONE);
- }
- }
-
- public static class PKCS7Padding extends CBC {
- public PKCS7Padding() {
- super(KeymasterDefs.KM_PAD_PKCS7);
- }
- }
- }
-
- abstract static class CTR extends AndroidKeyStoreUnauthenticatedAESCipherSpi {
- protected CTR(int keymasterPadding) {
- super(KeymasterDefs.KM_MODE_CTR, keymasterPadding, true);
- }
-
- public static class NoPadding extends CTR {
- public NoPadding() {
- super(KeymasterDefs.KM_PAD_NONE);
- }
- }
- }
-
- private static final int BLOCK_SIZE_BYTES = 16;
-
- private final int mKeymasterBlockMode;
- private final int mKeymasterPadding;
- /** Whether this transformation requires an IV. */
- private final boolean mIvRequired;
-
- private byte[] mIv;
-
- /** Whether the current {@code #mIv} has been used by the underlying crypto operation. */
- private boolean mIvHasBeenUsed;
-
- AndroidKeyStoreUnauthenticatedAESCipherSpi(
- int keymasterBlockMode,
- int keymasterPadding,
- boolean ivRequired) {
- mKeymasterBlockMode = keymasterBlockMode;
- mKeymasterPadding = keymasterPadding;
- mIvRequired = ivRequired;
- }
-
- @Override
- protected final void resetAll() {
- mIv = null;
- mIvHasBeenUsed = false;
- super.resetAll();
- }
-
- @Override
- protected final void resetWhilePreservingInitState() {
- super.resetWhilePreservingInitState();
- }
-
- @Override
- protected final void initKey(int opmode, Key key) throws InvalidKeyException {
- if (!(key instanceof AndroidKeyStoreSecretKey)) {
- throw new InvalidKeyException(
- "Unsupported key: " + ((key != null) ? key.getClass().getName() : "null"));
- }
- if (!KeyProperties.KEY_ALGORITHM_AES.equalsIgnoreCase(key.getAlgorithm())) {
- throw new InvalidKeyException(
- "Unsupported key algorithm: " + key.getAlgorithm() + ". Only " +
- KeyProperties.KEY_ALGORITHM_AES + " supported");
- }
- setKey((AndroidKeyStoreSecretKey) key);
- }
-
- @Override
- protected final void initAlgorithmSpecificParameters() throws InvalidKeyException {
- if (!mIvRequired) {
- return;
- }
-
- // IV is used
- if (!isEncrypting()) {
- throw new InvalidKeyException("IV required when decrypting"
- + ". Use IvParameterSpec or AlgorithmParameters to provide it.");
- }
- }
-
- @Override
- protected final void initAlgorithmSpecificParameters(AlgorithmParameterSpec params)
- throws InvalidAlgorithmParameterException {
- if (!mIvRequired) {
- if (params != null) {
- throw new InvalidAlgorithmParameterException("Unsupported parameters: " + params);
- }
- return;
- }
-
- // IV is used
- if (params == null) {
- if (!isEncrypting()) {
- // IV must be provided by the caller
- throw new InvalidAlgorithmParameterException(
- "IvParameterSpec must be provided when decrypting");
- }
- return;
- }
- if (!(params instanceof IvParameterSpec)) {
- throw new InvalidAlgorithmParameterException("Only IvParameterSpec supported");
- }
- mIv = ((IvParameterSpec) params).getIV();
- if (mIv == null) {
- throw new InvalidAlgorithmParameterException("Null IV in IvParameterSpec");
- }
- }
-
- @Override
- protected final void initAlgorithmSpecificParameters(AlgorithmParameters params)
- throws InvalidAlgorithmParameterException {
- if (!mIvRequired) {
- if (params != null) {
- throw new InvalidAlgorithmParameterException("Unsupported parameters: " + params);
- }
- return;
- }
-
- // IV is used
- if (params == null) {
- if (!isEncrypting()) {
- // IV must be provided by the caller
- throw new InvalidAlgorithmParameterException("IV required when decrypting"
- + ". Use IvParameterSpec or AlgorithmParameters to provide it.");
- }
- return;
- }
-
- if (!"AES".equalsIgnoreCase(params.getAlgorithm())) {
- throw new InvalidAlgorithmParameterException(
- "Unsupported AlgorithmParameters algorithm: " + params.getAlgorithm()
- + ". Supported: AES");
- }
-
- IvParameterSpec ivSpec;
- try {
- ivSpec = params.getParameterSpec(IvParameterSpec.class);
- } catch (InvalidParameterSpecException e) {
- if (!isEncrypting()) {
- // IV must be provided by the caller
- throw new InvalidAlgorithmParameterException("IV required when decrypting"
- + ", but not found in parameters: " + params, e);
- }
- mIv = null;
- return;
- }
- mIv = ivSpec.getIV();
- if (mIv == null) {
- throw new InvalidAlgorithmParameterException("Null IV in AlgorithmParameters");
- }
- }
-
- @Override
- protected final int getAdditionalEntropyAmountForBegin() {
- if ((mIvRequired) && (mIv == null) && (isEncrypting())) {
- // IV will need to be generated
- return BLOCK_SIZE_BYTES;
- }
-
- return 0;
- }
-
- @Override
- protected final int getAdditionalEntropyAmountForFinish() {
- return 0;
- }
-
- @Override
- protected final void addAlgorithmSpecificParametersToBegin(
- @NonNull KeymasterArguments keymasterArgs) {
- if ((isEncrypting()) && (mIvRequired) && (mIvHasBeenUsed)) {
- // IV is being reused for encryption: this violates security best practices.
- throw new IllegalStateException(
- "IV has already been used. Reusing IV in encryption mode violates security best"
- + " practices.");
- }
-
- keymasterArgs.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_AES);
- keymasterArgs.addEnum(KeymasterDefs.KM_TAG_BLOCK_MODE, mKeymasterBlockMode);
- keymasterArgs.addEnum(KeymasterDefs.KM_TAG_PADDING, mKeymasterPadding);
- if ((mIvRequired) && (mIv != null)) {
- keymasterArgs.addBytes(KeymasterDefs.KM_TAG_NONCE, mIv);
- }
- }
-
- @Override
- protected final void loadAlgorithmSpecificParametersFromBeginResult(
- @NonNull KeymasterArguments keymasterArgs) {
- mIvHasBeenUsed = true;
-
- // NOTE: Keymaster doesn't always return an IV, even if it's used.
- byte[] returnedIv = keymasterArgs.getBytes(KeymasterDefs.KM_TAG_NONCE, null);
- if ((returnedIv != null) && (returnedIv.length == 0)) {
- returnedIv = null;
- }
-
- if (mIvRequired) {
- if (mIv == null) {
- mIv = returnedIv;
- } else if ((returnedIv != null) && (!Arrays.equals(returnedIv, mIv))) {
- throw new ProviderException("IV in use differs from provided IV");
- }
- } else {
- if (returnedIv != null) {
- throw new ProviderException(
- "IV in use despite IV not being used by this transformation");
- }
- }
- }
-
- @Override
- protected final int engineGetBlockSize() {
- return BLOCK_SIZE_BYTES;
- }
-
- @Override
- protected final int engineGetOutputSize(int inputLen) {
- return inputLen + 3 * BLOCK_SIZE_BYTES;
- }
-
- @Override
- protected final byte[] engineGetIV() {
- return ArrayUtils.cloneIfNotEmpty(mIv);
- }
-
- @Nullable
- @Override
- protected final AlgorithmParameters engineGetParameters() {
- if (!mIvRequired) {
- return null;
- }
- if ((mIv != null) && (mIv.length > 0)) {
- try {
- AlgorithmParameters params = AlgorithmParameters.getInstance("AES");
- params.init(new IvParameterSpec(mIv));
- return params;
- } catch (NoSuchAlgorithmException e) {
- throw new ProviderException(
- "Failed to obtain AES AlgorithmParameters", e);
- } catch (InvalidParameterSpecException e) {
- throw new ProviderException(
- "Failed to initialize AES AlgorithmParameters with an IV",
- e);
- }
- }
- return null;
- }
-}
diff --git a/keystore/java/android/security/keystore/AttestationUtils.java b/keystore/java/android/security/keystore/AttestationUtils.java
index 1eb8541..be865a0 100644
--- a/keystore/java/android/security/keystore/AttestationUtils.java
+++ b/keystore/java/android/security/keystore/AttestationUtils.java
@@ -36,9 +36,11 @@
import java.security.KeyPairGenerator;
import java.security.KeyStore;
import java.security.SecureRandom;
+import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.spec.ECGenParameterSpec;
+import java.util.Arrays;
import java.util.Collection;
import java.util.Random;
import java.util.Set;
@@ -281,8 +283,9 @@
KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
keyStore.load(null);
+ Certificate[] certs = keyStore.getCertificateChain(keystoreAlias);
X509Certificate[] certificateChain =
- (X509Certificate[]) keyStore.getCertificateChain(keystoreAlias);
+ Arrays.copyOf(certs, certs.length, X509Certificate[].class);
keyStore.deleteEntry(keystoreAlias);
diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
index 9ca551b..1f9022b 100644
--- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java
+++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
@@ -446,13 +446,6 @@
@UnsupportedAppUsage
@Deprecated
public int getUid() {
- if (!AndroidKeyStoreProvider.isKeystore2Enabled()) {
- // If Keystore2 has not been enabled we have to behave as if mNamespace is actually
- // a UID, because we are still being used with the old Keystore SPI.
- // TODO This if statement and body can be removed when the Keystore 2 migration is
- // complete. b/171563717
- return mNamespace;
- }
try {
return KeyProperties.namespaceToLegacyUid(mNamespace);
} catch (IllegalArgumentException e) {
@@ -1021,14 +1014,6 @@
@NonNull
@Deprecated
public Builder setUid(int uid) {
- if (!AndroidKeyStoreProvider.isKeystore2Enabled()) {
- // If Keystore2 has not been enabled we have to behave as if mNamespace is actually
- // a UID, because we are still being used with the old Keystore SPI.
- // TODO This if statement and body can be removed when the Keystore 2 migration is
- // complete. b/171563717
- mNamespace = uid;
- return this;
- }
mNamespace = KeyProperties.legacyUidToNamespace(uid);
return this;
}
@@ -1666,9 +1651,10 @@
* Set whether this key is critical to the device encryption flow
*
* This is a special flag only available to system servers to indicate the current key
- * is part of the device encryption flow.
+ * is part of the device encryption flow. Setting this flag causes the key to not
+ * be cryptographically bound to the LSKF even if the key is otherwise authentication
+ * bound.
*
- * @see android.security.KeyStore#FLAG_CRITICAL_TO_DEVICE_ENCRYPTION
* @hide
*/
public Builder setCriticalToDeviceEncryption(boolean critical) {
diff --git a/keystore/java/android/security/keystore/KeyProtection.java b/keystore/java/android/security/keystore/KeyProtection.java
index 673491e..88d1a5b 100644
--- a/keystore/java/android/security/keystore/KeyProtection.java
+++ b/keystore/java/android/security/keystore/KeyProtection.java
@@ -24,6 +24,7 @@
import android.hardware.biometrics.BiometricManager;
import android.hardware.biometrics.BiometricPrompt;
import android.security.GateKeeper;
+import android.security.keystore2.KeymasterUtils;
import java.security.Key;
import java.security.KeyStore.ProtectionParameter;
diff --git a/keystore/java/android/security/keystore/KeyStoreCryptoOperationChunkedStreamer.java b/keystore/java/android/security/keystore/KeyStoreCryptoOperationChunkedStreamer.java
deleted file mode 100644
index 2c0f40d..0000000
--- a/keystore/java/android/security/keystore/KeyStoreCryptoOperationChunkedStreamer.java
+++ /dev/null
@@ -1,225 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.keystore;
-
-import android.os.IBinder;
-import android.security.KeyStore;
-import android.security.KeyStoreException;
-import android.security.keymaster.KeymasterDefs;
-import android.security.keymaster.OperationResult;
-
-import libcore.util.EmptyArray;
-
-/**
- * Helper for streaming a crypto operation's input and output via {@link KeyStore} service's
- * {@code update} and {@code finish} operations.
- *
- * <p>The helper abstracts away issues that need to be solved in most code that uses KeyStore's
- * update and finish operations. Firstly, KeyStore's update operation can consume only a limited
- * amount of data in one go because the operations are marshalled via Binder. Secondly, the update
- * operation may consume less data than provided, in which case the caller has to buffer the
- * remainder for next time. Thirdly, when the input is smaller than a threshold, skipping update
- * and passing input data directly to final improves performance. This threshold is configurable;
- * using a threshold <= 1 causes the helper act eagerly, which may be required for some types of
- * operations (e.g. ciphers).
- *
- * <p>The helper exposes {@link #update(byte[], int, int) update} and
- * {@link #doFinal(byte[], int, int, byte[], byte[]) doFinal} operations which can be used to
- * conveniently implement various JCA crypto primitives.
- *
- * <p>Bidirectional chunked streaming of data via a KeyStore crypto operation is abstracted away as
- * a {@link Stream} to avoid having this class deal with operation tokens and occasional additional
- * parameters to {@code update} and {@code final} operations.
- *
- * @hide
- */
-class KeyStoreCryptoOperationChunkedStreamer implements KeyStoreCryptoOperationStreamer {
-
- /**
- * Bidirectional chunked data stream over a KeyStore crypto operation.
- */
- interface Stream {
- /**
- * Returns the result of the KeyStore {@code update} operation or null if keystore couldn't
- * be reached.
- */
- OperationResult update(byte[] input);
-
- /**
- * Returns the result of the KeyStore {@code finish} operation or null if keystore couldn't
- * be reached.
- */
- OperationResult finish(byte[] input, byte[] siganture, byte[] additionalEntropy);
- }
-
- // Binder buffer is about 1MB, but it's shared between all active transactions of the process.
- // Thus, it's safer to use a much smaller upper bound.
- private static final int DEFAULT_CHUNK_SIZE_MAX = 64 * 1024;
- // The chunk buffer will be sent to update until its size under this threshold.
- // This threshold should be <= the max input allowed for finish.
- // Setting this threshold <= 1 will effectivley disable buffering between updates.
- private static final int DEFAULT_CHUNK_SIZE_THRESHOLD = 2 * 1024;
-
- private final Stream mKeyStoreStream;
- private final int mChunkSizeMax;
- private final int mChunkSizeThreshold;
- private final byte[] mChunk;
- private int mChunkLength = 0;
- private long mConsumedInputSizeBytes;
- private long mProducedOutputSizeBytes;
-
- KeyStoreCryptoOperationChunkedStreamer(Stream operation) {
- this(operation, DEFAULT_CHUNK_SIZE_THRESHOLD, DEFAULT_CHUNK_SIZE_MAX);
- }
-
- KeyStoreCryptoOperationChunkedStreamer(Stream operation, int chunkSizeThreshold) {
- this(operation, chunkSizeThreshold, DEFAULT_CHUNK_SIZE_MAX);
- }
-
- KeyStoreCryptoOperationChunkedStreamer(Stream operation, int chunkSizeThreshold,
- int chunkSizeMax) {
- mKeyStoreStream = operation;
- mChunkSizeMax = chunkSizeMax;
- if (chunkSizeThreshold <= 0) {
- mChunkSizeThreshold = 1;
- } else if (chunkSizeThreshold > chunkSizeMax) {
- mChunkSizeThreshold = chunkSizeMax;
- } else {
- mChunkSizeThreshold = chunkSizeThreshold;
- }
- mChunk = new byte[mChunkSizeMax];
- }
-
- public byte[] update(byte[] input, int inputOffset, int inputLength) throws KeyStoreException {
- if (inputLength == 0 || input == null) {
- // No input provided
- return EmptyArray.BYTE;
- }
- if (inputLength < 0 || inputOffset < 0 || (inputOffset + inputLength) > input.length) {
- throw new KeyStoreException(KeymasterDefs.KM_ERROR_UNKNOWN_ERROR,
- "Input offset and length out of bounds of input array");
- }
-
- byte[] output = EmptyArray.BYTE;
-
- while (inputLength > 0 || mChunkLength >= mChunkSizeThreshold) {
- int inputConsumed = ArrayUtils.copy(input, inputOffset, mChunk, mChunkLength,
- inputLength);
- inputLength -= inputConsumed;
- inputOffset += inputConsumed;
- mChunkLength += inputConsumed;
- mConsumedInputSizeBytes += inputConsumed;
-
- if (mChunkLength > mChunkSizeMax) {
- throw new KeyStoreException(KeymasterDefs.KM_ERROR_INVALID_INPUT_LENGTH,
- "Chunk size exceeded max chunk size. Max: " + mChunkSizeMax
- + " Actual: " + mChunkLength);
- }
-
- if (mChunkLength >= mChunkSizeThreshold) {
- OperationResult opResult = mKeyStoreStream.update(
- ArrayUtils.subarray(mChunk, 0, mChunkLength));
-
- if (opResult == null) {
- throw new KeyStoreConnectException();
- } else if (opResult.resultCode != KeyStore.NO_ERROR) {
- throw KeyStore.getKeyStoreException(opResult.resultCode);
- }
- if (opResult.inputConsumed <= 0) {
- throw new KeyStoreException(KeymasterDefs.KM_ERROR_INVALID_INPUT_LENGTH,
- "Keystore consumed 0 of " + mChunkLength + " bytes provided.");
- } else if (opResult.inputConsumed > mChunkLength) {
- throw new KeyStoreException(KeymasterDefs.KM_ERROR_UNKNOWN_ERROR,
- "Keystore consumed more input than provided. Provided: "
- + mChunkLength + ", consumed: " + opResult.inputConsumed);
- }
- mChunkLength -= opResult.inputConsumed;
-
- if (mChunkLength > 0) {
- // Partialy consumed, shift chunk contents
- ArrayUtils.copy(mChunk, opResult.inputConsumed, mChunk, 0, mChunkLength);
- }
-
- if ((opResult.output != null) && (opResult.output.length > 0)) {
- // Output was produced
- mProducedOutputSizeBytes += opResult.output.length;
- output = ArrayUtils.concat(output, opResult.output);
- }
- }
- }
- return output;
- }
-
- public byte[] doFinal(byte[] input, int inputOffset, int inputLength,
- byte[] signature, byte[] additionalEntropy) throws KeyStoreException {
- byte[] output = update(input, inputOffset, inputLength);
- byte[] finalChunk = ArrayUtils.subarray(mChunk, 0, mChunkLength);
- OperationResult opResult = mKeyStoreStream.finish(finalChunk, signature, additionalEntropy);
-
- if (opResult == null) {
- throw new KeyStoreConnectException();
- } else if (opResult.resultCode != KeyStore.NO_ERROR) {
- throw KeyStore.getKeyStoreException(opResult.resultCode);
- }
- // If no error, assume all input consumed
- mConsumedInputSizeBytes += finalChunk.length;
-
- if ((opResult.output != null) && (opResult.output.length > 0)) {
- mProducedOutputSizeBytes += opResult.output.length;
- output = ArrayUtils.concat(output, opResult.output);
- }
-
- return output;
- }
-
- @Override
- public long getConsumedInputSizeBytes() {
- return mConsumedInputSizeBytes;
- }
-
- @Override
- public long getProducedOutputSizeBytes() {
- return mProducedOutputSizeBytes;
- }
-
- /**
- * Main data stream via a KeyStore streaming operation.
- *
- * <p>For example, for an encryption operation, this is the stream through which plaintext is
- * provided and ciphertext is obtained.
- */
- public static class MainDataStream implements Stream {
-
- private final KeyStore mKeyStore;
- private final IBinder mOperationToken;
-
- public MainDataStream(KeyStore keyStore, IBinder operationToken) {
- mKeyStore = keyStore;
- mOperationToken = operationToken;
- }
-
- @Override
- public OperationResult update(byte[] input) {
- return mKeyStore.update(mOperationToken, null, input);
- }
-
- @Override
- public OperationResult finish(byte[] input, byte[] signature, byte[] additionalEntropy) {
- return mKeyStore.finish(mOperationToken, null, input, signature, additionalEntropy);
- }
- }
-}
diff --git a/keystore/java/android/security/keystore/KeyStoreCryptoOperationStreamer.java b/keystore/java/android/security/keystore/KeyStoreCryptoOperationStreamer.java
deleted file mode 100644
index 062c2d4..0000000
--- a/keystore/java/android/security/keystore/KeyStoreCryptoOperationStreamer.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.keystore;
-
-import android.security.KeyStore;
-import android.security.KeyStoreException;
-
-/**
- * Helper for streaming a crypto operation's input and output via {@link KeyStore} service's
- * {@code update} and {@code finish} operations.
- *
- * <p>The helper abstracts away to issues that need to be solved in most code that uses KeyStore's
- * update and finish operations. Firstly, KeyStore's update operation can consume only a limited
- * amount of data in one go because the operations are marshalled via Binder. Secondly, the update
- * operation may consume less data than provided, in which case the caller has to buffer the
- * remainder for next time. The helper exposes {@link #update(byte[], int, int) update} and
- * {@link #doFinal(byte[], int, int, byte[], byte[]) doFinal} operations which can be used to
- * conveniently implement various JCA crypto primitives.
- *
- * @hide
- */
-interface KeyStoreCryptoOperationStreamer {
- byte[] update(byte[] input, int inputOffset, int inputLength) throws KeyStoreException;
- byte[] doFinal(byte[] input, int inputOffset, int inputLength, byte[] signature,
- byte[] additionalEntropy) throws KeyStoreException;
- long getConsumedInputSizeBytes();
- long getProducedOutputSizeBytes();
-}
diff --git a/keystore/java/android/security/keystore/KeyStoreCryptoOperationUtils.java b/keystore/java/android/security/keystore/KeyStoreCryptoOperationUtils.java
deleted file mode 100644
index c82b6e6..0000000
--- a/keystore/java/android/security/keystore/KeyStoreCryptoOperationUtils.java
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.keystore;
-
-import android.security.KeyStore;
-import android.security.keymaster.KeymasterDefs;
-
-import libcore.util.EmptyArray;
-
-import java.security.GeneralSecurityException;
-import java.security.InvalidAlgorithmParameterException;
-import java.security.InvalidKeyException;
-import java.security.SecureRandom;
-
-/**
- * Assorted utility methods for implementing crypto operations on top of KeyStore.
- *
- * @hide
- */
-abstract class KeyStoreCryptoOperationUtils {
-
- private static volatile SecureRandom sRng;
-
- private KeyStoreCryptoOperationUtils() {}
-
- /**
- * Returns the {@link InvalidKeyException} to be thrown by the {@code init} method of
- * the crypto operation in response to {@code KeyStore.begin} operation or {@code null} if
- * the {@code init} method should succeed.
- */
- static InvalidKeyException getInvalidKeyExceptionForInit(
- KeyStore keyStore, AndroidKeyStoreKey key, int beginOpResultCode) {
- if (beginOpResultCode == KeyStore.NO_ERROR) {
- return null;
- }
-
- // An error occurred. However, some errors should not lead to init throwing an exception.
- // See below.
- InvalidKeyException e =
- keyStore.getInvalidKeyException(key.getAlias(), key.getUid(), beginOpResultCode);
- switch (beginOpResultCode) {
- case KeyStore.OP_AUTH_NEEDED:
- // Operation needs to be authorized by authenticating the user. Don't throw an
- // exception is such authentication is possible for this key
- // (UserNotAuthenticatedException). An example of when it's not possible is where
- // the key is permanently invalidated (KeyPermanentlyInvalidatedException).
- if (e instanceof UserNotAuthenticatedException) {
- return null;
- }
- break;
- }
- return e;
- }
-
- /**
- * Returns the exception to be thrown by the {@code Cipher.init} method of the crypto operation
- * in response to {@code KeyStore.begin} operation or {@code null} if the {@code init} method
- * should succeed.
- */
- public static GeneralSecurityException getExceptionForCipherInit(
- KeyStore keyStore, AndroidKeyStoreKey key, int beginOpResultCode) {
- if (beginOpResultCode == KeyStore.NO_ERROR) {
- return null;
- }
-
- // Cipher-specific cases
- switch (beginOpResultCode) {
- case KeymasterDefs.KM_ERROR_INVALID_NONCE:
- return new InvalidAlgorithmParameterException("Invalid IV");
- case KeymasterDefs.KM_ERROR_CALLER_NONCE_PROHIBITED:
- return new InvalidAlgorithmParameterException("Caller-provided IV not permitted");
- }
-
- // General cases
- return getInvalidKeyExceptionForInit(keyStore, key, beginOpResultCode);
- }
-
- /**
- * Returns the requested number of random bytes to mix into keystore/keymaster RNG.
- *
- * @param rng RNG from which to obtain the random bytes or {@code null} for the platform-default
- * RNG.
- */
- static byte[] getRandomBytesToMixIntoKeystoreRng(SecureRandom rng, int sizeBytes) {
- if (sizeBytes <= 0) {
- return EmptyArray.BYTE;
- }
- if (rng == null) {
- rng = getRng();
- }
- byte[] result = new byte[sizeBytes];
- rng.nextBytes(result);
- return result;
- }
-
- private static SecureRandom getRng() {
- // IMPLEMENTATION NOTE: It's OK to share a SecureRandom instance because SecureRandom is
- // required to be thread-safe.
- if (sRng == null) {
- sRng = new SecureRandom();
- }
- return sRng;
- }
-}
diff --git a/keystore/java/android/security/keystore/KeymasterUtils.java b/keystore/java/android/security/keystore/KeymasterUtils.java
deleted file mode 100644
index 670ef5e..0000000
--- a/keystore/java/android/security/keystore/KeymasterUtils.java
+++ /dev/null
@@ -1,241 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security.keystore;
-
-import android.hardware.biometrics.BiometricManager;
-import android.security.GateKeeper;
-import android.security.KeyStore;
-import android.security.keymaster.KeymasterArguments;
-import android.security.keymaster.KeymasterDefs;
-
-import java.security.ProviderException;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * @hide
- */
-public abstract class KeymasterUtils {
-
- private KeymasterUtils() {}
-
- public static int getDigestOutputSizeBits(int keymasterDigest) {
- switch (keymasterDigest) {
- case KeymasterDefs.KM_DIGEST_NONE:
- return -1;
- case KeymasterDefs.KM_DIGEST_MD5:
- return 128;
- case KeymasterDefs.KM_DIGEST_SHA1:
- return 160;
- case KeymasterDefs.KM_DIGEST_SHA_2_224:
- return 224;
- case KeymasterDefs.KM_DIGEST_SHA_2_256:
- return 256;
- case KeymasterDefs.KM_DIGEST_SHA_2_384:
- return 384;
- case KeymasterDefs.KM_DIGEST_SHA_2_512:
- return 512;
- default:
- throw new IllegalArgumentException("Unknown digest: " + keymasterDigest);
- }
- }
-
- public static boolean isKeymasterBlockModeIndCpaCompatibleWithSymmetricCrypto(
- int keymasterBlockMode) {
- switch (keymasterBlockMode) {
- case KeymasterDefs.KM_MODE_ECB:
- return false;
- case KeymasterDefs.KM_MODE_CBC:
- case KeymasterDefs.KM_MODE_CTR:
- case KeymasterDefs.KM_MODE_GCM:
- return true;
- default:
- throw new IllegalArgumentException("Unsupported block mode: " + keymasterBlockMode);
- }
- }
-
- public static boolean isKeymasterPaddingSchemeIndCpaCompatibleWithAsymmetricCrypto(
- int keymasterPadding) {
- switch (keymasterPadding) {
- case KeymasterDefs.KM_PAD_NONE:
- return false;
- case KeymasterDefs.KM_PAD_RSA_OAEP:
- case KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_ENCRYPT:
- return true;
- default:
- throw new IllegalArgumentException(
- "Unsupported asymmetric encryption padding scheme: " + keymasterPadding);
- }
- }
-
- private static void addSids(KeymasterArguments args, UserAuthArgs spec) {
- // If both biometric and credential are accepted, then just use the root sid from gatekeeper
- if (spec.getUserAuthenticationType() == (KeyProperties.AUTH_BIOMETRIC_STRONG
- | KeyProperties.AUTH_DEVICE_CREDENTIAL)) {
- if (spec.getBoundToSpecificSecureUserId() != GateKeeper.INVALID_SECURE_USER_ID) {
- args.addUnsignedLong(KeymasterDefs.KM_TAG_USER_SECURE_ID,
- KeymasterArguments.toUint64(spec.getBoundToSpecificSecureUserId()));
- } else {
- // The key is authorized for use for the specified amount of time after the user has
- // authenticated. Whatever unlocks the secure lock screen should authorize this key.
- args.addUnsignedLong(KeymasterDefs.KM_TAG_USER_SECURE_ID,
- KeymasterArguments.toUint64(getRootSid()));
- }
- } else {
- List<Long> sids = new ArrayList<>();
- if ((spec.getUserAuthenticationType() & KeyProperties.AUTH_BIOMETRIC_STRONG) != 0) {
- final BiometricManager bm = KeyStore.getApplicationContext()
- .getSystemService(BiometricManager.class);
-
- // TODO: Restore permission check in getAuthenticatorIds once the ID is no longer
- // needed here.
-
- final long[] biometricSids = bm.getAuthenticatorIds();
-
- if (biometricSids.length == 0) {
- throw new IllegalStateException(
- "At least one biometric must be enrolled to create keys requiring user"
- + " authentication for every use");
- }
-
- if (spec.getBoundToSpecificSecureUserId() != GateKeeper.INVALID_SECURE_USER_ID) {
- sids.add(spec.getBoundToSpecificSecureUserId());
- } else if (spec.isInvalidatedByBiometricEnrollment()) {
- // The biometric-only SIDs will change on biometric enrollment or removal of all
- // enrolled templates, invalidating the key.
- for (long sid : biometricSids) {
- sids.add(sid);
- }
- } else {
- // The root SID will *not* change on fingerprint enrollment, or removal of all
- // enrolled fingerprints, allowing the key to remain valid.
- sids.add(getRootSid());
- }
- } else if ((spec.getUserAuthenticationType() & KeyProperties.AUTH_DEVICE_CREDENTIAL)
- != 0) {
- sids.add(getRootSid());
- } else {
- throw new IllegalStateException("Invalid or no authentication type specified.");
- }
-
- for (int i = 0; i < sids.size(); i++) {
- args.addUnsignedLong(KeymasterDefs.KM_TAG_USER_SECURE_ID,
- KeymasterArguments.toUint64(sids.get(i)));
- }
- }
- }
-
- /**
- * Adds keymaster arguments to express the key's authorization policy supported by user
- * authentication.
- *
- * @param args The arguments sent to keymaster that need to be populated from the spec
- * @param spec The user authentication relevant portions of the spec passed in from the caller.
- * This spec will be translated into the relevant keymaster tags to be loaded into args.
- * @throws IllegalStateException if user authentication is required but the system is in a wrong
- * state (e.g., secure lock screen not set up) for generating or importing keys that
- * require user authentication.
- */
- public static void addUserAuthArgs(KeymasterArguments args, UserAuthArgs spec) {
-
- if (spec.isUserConfirmationRequired()) {
- args.addBoolean(KeymasterDefs.KM_TAG_TRUSTED_CONFIRMATION_REQUIRED);
- }
-
- if (spec.isUserPresenceRequired()) {
- args.addBoolean(KeymasterDefs.KM_TAG_TRUSTED_USER_PRESENCE_REQUIRED);
- }
-
- if (spec.isUnlockedDeviceRequired()) {
- args.addBoolean(KeymasterDefs.KM_TAG_UNLOCKED_DEVICE_REQUIRED);
- }
-
- if (!spec.isUserAuthenticationRequired()) {
- args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
- return;
- }
-
- if (spec.getUserAuthenticationValidityDurationSeconds() == 0) {
- // Every use of this key needs to be authorized by the user.
- addSids(args, spec);
- args.addEnum(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, spec.getUserAuthenticationType());
-
- if (spec.isUserAuthenticationValidWhileOnBody()) {
- throw new ProviderException("Key validity extension while device is on-body is not "
- + "supported for keys requiring fingerprint authentication");
- }
- } else {
- addSids(args, spec);
- args.addEnum(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, spec.getUserAuthenticationType());
- args.addUnsignedInt(KeymasterDefs.KM_TAG_AUTH_TIMEOUT,
- spec.getUserAuthenticationValidityDurationSeconds());
- if (spec.isUserAuthenticationValidWhileOnBody()) {
- args.addBoolean(KeymasterDefs.KM_TAG_ALLOW_WHILE_ON_BODY);
- }
- }
- }
-
- /**
- * Adds {@code KM_TAG_MIN_MAC_LENGTH} tag, if necessary, to the keymaster arguments for
- * generating or importing a key. This tag may only be needed for symmetric keys (e.g., HMAC,
- * AES-GCM).
- */
- public static void addMinMacLengthAuthorizationIfNecessary(KeymasterArguments args,
- int keymasterAlgorithm,
- int[] keymasterBlockModes,
- int[] keymasterDigests) {
- switch (keymasterAlgorithm) {
- case KeymasterDefs.KM_ALGORITHM_AES:
- if (com.android.internal.util.ArrayUtils.contains(
- keymasterBlockModes, KeymasterDefs.KM_MODE_GCM)) {
- // AES GCM key needs the minimum length of AEAD tag specified.
- args.addUnsignedInt(KeymasterDefs.KM_TAG_MIN_MAC_LENGTH,
- AndroidKeyStoreAuthenticatedAESCipherSpi.GCM
- .MIN_SUPPORTED_TAG_LENGTH_BITS);
- }
- break;
- case KeymasterDefs.KM_ALGORITHM_HMAC:
- // HMAC key needs the minimum length of MAC set to the output size of the associated
- // digest. This is because we do not offer a way to generate shorter MACs and
- // don't offer a way to verify MACs (other than by generating them).
- if (keymasterDigests.length != 1) {
- throw new ProviderException(
- "Unsupported number of authorized digests for HMAC key: "
- + keymasterDigests.length
- + ". Exactly one digest must be authorized");
- }
- int keymasterDigest = keymasterDigests[0];
- int digestOutputSizeBits = getDigestOutputSizeBits(keymasterDigest);
- if (digestOutputSizeBits == -1) {
- throw new ProviderException(
- "HMAC key authorized for unsupported digest: "
- + KeyProperties.Digest.fromKeymaster(keymasterDigest));
- }
- args.addUnsignedInt(KeymasterDefs.KM_TAG_MIN_MAC_LENGTH, digestOutputSizeBits);
- break;
- }
- }
-
- private static long getRootSid() {
- long rootSid = GateKeeper.getSecureUserId();
- if (rootSid == 0) {
- throw new IllegalStateException("Secure lock screen must be enabled"
- + " to create keys requiring user authentication");
- }
- return rootSid;
- }
-}
diff --git a/keystore/java/android/security/keystore/SecureKeyImportUnavailableException.java b/keystore/java/android/security/keystore/SecureKeyImportUnavailableException.java
index d1cc572..c1842b4 100644
--- a/keystore/java/android/security/keystore/SecureKeyImportUnavailableException.java
+++ b/keystore/java/android/security/keystore/SecureKeyImportUnavailableException.java
@@ -16,8 +16,8 @@
package android.security.keystore;
-import android.security.KeyStore;
import android.security.KeyStoreException;
+import android.security.keymaster.KeymasterDefs;
import java.security.ProviderException;
@@ -31,7 +31,7 @@
}
public SecureKeyImportUnavailableException(String message) {
- super(message, new KeyStoreException(KeyStore.HARDWARE_TYPE_UNAVAILABLE,
+ super(message, new KeyStoreException(KeymasterDefs.KM_ERROR_HARDWARE_TYPE_UNAVAILABLE,
"Secure Key Import not available"));
}
diff --git a/keystore/java/android/security/keystore/StrongBoxUnavailableException.java b/keystore/java/android/security/keystore/StrongBoxUnavailableException.java
index 6c7e9a9..1f4e12e 100644
--- a/keystore/java/android/security/keystore/StrongBoxUnavailableException.java
+++ b/keystore/java/android/security/keystore/StrongBoxUnavailableException.java
@@ -16,8 +16,8 @@
package android.security.keystore;
-import android.security.KeyStore;
import android.security.KeyStoreException;
+import android.security.keymaster.KeymasterDefs;
import java.security.ProviderException;
@@ -33,7 +33,8 @@
public StrongBoxUnavailableException(String message) {
super(message,
- new KeyStoreException(KeyStore.HARDWARE_TYPE_UNAVAILABLE, "No StrongBox available")
+ new KeyStoreException(KeymasterDefs.KM_ERROR_HARDWARE_TYPE_UNAVAILABLE,
+ "No StrongBox available")
);
}
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreHmacSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreHmacSpi.java
index 0f77749..268b15b 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreHmacSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreHmacSpi.java
@@ -21,7 +21,6 @@
import android.security.KeyStoreOperation;
import android.security.keymaster.KeymasterDefs;
import android.security.keystore.KeyStoreCryptoOperation;
-import android.security.keystore.KeymasterUtils;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyGeneratorSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyGeneratorSpi.java
index 1575bb4..f1681ec 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyGeneratorSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyGeneratorSpi.java
@@ -20,12 +20,10 @@
import android.hardware.security.keymint.SecurityLevel;
import android.security.KeyStore2;
import android.security.KeyStoreSecurityLevel;
-import android.security.keymaster.KeymasterArguments;
import android.security.keymaster.KeymasterDefs;
import android.security.keystore.ArrayUtils;
import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyProperties;
-import android.security.keystore.KeymasterUtils;
import android.security.keystore.StrongBoxUnavailableException;
import android.system.keystore2.Domain;
import android.system.keystore2.IKeystoreSecurityLevel;
@@ -259,7 +257,7 @@
// Check that user authentication related parameters are acceptable. This method
// will throw an IllegalStateException if there are issues (e.g., secure lock screen
// not set up).
- KeymasterUtils.addUserAuthArgs(new KeymasterArguments(), spec);
+ KeyStore2ParameterUtils.addUserAuthArgs(new ArrayList<>(), spec);
} catch (IllegalStateException | IllegalArgumentException e) {
throw new InvalidAlgorithmParameterException(e);
}
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
index 2d8901a..c26d9f5 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
@@ -18,6 +18,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.ActivityThread;
import android.content.Context;
import android.hardware.security.keymint.KeyParameter;
import android.hardware.security.keymint.KeyPurpose;
@@ -28,7 +29,6 @@
import android.security.GenerateRkpKey;
import android.security.GenerateRkpKeyException;
import android.security.KeyPairGeneratorSpec;
-import android.security.KeyStore;
import android.security.KeyStore2;
import android.security.KeyStoreException;
import android.security.KeyStoreSecurityLevel;
@@ -39,7 +39,6 @@
import android.security.keystore.DeviceIdAttestationException;
import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyProperties;
-import android.security.keystore.KeymasterUtils;
import android.security.keystore.SecureKeyImportUnavailableException;
import android.security.keystore.StrongBoxUnavailableException;
import android.system.keystore2.Authorization;
@@ -270,7 +269,7 @@
// Check that user authentication related parameters are acceptable. This method
// will throw an IllegalStateException if there are issues (e.g., secure lock screen
// not set up).
- KeymasterUtils.addUserAuthArgs(new KeymasterArguments(), mSpec);
+ KeyStore2ParameterUtils.addUserAuthArgs(new ArrayList<>(), mSpec);
} catch (IllegalArgumentException | IllegalStateException e) {
throw new InvalidAlgorithmParameterException(e);
}
@@ -572,7 +571,8 @@
AndroidKeyStorePublicKey publicKey =
AndroidKeyStoreProvider.makeAndroidKeyStorePublicKeyFromKeyEntryResponse(
descriptor, metadata, iSecurityLevel, mKeymasterAlgorithm);
- GenerateRkpKey keyGen = new GenerateRkpKey(KeyStore.getApplicationContext());
+ GenerateRkpKey keyGen = new GenerateRkpKey(ActivityThread
+ .currentApplication());
try {
if (mSpec.getAttestationChallenge() != null) {
keyGen.notifyKeyGenerated(securityLevel);
@@ -589,7 +589,8 @@
case KeymasterDefs.KM_ERROR_HARDWARE_TYPE_UNAVAILABLE:
throw new StrongBoxUnavailableException("Failed to generated key pair.", e);
case ResponseCode.OUT_OF_KEYS:
- GenerateRkpKey keyGen = new GenerateRkpKey(KeyStore.getApplicationContext());
+ GenerateRkpKey keyGen = new GenerateRkpKey(ActivityThread
+ .currentApplication());
try {
keyGen.notifyEmpty(securityLevel);
} catch (RemoteException f) {
@@ -665,8 +666,8 @@
if (idTypesSet.contains(AttestationUtils.ID_TYPE_IMEI)
|| idTypesSet.contains(AttestationUtils.ID_TYPE_MEID)) {
telephonyService =
- (TelephonyManager) KeyStore.getApplicationContext().getSystemService(
- Context.TELEPHONY_SERVICE);
+ (TelephonyManager) android.app.AppGlobals.getInitialApplication()
+ .getSystemService(Context.TELEPHONY_SERVICE);
if (telephonyService == null) {
throw new DeviceIdAttestationException("Unable to access telephony service");
}
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java b/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
index ba6d22f..89d2b74 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
@@ -110,23 +110,6 @@
putSecretKeyFactoryImpl("HmacSHA512");
}
- private static boolean sInstalled = false;
-
- /**
- * This function indicates whether or not this provider was installed. This is manly used
- * as indicator for
- * {@link android.security.keystore.AndroidKeyStoreProvider#getKeyStoreForUid(int)}
- * to whether or not to retrieve the Keystore provider by "AndroidKeyStoreLegacy".
- * This function can be removed once the transition to Keystore 2.0 is complete.
- * b/171305684
- *
- * @return true if this provider was installed.
- * @hide
- */
- public static boolean isInstalled() {
- return sInstalled;
- }
-
/**
* Installs a new instance of this provider (and the
* {@link AndroidKeyStoreBCWorkaroundProvider}).
@@ -142,7 +125,6 @@
break;
}
}
- sInstalled = true;
Security.addProvider(new AndroidKeyStoreProvider());
Provider workaroundProvider = new AndroidKeyStoreBCWorkaroundProvider();
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreRSACipherSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreRSACipherSpi.java
index 6ff9432..5848247 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreRSACipherSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreRSACipherSpi.java
@@ -21,7 +21,6 @@
import android.hardware.security.keymint.KeyParameter;
import android.security.keymaster.KeymasterDefs;
import android.security.keystore.KeyProperties;
-import android.security.keystore.KeymasterUtils;
import android.system.keystore2.Authorization;
import java.security.AlgorithmParameters;
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java
index 32f98a2..3e2fb94 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java
@@ -30,7 +30,6 @@
import android.security.keystore.KeyPermanentlyInvalidatedException;
import android.security.keystore.KeyProperties;
import android.security.keystore.KeyProtection;
-import android.security.keystore.KeymasterUtils;
import android.security.keystore.SecureKeyImportUnavailableException;
import android.security.keystore.WrappedKeyEntry;
import android.system.keystore2.AuthenticatorSpec;
diff --git a/keystore/java/android/security/keystore2/KeymasterUtils.java b/keystore/java/android/security/keystore2/KeymasterUtils.java
new file mode 100644
index 0000000..de4696c
--- /dev/null
+++ b/keystore/java/android/security/keystore2/KeymasterUtils.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.keystore2;
+
+import android.security.keymaster.KeymasterArguments;
+import android.security.keymaster.KeymasterDefs;
+import android.security.keystore.KeyProperties;
+
+import java.security.ProviderException;
+
+/**
+ * @hide
+ */
+public abstract class KeymasterUtils {
+
+ private KeymasterUtils() {}
+
+ /** @hide */
+ static int getDigestOutputSizeBits(int keymasterDigest) {
+ switch (keymasterDigest) {
+ case KeymasterDefs.KM_DIGEST_NONE:
+ return -1;
+ case KeymasterDefs.KM_DIGEST_MD5:
+ return 128;
+ case KeymasterDefs.KM_DIGEST_SHA1:
+ return 160;
+ case KeymasterDefs.KM_DIGEST_SHA_2_224:
+ return 224;
+ case KeymasterDefs.KM_DIGEST_SHA_2_256:
+ return 256;
+ case KeymasterDefs.KM_DIGEST_SHA_2_384:
+ return 384;
+ case KeymasterDefs.KM_DIGEST_SHA_2_512:
+ return 512;
+ default:
+ throw new IllegalArgumentException("Unknown digest: " + keymasterDigest);
+ }
+ }
+
+ /** @hide */
+ static boolean isKeymasterBlockModeIndCpaCompatibleWithSymmetricCrypto(
+ int keymasterBlockMode) {
+ switch (keymasterBlockMode) {
+ case KeymasterDefs.KM_MODE_ECB:
+ return false;
+ case KeymasterDefs.KM_MODE_CBC:
+ case KeymasterDefs.KM_MODE_CTR:
+ case KeymasterDefs.KM_MODE_GCM:
+ return true;
+ default:
+ throw new IllegalArgumentException("Unsupported block mode: " + keymasterBlockMode);
+ }
+ }
+
+ /** @hide */
+ static boolean isKeymasterPaddingSchemeIndCpaCompatibleWithAsymmetricCrypto(
+ int keymasterPadding) {
+ switch (keymasterPadding) {
+ case KeymasterDefs.KM_PAD_NONE:
+ return false;
+ case KeymasterDefs.KM_PAD_RSA_OAEP:
+ case KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_ENCRYPT:
+ return true;
+ default:
+ throw new IllegalArgumentException(
+ "Unsupported asymmetric encryption padding scheme: " + keymasterPadding);
+ }
+ }
+
+ /**
+ * Adds {@code KM_TAG_MIN_MAC_LENGTH} tag, if necessary, to the keymaster arguments for
+ * generating or importing a key. This tag may only be needed for symmetric keys (e.g., HMAC,
+ * AES-GCM).
+ */
+ public static void addMinMacLengthAuthorizationIfNecessary(KeymasterArguments args,
+ int keymasterAlgorithm,
+ int[] keymasterBlockModes,
+ int[] keymasterDigests) {
+ switch (keymasterAlgorithm) {
+ case KeymasterDefs.KM_ALGORITHM_AES:
+ if (com.android.internal.util.ArrayUtils.contains(
+ keymasterBlockModes, KeymasterDefs.KM_MODE_GCM)) {
+ // AES GCM key needs the minimum length of AEAD tag specified.
+ args.addUnsignedInt(KeymasterDefs.KM_TAG_MIN_MAC_LENGTH,
+ AndroidKeyStoreAuthenticatedAESCipherSpi.GCM
+ .MIN_SUPPORTED_TAG_LENGTH_BITS);
+ }
+ break;
+ case KeymasterDefs.KM_ALGORITHM_HMAC:
+ // HMAC key needs the minimum length of MAC set to the output size of the associated
+ // digest. This is because we do not offer a way to generate shorter MACs and
+ // don't offer a way to verify MACs (other than by generating them).
+ if (keymasterDigests.length != 1) {
+ throw new ProviderException(
+ "Unsupported number of authorized digests for HMAC key: "
+ + keymasterDigests.length
+ + ". Exactly one digest must be authorized");
+ }
+ int keymasterDigest = keymasterDigests[0];
+ int digestOutputSizeBits = getDigestOutputSizeBits(keymasterDigest);
+ if (digestOutputSizeBits == -1) {
+ throw new ProviderException(
+ "HMAC key authorized for unsupported digest: "
+ + KeyProperties.Digest.fromKeymaster(keymasterDigest));
+ }
+ args.addUnsignedInt(KeymasterDefs.KM_TAG_MIN_MAC_LENGTH, digestOutputSizeBits);
+ break;
+ }
+ }
+}
diff --git a/location/java/Android.bp b/location/java/Android.bp
new file mode 100644
index 0000000..543f2b1
--- /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 0000000..58513d7
--- /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 aea63a0..eeaf6e9 100644
--- a/media/java/Android.bp
+++ b/media/java/Android.bp
@@ -8,6 +8,18 @@
}
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 7062f83..5633236 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -4412,14 +4412,25 @@
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 66c7bd4..e365ee1 100644
--- a/media/java/android/media/tv/tunerresourcemanager/Android.bp
+++ b/media/java/android/media/tv/tunerresourcemanager/Android.bp
@@ -6,6 +6,12 @@
// 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 ed56b43..9fe700a 100755
--- a/media/java/android/mtp/MtpDatabase.java
+++ b/media/java/android/mtp/MtpDatabase.java
@@ -821,8 +821,10 @@
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 @@
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 @@
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 0000000..70d999f
--- /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 0000000..77afcff
--- /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 0000000..f370b21
--- /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
index e69de29..78ac703 100644
--- a/media/tests/MtpTests/res/raw/test_bad_thumb.jpg
+++ b/media/tests/MtpTests/res/raw/test_bad_thumb.jpg
Binary files differ
diff --git a/media/tests/MtpTests/src/android/mtp/MtpDatabaseTest.java b/media/tests/MtpTests/src/android/mtp/MtpDatabaseTest.java
index e2e8ff4..0bf99cf 100644
--- a/media/tests/MtpTests/src/android/mtp/MtpDatabaseTest.java
+++ b/media/tests/MtpTests/src/android/mtp/MtpDatabaseTest.java
@@ -271,9 +271,10 @@
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 0000000..07cada8e
--- /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 0000000..4d51439
--- /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/native/android/OWNERS b/native/android/OWNERS
index d414ed4..02dfd39 100644
--- a/native/android/OWNERS
+++ b/native/android/OWNERS
@@ -1,4 +1,16 @@
+jreck@google.com
+
per-file libandroid_net.map.txt, net.c = set noparent
per-file libandroid_net.map.txt, net.c = codewiz@google.com, jchalard@google.com, junyulai@google.com
per-file libandroid_net.map.txt, net.c = lorenzo@google.com, reminv@google.com, satk@google.com
per-file system_fonts.cpp = file:/graphics/java/android/graphics/fonts/OWNERS
+
+per-file native_window_jni.cpp = file:/services/core/java/com/android/server/wm/OWNERS
+per-file native_activity.cpp = file:/services/core/java/com/android/server/wm/OWNERS
+per-file surface_control.cpp = file:/services/core/java/com/android/server/wm/OWNERS
+
+per-file choreographer.cpp = file:/graphics/java/android/graphics/OWNERS
+per-file hardware_buffer_jni.cpp = file:/graphics/java/android/graphics/OWNERS
+per-file native_window_jni.cpp = file:/graphics/java/android/graphics/OWNERS
+per-file surface_control.cpp = file:/graphics/java/android/graphics/OWNERS
+per-file surface_texture.cpp = file:/graphics/java/android/graphics/OWNERS
diff --git a/opengl/java/Android.bp b/opengl/java/Android.bp
new file mode 100644
index 0000000..6dbae42
--- /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/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java
index 550e324..10d68ba 100644
--- a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java
+++ b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java
@@ -50,7 +50,7 @@
import android.widget.TextView;
import com.android.internal.util.ArrayUtils;
-import com.android.internal.util.TrafficStatsConstants;
+import com.android.net.module.util.NetworkStackConstants;
import java.io.IOException;
import java.lang.reflect.Field;
@@ -238,7 +238,7 @@
HttpURLConnection urlConnection = null;
int httpResponseCode = 500;
int oldTag = TrafficStats.getAndSetThreadStatsTag(
- TrafficStatsConstants.TAG_SYSTEM_PROBE);
+ NetworkStackConstants.TAG_SYSTEM_PROBE);
try {
urlConnection = (HttpURLConnection) mNetwork.openConnection(
new URL(mCm.getCaptivePortalServerUrl()));
diff --git a/packages/Connectivity/framework/aidl-export/android/net/IpPrefix.aidl b/packages/Connectivity/framework/aidl-export/android/net/IpPrefix.aidl
index 0d70f2a..3495efc 100644
--- a/packages/Connectivity/framework/aidl-export/android/net/IpPrefix.aidl
+++ b/packages/Connectivity/framework/aidl-export/android/net/IpPrefix.aidl
@@ -18,5 +18,5 @@
package android.net;
// @JavaOnlyStableParcelable only affects the parcelable when built as stable aidl (aidl_interface
-// build rule). IpPrefix is also used in cpp but only as non-stable aidl.
-@JavaOnlyStableParcelable parcelable IpPrefix cpp_header "binder/IpPrefix.h";
+// build rule).
+@JavaOnlyStableParcelable parcelable IpPrefix;
diff --git a/packages/Connectivity/framework/api/current.txt b/packages/Connectivity/framework/api/current.txt
index ad44b27..ab290f9 100644
--- a/packages/Connectivity/framework/api/current.txt
+++ b/packages/Connectivity/framework/api/current.txt
@@ -68,6 +68,7 @@
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();
@@ -297,7 +298,6 @@
method @Nullable public android.net.NetworkSpecifier getNetworkSpecifier();
method public int getOwnerUid();
method public int getSignalStrength();
- method @NonNull public java.util.Set<java.lang.Integer> getSubIds();
method @Nullable public android.net.TransportInfo getTransportInfo();
method public boolean hasCapability(int);
method public boolean hasTransport(int);
@@ -387,7 +387,9 @@
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);
@@ -405,7 +407,6 @@
method public android.net.NetworkRequest.Builder removeTransportType(int);
method @Deprecated public android.net.NetworkRequest.Builder setNetworkSpecifier(String);
method public android.net.NetworkRequest.Builder setNetworkSpecifier(android.net.NetworkSpecifier);
- method @NonNull public android.net.NetworkRequest.Builder setSubIds(@NonNull java.util.Set<java.lang.Integer>);
}
public class ParseException extends java.lang.RuntimeException {
diff --git a/packages/Connectivity/framework/api/module-lib-current.txt b/packages/Connectivity/framework/api/module-lib-current.txt
index ac69a3e..8dfdd614 100644
--- a/packages/Connectivity/framework/api/module-lib-current.txt
+++ b/packages/Connectivity/framework/api/module-lib-current.txt
@@ -20,17 +20,24 @@
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void setAvoidUnvalidated(@NonNull android.net.Network);
method @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public void setGlobalProxy(@Nullable android.net.ProxyInfo);
method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public void setLegacyLockdownVpnEnabled(boolean);
+ method public static void setPrivateDnsMode(@NonNull android.content.Context, @NonNull String);
method @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public void setProfileNetworkPreference(@NonNull android.os.UserHandle, int, @Nullable java.util.concurrent.Executor, @Nullable Runnable);
method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public void setRequireVpnForUids(boolean, @NonNull java.util.Collection<android.util.Range<java.lang.Integer>>);
method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_TEST_NETWORKS, android.Manifest.permission.NETWORK_STACK}) public void simulateDataStall(int, long, @NonNull android.net.Network, @NonNull android.os.PersistableBundle);
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void startCaptivePortalApp(@NonNull android.net.Network);
method public void systemReady();
+ field public static final String ACTION_CLEAR_DNS_CACHE = "android.net.action.CLEAR_DNS_CACHE";
+ field public static final String ACTION_PROMPT_LOST_VALIDATION = "android.net.action.PROMPT_LOST_VALIDATION";
+ field public static final String ACTION_PROMPT_PARTIAL_CONNECTIVITY = "android.net.action.PROMPT_PARTIAL_CONNECTIVITY";
+ field public static final String ACTION_PROMPT_UNVALIDATED = "android.net.action.PROMPT_UNVALIDATED";
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 +47,56 @@
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();
@@ -51,7 +108,6 @@
}
public final class NetworkCapabilities implements android.os.Parcelable {
- ctor public NetworkCapabilities(@Nullable android.net.NetworkCapabilities, long);
method @Nullable public java.util.Set<android.util.Range<java.lang.Integer>> getUids();
method public boolean hasUnwantedCapability(int);
field public static final long REDACT_ALL = -1L; // 0xffffffffffffffffL
@@ -67,6 +123,7 @@
}
public class NetworkRequest implements android.os.Parcelable {
+ method @NonNull public int[] getUnwantedCapabilities();
method public boolean hasUnwantedCapability(int);
}
@@ -122,10 +179,12 @@
}
public final class VpnTransportInfo implements android.os.Parcelable android.net.TransportInfo {
- ctor public VpnTransportInfo(int);
+ ctor public VpnTransportInfo(int, @Nullable String);
method public int describeContents();
+ method @NonNull public android.net.VpnTransportInfo makeCopy(long);
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.net.VpnTransportInfo> CREATOR;
+ field @Nullable public final String sessionId;
field public final int type;
}
diff --git a/packages/Connectivity/framework/api/system-current.txt b/packages/Connectivity/framework/api/system-current.txt
index 8e6e846..0a82cb7 100644
--- a/packages/Connectivity/framework/api/system-current.txt
+++ b/packages/Connectivity/framework/api/system-current.txt
@@ -217,7 +217,9 @@
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 @@
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 @@
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);
@@ -264,15 +273,19 @@
public final class NetworkCapabilities implements android.os.Parcelable {
method @NonNull public int[] getAdministratorUids();
+ method @Nullable public static String getCapabilityCarrierName(int);
method @Nullable public String getSsid();
+ method @NonNull public java.util.Set<java.lang.Integer> getSubIds();
method @NonNull public int[] getTransportTypes();
method public boolean isPrivateDnsBroken();
method public boolean satisfiedByNetworkCapabilities(@Nullable android.net.NetworkCapabilities);
+ field public static final int NET_CAPABILITY_BIP = 31; // 0x1f
field public static final int NET_CAPABILITY_NOT_VCN_MANAGED = 28; // 0x1c
field public static final int NET_CAPABILITY_OEM_PAID = 22; // 0x16
field public static final int NET_CAPABILITY_OEM_PRIVATE = 26; // 0x1a
field public static final int NET_CAPABILITY_PARTIAL_CONNECTIVITY = 24; // 0x18
field public static final int NET_CAPABILITY_VEHICLE_INTERNAL = 27; // 0x1b
+ field public static final int NET_CAPABILITY_VSIM = 30; // 0x1e
}
public static final class NetworkCapabilities.Builder {
@@ -316,6 +329,7 @@
public static class NetworkRequest.Builder {
method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP) public android.net.NetworkRequest.Builder setSignalStrength(int);
+ method @NonNull public android.net.NetworkRequest.Builder setSubIds(@NonNull java.util.Set<java.lang.Integer>);
}
public final class NetworkScore implements android.os.Parcelable {
@@ -404,6 +418,7 @@
}
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 bc668f3..9fbf049 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.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;
@@ -423,7 +425,8 @@
*
* @hide
*/
- public static final String ACTION_PROMPT_UNVALIDATED = "android.net.conn.PROMPT_UNVALIDATED";
+ @SystemApi(client = MODULE_LIBRARIES)
+ public static final String ACTION_PROMPT_UNVALIDATED = "android.net.action.PROMPT_UNVALIDATED";
/**
* Action used to display a dialog that asks the user whether to avoid a network that is no
@@ -431,8 +434,9 @@
*
* @hide
*/
+ @SystemApi(client = MODULE_LIBRARIES)
public static final String ACTION_PROMPT_LOST_VALIDATION =
- "android.net.conn.PROMPT_LOST_VALIDATION";
+ "android.net.action.PROMPT_LOST_VALIDATION";
/**
* Action used to display a dialog that asks the user whether to stay connected to a network
@@ -441,8 +445,18 @@
*
* @hide
*/
+ @SystemApi(client = MODULE_LIBRARIES)
public static final String ACTION_PROMPT_PARTIAL_CONNECTIVITY =
- "android.net.conn.PROMPT_PARTIAL_CONNECTIVITY";
+ "android.net.action.PROMPT_PARTIAL_CONNECTIVITY";
+
+ /**
+ * Clear DNS Cache Action: This is broadcast when networks have changed and old
+ * DNS entries should be cleared.
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public static final String ACTION_CLEAR_DNS_CACHE = "android.net.action.CLEAR_DNS_CACHE";
/**
* Invalid tethering type.
@@ -872,6 +886,17 @@
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 +933,21 @@
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 +1202,7 @@
*
* @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
@@ -3119,18 +3152,27 @@
}
/**
- * Set a network-independent global http proxy. This is not normally what you want
- * for typical HTTP proxies - they are general network dependent. However if you're
- * doing something unusual like general internal filtering this may be useful. On
- * a private network where the proxy is not accessible, you may break HTTP using this.
+ * Set a network-independent global HTTP proxy.
*
- * @param p A {@link ProxyInfo} object defining the new global
- * HTTP proxy. A {@code null} value will clear the global HTTP proxy.
+ * This sets an HTTP proxy that applies to all networks and overrides any network-specific
+ * proxy. If set, HTTP libraries that are proxy-aware will use this global proxy when
+ * accessing any network, regardless of what the settings for that network are.
+ *
+ * Note that HTTP proxies are by nature typically network-dependent, and setting a global
+ * proxy is likely to break networking on multiple networks. This method is only meant
+ * for device policy clients looking to do general internal filtering or similar use cases.
+ *
+ * {@see #getGlobalProxy}
+ * {@see LinkProperties#getHttpProxy}
+ *
+ * @param p A {@link ProxyInfo} object defining the new global HTTP proxy. Calling this
+ * method with a {@code null} value will clear the global HTTP proxy.
* @hide
*/
+ // Used by Device Policy Manager to set the global proxy.
@SystemApi(client = MODULE_LIBRARIES)
@RequiresPermission(android.Manifest.permission.NETWORK_STACK)
- public void setGlobalProxy(@Nullable ProxyInfo p) {
+ public void setGlobalProxy(@Nullable final ProxyInfo p) {
try {
mService.setGlobalProxy(p);
} catch (RemoteException e) {
@@ -3388,6 +3430,8 @@
* not include location sensitive info.
* </p>
*/
+ // Note: Some existing fields which are location sensitive may still be included without
+ // this flag if the app targets SDK < S (to maintain backwards compatibility).
public static final int FLAG_INCLUDE_LOCATION_INFO = 1 << 0;
/** @hide */
@@ -3442,12 +3486,30 @@
* @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 +3517,7 @@
}
onCapabilitiesChanged(network, networkCapabilities);
onLinkPropertiesChanged(network, linkProperties);
- onBlockedStatusChanged(network, blocked);
+ // No call to onBlockedStatusChanged here. That is done by the caller.
}
/**
@@ -3619,6 +3681,27 @@
*/
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 +3816,7 @@
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 +3850,7 @@
break;
}
case CALLBACK_BLK_CHANGED: {
- boolean blocked = message.arg1 != 0;
- callback.onBlockedStatusChanged(network, blocked);
+ callback.onBlockedStatusChanged(network, message.arg1);
}
}
}
@@ -5371,4 +5453,23 @@
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 bbd8393..9a00055 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 @@
* 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 @@
/**
* 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 @@
/**
* 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 @@
/**
* 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 @@
/**
* 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 @@
* 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 @@
* 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 @@
* 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 @@
* 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 @@
* 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 @@
* See ConnectivityService for more info.
*
* (0 = disabled, 1 = enabled)
+ *
+ * @hide
*/
public static final String WIFI_ALWAYS_REQUESTED = "wifi_always_requested";
@@ -228,14 +293,637 @@
* 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/DnsResolver.java b/packages/Connectivity/framework/src/android/net/DnsResolver.java
index 3f7660f..dac88ad 100644
--- a/packages/Connectivity/framework/src/android/net/DnsResolver.java
+++ b/packages/Connectivity/framework/src/android/net/DnsResolver.java
@@ -500,7 +500,7 @@
try {
resp = resNetworkResult(fd); // Closes fd, marks it invalid.
} catch (ErrnoException e) {
- Log.e(TAG, "resNetworkResult:" + e.toString());
+ Log.w(TAG, "resNetworkResult:" + e.toString());
exception = e;
}
}
diff --git a/packages/Connectivity/framework/src/android/net/INetworkAgent.aidl b/packages/Connectivity/framework/src/android/net/INetworkAgent.aidl
index 078acbd..d941d4b 100644
--- a/packages/Connectivity/framework/src/android/net/INetworkAgent.aidl
+++ b/packages/Connectivity/framework/src/android/net/INetworkAgent.aidl
@@ -47,4 +47,5 @@
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 cbd6193..26cb1ed 100644
--- a/packages/Connectivity/framework/src/android/net/INetworkAgentRegistry.aidl
+++ b/packages/Connectivity/framework/src/android/net/INetworkAgentRegistry.aidl
@@ -41,4 +41,5 @@
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/Network.java b/packages/Connectivity/framework/src/android/net/Network.java
index 0741414..41fad63 100644
--- a/packages/Connectivity/framework/src/android/net/Network.java
+++ b/packages/Connectivity/framework/src/android/net/Network.java
@@ -27,7 +27,6 @@
import android.system.ErrnoException;
import android.system.Os;
import android.system.OsConstants;
-import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.GuardedBy;
@@ -526,11 +525,4 @@
public String toString() {
return Integer.toString(netId);
}
-
- /** @hide */
- public void dumpDebug(ProtoOutputStream proto, long fieldId) {
- final long token = proto.start(fieldId);
- proto.write(NetworkProto.NET_ID, netId);
- proto.end(token);
- }
}
diff --git a/packages/Connectivity/framework/src/android/net/NetworkAgent.java b/packages/Connectivity/framework/src/android/net/NetworkAgent.java
index aef1a31..c57da53 100644
--- a/packages/Connectivity/framework/src/android/net/NetworkAgent.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkAgent.java
@@ -185,6 +185,20 @@
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 static final int CMD_REPORT_NETWORK_STATUS = BASE + 7;
-
/**
* Network validation suceeded.
* Corresponds to {@link NetworkCapabilities.NET_CAPABILITY_VALIDATED}.
@@ -370,10 +383,17 @@
*/
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 @@
onNetworkCreated();
break;
}
+ case CMD_NETWORK_DESTROYED: {
+ onNetworkDestroyed();
+ break;
+ }
}
}
}
@@ -719,6 +743,11 @@
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 @@
}
/**
+ * 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 @@
* @hide
*/
@Deprecated
+ @SystemApi
public void setLegacySubtype(final int legacySubtype, @NonNull final String legacySubtypeName) {
mNetworkInfo.setSubtype(legacySubtype, legacySubtypeName);
queueOrSendNetworkInfo(mNetworkInfo);
@@ -979,6 +1032,7 @@
* shall try to overwrite this method and produce a bandwidth update if capable.
* @hide
*/
+ @SystemApi
public void onBandwidthUpdateRequested() {
pollLceData();
}
@@ -1031,6 +1085,12 @@
*/
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 0bd2371..3f058d8 100644
--- a/packages/Connectivity/framework/src/android/net/NetworkAgentConfig.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkAgentConfig.java
@@ -175,6 +175,12 @@
}
/**
+ * 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 @@
}
/**
+ * 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 @@
skip464xlat = nac.skip464xlat;
legacyType = nac.legacyType;
legacyTypeName = nac.legacyTypeName;
+ legacySubType = nac.legacySubType;
+ legacySubTypeName = nac.legacySubTypeName;
mLegacyExtraInfo = nac.mLegacyExtraInfo;
}
}
@@ -300,7 +315,6 @@
* 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 @@
* perform its own carrier-specific provisioning procedure.
*
* @return this builder, to facilitate chaining.
- * @hide
*/
@NonNull
public Builder disableProvisioningNotification() {
@@ -334,6 +347,18 @@
}
/**
+ * 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 @@
}
/**
+ * 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 @@
out.writeInt(skip464xlat ? 1 : 0);
out.writeInt(legacyType);
out.writeString(legacyTypeName);
+ out.writeInt(legacySubType);
+ out.writeString(legacySubTypeName);
out.writeString(mLegacyExtraInfo);
}
@@ -452,6 +489,8 @@
networkAgentConfig.skip464xlat = in.readInt() != 0;
networkAgentConfig.legacyType = in.readInt();
networkAgentConfig.legacyTypeName = in.readString();
+ networkAgentConfig.legacySubType = in.readInt();
+ networkAgentConfig.legacySubTypeName = in.readString();
networkAgentConfig.mLegacyExtraInfo = in.readString();
return networkAgentConfig;
}
diff --git a/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java b/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java
index 881fa8c..a43dd15 100644
--- a/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java
@@ -35,7 +35,6 @@
import android.text.TextUtils;
import android.util.ArraySet;
import android.util.Range;
-import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.VisibleForTesting;
import com.android.net.module.util.CollectionUtils;
@@ -163,7 +162,6 @@
* {@link NetworkCapabilities}.
* @hide
*/
- @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public NetworkCapabilities(@Nullable NetworkCapabilities nc, @RedactionType long redactions) {
mRedactions = redactions;
if (nc != null) {
@@ -274,6 +272,8 @@
NET_CAPABILITY_VEHICLE_INTERNAL,
NET_CAPABILITY_NOT_VCN_MANAGED,
NET_CAPABILITY_ENTERPRISE,
+ NET_CAPABILITY_VSIM,
+ NET_CAPABILITY_BIP,
})
public @interface NetCapability { }
@@ -493,8 +493,22 @@
*/
public static final int NET_CAPABILITY_ENTERPRISE = 29;
+ /**
+ * Indicates that this network has ability to access the carrier's Virtual Sim service.
+ * @hide
+ */
+ @SystemApi
+ public static final int NET_CAPABILITY_VSIM = 30;
+
+ /**
+ * Indicates that this network has ability to support Bearer Independent Protol.
+ * @hide
+ */
+ @SystemApi
+ public static final int NET_CAPABILITY_BIP = 31;
+
private static final int MIN_NET_CAPABILITY = NET_CAPABILITY_MMS;
- private static final int MAX_NET_CAPABILITY = NET_CAPABILITY_ENTERPRISE;
+ private static final int MAX_NET_CAPABILITY = NET_CAPABILITY_BIP;
/**
* Network capabilities that are expected to be mutable, i.e., can change while a particular
@@ -538,43 +552,6 @@
| (1 << NET_CAPABILITY_NOT_VPN);
/**
- * Capabilities that suggest that a network is restricted.
- * {@see #maybeMarkCapabilitiesRestricted}, {@see #FORCE_RESTRICTED_CAPABILITIES}
- */
- @VisibleForTesting
- /* package */ static final long RESTRICTED_CAPABILITIES =
- (1 << NET_CAPABILITY_CBS)
- | (1 << NET_CAPABILITY_DUN)
- | (1 << NET_CAPABILITY_EIMS)
- | (1 << NET_CAPABILITY_FOTA)
- | (1 << NET_CAPABILITY_IA)
- | (1 << NET_CAPABILITY_IMS)
- | (1 << NET_CAPABILITY_MCX)
- | (1 << NET_CAPABILITY_RCS)
- | (1 << NET_CAPABILITY_VEHICLE_INTERNAL)
- | (1 << NET_CAPABILITY_XCAP)
- | (1 << NET_CAPABILITY_ENTERPRISE);
-
- /**
- * Capabilities that force network to be restricted.
- * {@see #maybeMarkCapabilitiesRestricted}.
- */
- private static final long FORCE_RESTRICTED_CAPABILITIES =
- (1 << NET_CAPABILITY_OEM_PAID)
- | (1 << NET_CAPABILITY_OEM_PRIVATE);
-
- /**
- * Capabilities that suggest that a network is unrestricted.
- * {@see #maybeMarkCapabilitiesRestricted}.
- */
- @VisibleForTesting
- /* package */ static final long UNRESTRICTED_CAPABILITIES =
- (1 << NET_CAPABILITY_INTERNET)
- | (1 << NET_CAPABILITY_MMS)
- | (1 << NET_CAPABILITY_SUPL)
- | (1 << NET_CAPABILITY_WIFI_P2P);
-
- /**
* Capabilities that are managed by ConnectivityService.
*/
private static final long CONNECTIVITY_MANAGED_CAPABILITIES =
@@ -614,8 +591,9 @@
// TODO: Consider adding unwanted capabilities to the public API and mention this
// in the documentation.
checkValidCapability(capability);
- mNetworkCapabilities |= 1 << capability;
- mUnwantedNetworkCapabilities &= ~(1 << capability); // remove from unwanted capability list
+ mNetworkCapabilities |= 1L << capability;
+ // remove from unwanted capability list
+ mUnwantedNetworkCapabilities &= ~(1L << capability);
return this;
}
@@ -634,8 +612,8 @@
*/
public void addUnwantedCapability(@NetCapability int capability) {
checkValidCapability(capability);
- mUnwantedNetworkCapabilities |= 1 << capability;
- mNetworkCapabilities &= ~(1 << capability); // remove from requested capabilities
+ mUnwantedNetworkCapabilities |= 1L << capability;
+ mNetworkCapabilities &= ~(1L << capability); // remove from requested capabilities
}
/**
@@ -648,7 +626,7 @@
*/
public @NonNull NetworkCapabilities removeCapability(@NetCapability int capability) {
checkValidCapability(capability);
- final long mask = ~(1 << capability);
+ final long mask = ~(1L << capability);
mNetworkCapabilities &= mask;
return this;
}
@@ -663,7 +641,7 @@
*/
public @NonNull NetworkCapabilities removeUnwantedCapability(@NetCapability int capability) {
checkValidCapability(capability);
- mUnwantedNetworkCapabilities &= ~(1 << capability);
+ mUnwantedNetworkCapabilities &= ~(1L << capability);
return this;
}
@@ -731,14 +709,14 @@
*/
public boolean hasCapability(@NetCapability int capability) {
return isValidCapability(capability)
- && ((mNetworkCapabilities & (1 << capability)) != 0);
+ && ((mNetworkCapabilities & (1L << capability)) != 0);
}
/** @hide */
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public boolean hasUnwantedCapability(@NetCapability int capability) {
return isValidCapability(capability)
- && ((mUnwantedNetworkCapabilities & (1 << capability)) != 0);
+ && ((mUnwantedNetworkCapabilities & (1L << capability)) != 0);
}
/**
@@ -749,6 +727,23 @@
return ((mNetworkCapabilities & CONNECTIVITY_MANAGED_CAPABILITIES) != 0);
}
+ /**
+ * Get the name of the given capability that carriers use.
+ * If the capability does not have a carrier-name, returns null.
+ *
+ * @param capability The capability to get the carrier-name of.
+ * @return The carrier-name of the capability, or null if it doesn't exist.
+ * @hide
+ */
+ @SystemApi
+ public static @Nullable String getCapabilityCarrierName(@NetCapability int capability) {
+ if (capability == NET_CAPABILITY_ENTERPRISE) {
+ return capabilityNameOf(capability);
+ } else {
+ return null;
+ }
+ }
+
private void combineNetCapabilities(@NonNull NetworkCapabilities nc) {
final long wantedCaps = this.mNetworkCapabilities | nc.mNetworkCapabilities;
final long unwantedCaps =
@@ -811,37 +806,12 @@
}
/**
- * Deduces that all the capabilities it provides are typically provided by restricted networks
- * or not.
- *
- * @return {@code true} if the network should be restricted.
- * @hide
- */
- public boolean deduceRestrictedCapability() {
- // Check if we have any capability that forces the network to be restricted.
- final boolean forceRestrictedCapability =
- (mNetworkCapabilities & FORCE_RESTRICTED_CAPABILITIES) != 0;
-
- // Verify there aren't any unrestricted capabilities. If there are we say
- // the whole thing is unrestricted unless it is forced to be restricted.
- final boolean hasUnrestrictedCapabilities =
- (mNetworkCapabilities & UNRESTRICTED_CAPABILITIES) != 0;
-
- // Must have at least some restricted capabilities.
- final boolean hasRestrictedCapabilities =
- (mNetworkCapabilities & RESTRICTED_CAPABILITIES) != 0;
-
- return forceRestrictedCapability
- || (hasRestrictedCapabilities && !hasUnrestrictedCapabilities);
- }
-
- /**
- * Removes the NET_CAPABILITY_NOT_RESTRICTED capability if deducing the network is restricted.
+ * Removes the NET_CAPABILITY_NOT_RESTRICTED capability if inferring the network is restricted.
*
* @hide
*/
public void maybeMarkCapabilitiesRestricted() {
- if (deduceRestrictedCapability()) {
+ if (NetworkCapabilitiesUtils.inferRestrictedCapability(this)) {
removeCapability(NET_CAPABILITY_NOT_RESTRICTED);
}
}
@@ -1141,7 +1111,9 @@
* app needs to hold {@link android.Manifest.permission#ACCESS_FINE_LOCATION} permission. If the
* app targets SDK version greater than or equal to {@link Build.VERSION_CODES#S}, then they
* also need to use {@link NetworkCallback#FLAG_INCLUDE_LOCATION_INFO} to get the info in their
- * callback. The app will be blamed for location access if this field is included.
+ * callback. If the apps targets SDK version equal to {{@link Build.VERSION_CODES#R}, this field
+ * will always be included. The app will be blamed for location access if this field is
+ * included.
* </p>
*/
public int getOwnerUid() {
@@ -2087,34 +2059,6 @@
}
}
- /** @hide */
- public void dumpDebug(@NonNull ProtoOutputStream proto, long fieldId) {
- final long token = proto.start(fieldId);
-
- for (int transport : getTransportTypes()) {
- proto.write(NetworkCapabilitiesProto.TRANSPORTS, transport);
- }
-
- for (int capability : getCapabilities()) {
- proto.write(NetworkCapabilitiesProto.CAPABILITIES, capability);
- }
-
- proto.write(NetworkCapabilitiesProto.LINK_UP_BANDWIDTH_KBPS, mLinkUpBandwidthKbps);
- proto.write(NetworkCapabilitiesProto.LINK_DOWN_BANDWIDTH_KBPS, mLinkDownBandwidthKbps);
-
- if (mNetworkSpecifier != null) {
- proto.write(NetworkCapabilitiesProto.NETWORK_SPECIFIER, mNetworkSpecifier.toString());
- }
- if (mTransportInfo != null) {
- // TODO b/120653863: write transport-specific info to proto?
- }
-
- proto.write(NetworkCapabilitiesProto.CAN_REPORT_SIGNAL_STRENGTH, hasSignalStrength());
- proto.write(NetworkCapabilitiesProto.SIGNAL_STRENGTH, mSignalStrength);
-
- proto.end(token);
- }
-
/**
* @hide
*/
@@ -2163,6 +2107,8 @@
case NET_CAPABILITY_VEHICLE_INTERNAL: return "VEHICLE_INTERNAL";
case NET_CAPABILITY_NOT_VCN_MANAGED: return "NOT_VCN_MANAGED";
case NET_CAPABILITY_ENTERPRISE: return "ENTERPRISE";
+ case NET_CAPABILITY_VSIM: return "VSIM";
+ case NET_CAPABILITY_BIP: return "BIP";
default: return Integer.toString(capability);
}
}
@@ -2390,9 +2336,15 @@
/**
* Gets the subscription ID set that associated to this network or request.
+ *
+ * <p>Instances of NetworkCapabilities will only have this field populated by the system if the
+ * receiver holds the NETWORK_FACTORY permission. In all other cases, it will be the empty set.
+ *
* @return
+ * @hide
*/
@NonNull
+ @SystemApi
public Set<Integer> getSubIds() {
return new ArraySet<>(mSubIds);
}
@@ -2757,10 +2709,17 @@
/**
* Set the subscription ID set.
*
+ * <p>SubIds are populated in NetworkCapability instances from the system only for callers
+ * that hold the NETWORK_FACTORY permission. Similarly, the system will reject any
+ * NetworkRequests filed with a non-empty set of subIds unless the caller holds the
+ * NETWORK_FACTORY permission.
+ *
* @param subIds a set that represent the subscription IDs. Empty if clean up.
* @return this builder.
+ * @hide
*/
@NonNull
+ @SystemApi
public Builder setSubIds(@NonNull final Set<Integer> subIds) {
mCaps.setSubIds(subIds);
return this;
diff --git a/packages/Connectivity/framework/src/android/net/NetworkRequest.java b/packages/Connectivity/framework/src/android/net/NetworkRequest.java
index bcbc04f7..3a8a07a 100644
--- a/packages/Connectivity/framework/src/android/net/NetworkRequest.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkRequest.java
@@ -47,7 +47,6 @@
import android.os.Process;
import android.text.TextUtils;
import android.util.Range;
-import android.util.proto.ProtoOutputStream;
import java.util.Arrays;
import java.util.List;
@@ -501,9 +500,14 @@
* A network will satisfy this request only if it matches one of the subIds in this set.
* An empty set matches all networks, including those without a subId.
*
+ * <p>Registering a NetworkRequest with a non-empty set of subIds requires the
+ * NETWORK_FACTORY permission.
+ *
* @param subIds A {@code Set} that represents subscription IDs.
+ * @hide
*/
@NonNull
+ @SystemApi
public Builder setSubIds(@NonNull Set<Integer> subIds) {
mNetworkCapabilities.setSubIds(subIds);
return this;
@@ -675,18 +679,6 @@
}
}
- /** @hide */
- public void dumpDebug(ProtoOutputStream proto, long fieldId) {
- final long token = proto.start(fieldId);
-
- proto.write(NetworkRequestProto.TYPE, typeToProtoEnum(type));
- proto.write(NetworkRequestProto.REQUEST_ID, requestId);
- proto.write(NetworkRequestProto.LEGACY_TYPE, legacyType);
- networkCapabilities.dumpDebug(proto, NetworkRequestProto.NETWORK_CAPABILITIES);
-
- proto.end(token);
- }
-
public boolean equals(@Nullable Object obj) {
if (obj instanceof NetworkRequest == false) return false;
NetworkRequest that = (NetworkRequest)obj;
@@ -699,4 +691,43 @@
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 c4bebc0..a92fda1 100644
--- a/packages/Connectivity/framework/src/android/net/NetworkUtils.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkUtils.java
@@ -92,7 +92,10 @@
* 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 d007a95..f6cae72 100644
--- a/packages/Connectivity/framework/src/android/net/SocketKeepalive.java
+++ b/packages/Connectivity/framework/src/android/net/SocketKeepalive.java
@@ -55,36 +55,68 @@
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 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 @@
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 @@
ERROR_INVALID_LENGTH,
ERROR_UNSUPPORTED,
ERROR_INSUFFICIENT_RESOURCES,
- ERROR_HARDWARE_UNSUPPORTED
})
public @interface KeepaliveEvent {}
diff --git a/packages/Connectivity/framework/src/android/net/VpnTransportInfo.java b/packages/Connectivity/framework/src/android/net/VpnTransportInfo.java
index cd8f4c0..ba83a44 100644
--- a/packages/Connectivity/framework/src/android/net/VpnTransportInfo.java
+++ b/packages/Connectivity/framework/src/android/net/VpnTransportInfo.java
@@ -17,11 +17,14 @@
package android.net;
import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
+import static android.net.NetworkCapabilities.REDACT_FOR_NETWORK_SETTINGS;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
+import android.text.TextUtils;
import java.util.Objects;
@@ -38,8 +41,26 @@
/** Type of this VPN. */
public final int type;
- public VpnTransportInfo(int type) {
+ @Nullable
+ public final String sessionId;
+
+ @Override
+ public long getApplicableRedactions() {
+ return REDACT_FOR_NETWORK_SETTINGS;
+ }
+
+ /**
+ * Create a copy of a {@link VpnTransportInfo} with the sessionId redacted if necessary.
+ */
+ @NonNull
+ public VpnTransportInfo makeCopy(long redactions) {
+ return new VpnTransportInfo(type,
+ ((redactions & REDACT_FOR_NETWORK_SETTINGS) != 0) ? null : sessionId);
+ }
+
+ public VpnTransportInfo(int type, @Nullable String sessionId) {
this.type = type;
+ this.sessionId = sessionId;
}
@Override
@@ -47,17 +68,17 @@
if (!(o instanceof VpnTransportInfo)) return false;
VpnTransportInfo that = (VpnTransportInfo) o;
- return this.type == that.type;
+ return (this.type == that.type) && TextUtils.equals(this.sessionId, that.sessionId);
}
@Override
public int hashCode() {
- return Objects.hash(type);
+ return Objects.hash(type, sessionId);
}
@Override
public String toString() {
- return String.format("VpnTransportInfo{type=%d}", type);
+ return String.format("VpnTransportInfo{type=%d, sessionId=%s}", type, sessionId);
}
@Override
@@ -68,12 +89,13 @@
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeInt(type);
+ dest.writeString(sessionId);
}
public static final @NonNull Creator<VpnTransportInfo> CREATOR =
new Creator<VpnTransportInfo>() {
public VpnTransportInfo createFromParcel(Parcel in) {
- return new VpnTransportInfo(in.readInt());
+ return new VpnTransportInfo(in.readInt(), in.readString());
}
public VpnTransportInfo[] newArray(int size) {
return new VpnTransportInfo[size];
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
index c57d4ad..cbb5105 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
@@ -66,31 +66,40 @@
@Override
public void onCapabilitiesChanged(
Network network, NetworkCapabilities networkCapabilities) {
+ WifiInfo wifiInfo = (WifiInfo) networkCapabilities.getTransportInfo();
+ updateWifiInfo(wifiInfo);
+ updateStatusLabel();
+ mCallback.run();
+ }
+
+ @Override
+ public void onLost(Network network) {
+ updateWifiInfo(null);
updateStatusLabel();
mCallback.run();
}
};
private final NetworkCallback mDefaultNetworkCallback = new NetworkCallback() {
- @Override
- public void onCapabilitiesChanged(Network network, NetworkCapabilities nc) {
- // network is now the default network, and its capabilities are nc.
- // This method will always be called immediately after the network becomes the
- // default, in addition to any time the capabilities change while the network is
- // the default.
- mDefaultNetwork = network;
- mDefaultNetworkCapabilities = nc;
- updateStatusLabel();
- mCallback.run();
- }
- @Override
- public void onLost(Network network) {
- // The system no longer has a default network.
- mDefaultNetwork = null;
- mDefaultNetworkCapabilities = null;
- updateStatusLabel();
- mCallback.run();
- }
- };
+ @Override
+ public void onCapabilitiesChanged(Network network, NetworkCapabilities nc) {
+ // network is now the default network, and its capabilities are nc.
+ // This method will always be called immediately after the network becomes the
+ // default, in addition to any time the capabilities change while the network is
+ // the default.
+ mDefaultNetwork = network;
+ mDefaultNetworkCapabilities = nc;
+ updateStatusLabel();
+ mCallback.run();
+ }
+ @Override
+ public void onLost(Network network) {
+ // The system no longer has a default network.
+ mDefaultNetwork = null;
+ mDefaultNetworkCapabilities = null;
+ updateStatusLabel();
+ mCallback.run();
+ }
+ };
private Network mDefaultNetwork = null;
private NetworkCapabilities mDefaultNetworkCapabilities = null;
private final Runnable mCallback;
@@ -170,32 +179,22 @@
String action = intent.getAction();
if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
updateWifiState();
- } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
- updateWifiState();
- final NetworkInfo networkInfo =
- intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
- connected = networkInfo != null && networkInfo.isConnected();
- mWifiInfo = null;
- ssid = null;
- if (connected) {
- mWifiInfo = mWifiManager.getConnectionInfo();
- if (mWifiInfo != null) {
- if (mWifiInfo.isPasspointAp() || mWifiInfo.isOsuAp()) {
- ssid = mWifiInfo.getPasspointProviderFriendlyName();
- } else {
- ssid = getValidSsid(mWifiInfo);
- }
- updateRssi(mWifiInfo.getRssi());
- maybeRequestNetworkScore();
- }
+ }
+ }
+
+ private void updateWifiInfo(WifiInfo wifiInfo) {
+ updateWifiState();
+ connected = wifiInfo != null;
+ mWifiInfo = wifiInfo;
+ ssid = null;
+ if (mWifiInfo != null) {
+ if (mWifiInfo.isPasspointAp() || mWifiInfo.isOsuAp()) {
+ ssid = mWifiInfo.getPasspointProviderFriendlyName();
+ } else {
+ ssid = getValidSsid(mWifiInfo);
}
- updateStatusLabel();
- mCallback.run();
- } else if (action.equals(WifiManager.RSSI_CHANGED_ACTION)) {
- // Default to -200 as its below WifiManager.MIN_RSSI.
- updateRssi(intent.getIntExtra(WifiManager.EXTRA_NEW_RSSI, -200));
- updateStatusLabel();
- mCallback.run();
+ updateRssi(mWifiInfo.getRssi());
+ maybeRequestNetworkScore();
}
}
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index cad4b69..bd5f8ab 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" />
@@ -355,6 +360,9 @@
<!-- Permission needed for CTS test - CtsHdmiCecHostTestCases -->
<uses-permission android:name="android.permission.HDMI_CEC" />
+ <!-- Permission needed for CTS test - MediaPlayerTest -->
+ <uses-permission android:name="android.permission.BIND_IMS_SERVICE" />
+
<!-- Permission needed for CTS test - WifiManagerTest -->
<uses-permission android:name="android.permission.WIFI_ACCESS_COEX_UNSAFE_CHANNELS" />
<uses-permission android:name="android.permission.WIFI_UPDATE_COEX_UNSAFE_CHANNELS" />
@@ -370,6 +378,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 f884270..835471d 100644
--- a/packages/SystemUI/OWNERS
+++ b/packages/SystemUI/OWNERS
@@ -9,6 +9,7 @@
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 @@
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 @@
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 @@
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 @@
vadimt@google.com
victortulias@google.com
winsonc@google.com
+yurilin@google.com
xuqiu@google.com
zakcohen@google.com
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index df00a4f..7e3ffde 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -344,8 +344,6 @@
// broadcasts
IntentFilter filter = new IntentFilter();
- filter.addAction(WifiManager.RSSI_CHANGED_ACTION);
- filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
filter.addAction(Intent.ACTION_SIM_STATE_CHANGED);
filter.addAction(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
index 4ae9665..3c0b07a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
@@ -101,11 +101,7 @@
wifiDesc, mCurrentState.isTransient, mCurrentState.statusLabel);
}
- /**
- * Fetches wifi initial state replacing the initial sticky broadcast.
- */
- public void fetchInitialState() {
- mWifiTracker.fetchInitialState();
+ private void copyWifiStates() {
mCurrentState.enabled = mWifiTracker.enabled;
mCurrentState.isDefault = mWifiTracker.isDefaultNetwork;
mCurrentState.connected = mWifiTracker.connected;
@@ -113,6 +109,14 @@
mCurrentState.rssi = mWifiTracker.rssi;
mCurrentState.level = mWifiTracker.level;
mCurrentState.statusLabel = mWifiTracker.statusLabel;
+ }
+
+ /**
+ * Fetches wifi initial state replacing the initial sticky broadcast.
+ */
+ public void fetchInitialState() {
+ mWifiTracker.fetchInitialState();
+ copyWifiStates();
notifyListenersIfNecessary();
}
@@ -121,19 +125,12 @@
*/
public void handleBroadcast(Intent intent) {
mWifiTracker.handleBroadcast(intent);
- mCurrentState.enabled = mWifiTracker.enabled;
- mCurrentState.isDefault = mWifiTracker.isDefaultNetwork;
- mCurrentState.connected = mWifiTracker.connected;
- mCurrentState.ssid = mWifiTracker.ssid;
- mCurrentState.rssi = mWifiTracker.rssi;
- mCurrentState.level = mWifiTracker.level;
- mCurrentState.statusLabel = mWifiTracker.statusLabel;
+ copyWifiStates();
notifyListenersIfNecessary();
}
private void handleStatusUpdated() {
- mCurrentState.statusLabel = mWifiTracker.statusLabel;
- mCurrentState.isDefault = mWifiTracker.isDefaultNetwork;
+ copyWifiStates();
notifyListenersIfNecessary();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
index 3a84e31..0dfcf7a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
@@ -40,7 +40,9 @@
import android.net.ConnectivityManager;
import android.net.Network;
import android.net.NetworkCapabilities;
+import android.net.NetworkRequest;
import android.net.NetworkScoreManager;
+import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Handler;
import android.provider.Settings;
@@ -51,7 +53,6 @@
import android.telephony.SignalStrength;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
-import android.telephony.TelephonyCallback;
import android.telephony.TelephonyDisplayInfo;
import android.telephony.TelephonyManager;
import android.testing.TestableLooper;
@@ -115,6 +116,7 @@
protected int mSubId;
private NetworkCapabilities mNetCapabilities;
+ private ConnectivityManager.NetworkCallback mDefaultNetworkCallback;
private ConnectivityManager.NetworkCallback mNetworkCallback;
@Rule
@@ -214,6 +216,10 @@
ArgumentCaptor.forClass(ConnectivityManager.NetworkCallback.class);
verify(mMockCm, atLeastOnce())
.registerDefaultNetworkCallback(callbackArg.capture(), isA(Handler.class));
+ mDefaultNetworkCallback = callbackArg.getValue();
+ assertNotNull(mDefaultNetworkCallback);
+ verify(mMockCm, atLeastOnce()).registerNetworkCallback(
+ isA(NetworkRequest.class), callbackArg.capture(), isA(Handler.class));
mNetworkCallback = callbackArg.getValue();
assertNotNull(mNetworkCallback);
}
@@ -270,10 +276,19 @@
}
public void setConnectivityViaCallback(
- int networkType, boolean validated, boolean isConnected){
+ int networkType, boolean validated, boolean isConnected, WifiInfo wifiInfo) {
+ mNetCapabilities.setTransportInfo(wifiInfo);
setConnectivityCommon(networkType, validated, isConnected);
- mNetworkCallback.onCapabilitiesChanged(
+ mDefaultNetworkCallback.onCapabilitiesChanged(
mock(Network.class), new NetworkCapabilities(mNetCapabilities));
+ if (networkType == NetworkCapabilities.TRANSPORT_WIFI) {
+ if (isConnected) {
+ mNetworkCallback.onCapabilitiesChanged(
+ mock(Network.class), new NetworkCapabilities(mNetCapabilities));
+ } else {
+ mNetworkCallback.onLost(mock(Network.class));
+ }
+ }
}
private void setConnectivityCommon(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java
index 988e022..9c9d6ea 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerWifiTest.java
@@ -32,6 +32,7 @@
// These match the constants in WifiManager and need to be kept up to date.
private static final int MIN_RSSI = -100;
private static final int MAX_RSSI = -55;
+ private WifiInfo mWifiInfo = mock(WifiInfo.class);
@Test
public void testWifiIcon() {
@@ -41,15 +42,16 @@
setWifiState(true, testSsid);
setWifiLevel(0);
+ setConnectivityViaCallback(NetworkCapabilities.TRANSPORT_WIFI, false, true, mWifiInfo);
// Connected, but still not validated - does not show
verifyLastWifiIcon(false, WifiIcons.WIFI_SIGNAL_STRENGTH[0][0]);
for (int testLevel = 0; testLevel < WifiIcons.WIFI_LEVEL_COUNT; testLevel++) {
setWifiLevel(testLevel);
- setConnectivityViaBroadcast(NetworkCapabilities.TRANSPORT_WIFI, true, true);
+ setConnectivityViaCallback(NetworkCapabilities.TRANSPORT_WIFI, true, true, mWifiInfo);
verifyLastWifiIcon(true, WifiIcons.WIFI_SIGNAL_STRENGTH[1][testLevel]);
- setConnectivityViaBroadcast(NetworkCapabilities.TRANSPORT_WIFI, false, true);
+ setConnectivityViaCallback(NetworkCapabilities.TRANSPORT_WIFI, false, true, mWifiInfo);
// Icon does not show if not validated
verifyLastWifiIcon(false, WifiIcons.WIFI_SIGNAL_STRENGTH[0][testLevel]);
}
@@ -69,10 +71,10 @@
for (int testLevel = 0; testLevel < WifiIcons.WIFI_LEVEL_COUNT; testLevel++) {
setWifiLevel(testLevel);
- setConnectivityViaBroadcast(NetworkCapabilities.TRANSPORT_WIFI, true, true);
+ setConnectivityViaCallback(NetworkCapabilities.TRANSPORT_WIFI, true, true, mWifiInfo);
verifyLastQsWifiIcon(true, true, WifiIcons.QS_WIFI_SIGNAL_STRENGTH[1][testLevel],
testSsid);
- setConnectivityViaBroadcast(NetworkCapabilities.TRANSPORT_WIFI, false, true);
+ setConnectivityViaCallback(NetworkCapabilities.TRANSPORT_WIFI, false, true, mWifiInfo);
verifyLastQsWifiIcon(true, true, WifiIcons.QS_WIFI_SIGNAL_STRENGTH[0][testLevel],
testSsid);
}
@@ -86,7 +88,7 @@
setWifiEnabled(true);
setWifiState(true, testSsid);
setWifiLevel(testLevel);
- setConnectivityViaBroadcast(NetworkCapabilities.TRANSPORT_WIFI, true, true);
+ setConnectivityViaCallback(NetworkCapabilities.TRANSPORT_WIFI, true, true, mWifiInfo);
verifyLastQsWifiIcon(true, true,
WifiIcons.QS_WIFI_SIGNAL_STRENGTH[1][testLevel], testSsid);
@@ -111,14 +113,14 @@
setWifiEnabled(true);
setWifiState(true, testSsid);
setWifiLevel(testLevel);
- setConnectivityViaBroadcast(NetworkCapabilities.TRANSPORT_WIFI, true, true);
+ setConnectivityViaCallback(NetworkCapabilities.TRANSPORT_WIFI, true, true, mWifiInfo);
verifyLastWifiIcon(true, WifiIcons.WIFI_SIGNAL_STRENGTH[1][testLevel]);
setupDefaultSignal();
setGsmRoaming(true);
// Still be on wifi though.
- setConnectivityViaBroadcast(NetworkCapabilities.TRANSPORT_WIFI, true, true);
- setConnectivityViaBroadcast(NetworkCapabilities.TRANSPORT_CELLULAR, false, false);
+ setConnectivityViaCallback(NetworkCapabilities.TRANSPORT_WIFI, true, true, mWifiInfo);
+ setConnectivityViaCallback(NetworkCapabilities.TRANSPORT_CELLULAR, false, false, mWifiInfo);
verifyLastMobileDataIndicators(true,
DEFAULT_LEVEL,
0, true);
@@ -132,10 +134,10 @@
setWifiEnabled(true);
setWifiState(true, testSsid);
setWifiLevel(testLevel);
- setConnectivityViaBroadcast(NetworkCapabilities.TRANSPORT_WIFI, true, true);
+ setConnectivityViaCallback(NetworkCapabilities.TRANSPORT_WIFI, true, true, mWifiInfo);
verifyLastWifiIcon(true, WifiIcons.WIFI_SIGNAL_STRENGTH[1][testLevel]);
- setConnectivityViaCallback(NetworkCapabilities.TRANSPORT_WIFI, false, true);
+ setConnectivityViaCallback(NetworkCapabilities.TRANSPORT_WIFI, false, true, mWifiInfo);
verifyLastWifiIcon(false, WifiIcons.WIFI_SIGNAL_STRENGTH[0][testLevel]);
}
@@ -147,11 +149,11 @@
setWifiEnabled(true);
setWifiState(true, testSsid);
setWifiLevel(testLevel);
- setConnectivityViaBroadcast(NetworkCapabilities.TRANSPORT_WIFI, true, true);
+ setConnectivityViaCallback(NetworkCapabilities.TRANSPORT_WIFI, true, true, mWifiInfo);
verifyLastWifiIcon(true, WifiIcons.WIFI_SIGNAL_STRENGTH[1][testLevel]);
setWifiState(false, testSsid);
- setConnectivityViaCallback(NetworkCapabilities.TRANSPORT_WIFI, false, false);
+ setConnectivityViaCallback(NetworkCapabilities.TRANSPORT_WIFI, false, false, mWifiInfo);
verifyLastWifiIcon(false, WifiIcons.WIFI_NO_NETWORK);
}
@@ -162,14 +164,14 @@
setWifiEnabled(true);
verifyLastWifiIcon(false, WifiIcons.WIFI_NO_NETWORK);
- setConnectivityViaCallback(NetworkCapabilities.TRANSPORT_VPN, false, true);
- setConnectivityViaCallback(NetworkCapabilities.TRANSPORT_VPN, true, true);
+ setConnectivityViaCallback(NetworkCapabilities.TRANSPORT_VPN, false, true, mWifiInfo);
+ setConnectivityViaCallback(NetworkCapabilities.TRANSPORT_VPN, true, true, mWifiInfo);
verifyLastWifiIcon(false, WifiIcons.WIFI_NO_NETWORK);
// Mock calling setUnderlyingNetworks.
setWifiState(true, testSsid);
setWifiLevel(testLevel);
- setConnectivityViaCallback(NetworkCapabilities.TRANSPORT_WIFI, true, true);
+ setConnectivityViaCallback(NetworkCapabilities.TRANSPORT_WIFI, true, true, mWifiInfo);
verifyLastWifiIcon(true, WifiIcons.WIFI_SIGNAL_STRENGTH[1][testLevel]);
}
@@ -209,6 +211,7 @@
int rssi = (int)(MIN_RSSI + level * amountPerLevel);
// Put RSSI in the middle of the range.
rssi += amountPerLevel / 2;
+ when(mWifiInfo.getRssi()).thenReturn(rssi);
Intent i = new Intent(WifiManager.RSSI_CHANGED_ACTION);
i.putExtra(WifiManager.EXTRA_NEW_RSSI, rssi);
mNetworkController.onReceive(mContext, i);
@@ -224,10 +227,8 @@
Intent i = new Intent(WifiManager.NETWORK_STATE_CHANGED_ACTION);
NetworkInfo networkInfo = mock(NetworkInfo.class);
when(networkInfo.isConnected()).thenReturn(connected);
-
- WifiInfo wifiInfo = mock(WifiInfo.class);
- when(wifiInfo.getSSID()).thenReturn(ssid);
- when(mMockWm.getConnectionInfo()).thenReturn(wifiInfo);
+ when(mWifiInfo.getSSID()).thenReturn(ssid);
+ when(mMockWm.getConnectionInfo()).thenReturn(mWifiInfo);
i.putExtra(WifiManager.EXTRA_NETWORK_INFO, networkInfo);
mNetworkController.onReceive(mContext, i);
diff --git a/packages/WAPPushManager/AndroidManifest.xml b/packages/WAPPushManager/AndroidManifest.xml
index a75fb2d..15f01e6 100644
--- a/packages/WAPPushManager/AndroidManifest.xml
+++ b/packages/WAPPushManager/AndroidManifest.xml
@@ -27,7 +27,8 @@
<original-package android:name="com.android.smspush" />
<application
- android:allowClearUserData="false">
+ android:allowClearUserData="false"
+ android:directBootAware="true">
<service android:name=".WapPushManager"
android:permission="com.android.smspush.WAPPUSH_MANAGER_BIND"
android:exported="true">
diff --git a/packages/WAPPushManager/src/com/android/smspush/WapPushManager.java b/packages/WAPPushManager/src/com/android/smspush/WapPushManager.java
index dc2707b..951e64f 100755
--- a/packages/WAPPushManager/src/com/android/smspush/WapPushManager.java
+++ b/packages/WAPPushManager/src/com/android/smspush/WapPushManager.java
@@ -26,17 +26,21 @@
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.database.Cursor;
-import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
import android.os.Build;
import android.os.IBinder;
import android.os.PowerManager;
import android.os.RemoteException;
+import android.os.UserManager;
import android.util.Log;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.IWapPushManager;
import com.android.internal.telephony.WapPushManagerParams;
+import java.io.File;
+
/**
* The WapPushManager service is implemented to process incoming
* WAP Push messages and to maintain the Receiver Application/Application
@@ -67,8 +71,13 @@
/**
* Inner class that deals with application ID table
*/
- private class WapPushManDBHelper extends SQLiteOpenHelper {
- WapPushManDBHelper(Context context) {
+ @VisibleForTesting
+ public static class WapPushManDBHelper extends SQLiteOpenHelper {
+ /**
+ * Constructor
+ */
+ @VisibleForTesting
+ public WapPushManDBHelper(Context context) {
super(context, DATABASE_NAME, null, WAP_PUSH_MANAGER_VERSION);
if (LOCAL_LOGV) Log.v(LOG_TAG, "helper instance created.");
}
@@ -269,10 +278,6 @@
int app_type, boolean need_signature, boolean further_processing) {
WapPushManDBHelper dbh = getDatabase(mContext);
SQLiteDatabase db = dbh.getWritableDatabase();
- WapPushManDBHelper.queryData lastapp = dbh.queryLastApp(db, x_app_id, content_type);
- boolean ret = false;
- boolean insert = false;
- int sq = 0;
if (!appTypeCheck(app_type)) {
Log.w(LOG_TAG, "invalid app_type " + app_type + ". app_type must be "
@@ -280,34 +285,8 @@
+ WapPushManagerParams.APP_TYPE_SERVICE);
return false;
}
-
- if (lastapp == null) {
- insert = true;
- sq = 0;
- } else if (!lastapp.packageName.equals(package_name) ||
- !lastapp.className.equals(class_name)) {
- insert = true;
- sq = lastapp.installOrder + 1;
- }
-
- if (insert) {
- ContentValues values = new ContentValues();
-
- values.put("x_wap_application", x_app_id);
- values.put("content_type", content_type);
- values.put("package_name", package_name);
- values.put("class_name", class_name);
- values.put("app_type", app_type);
- values.put("need_signature", need_signature ? 1 : 0);
- values.put("further_processing", further_processing ? 1 : 0);
- values.put("install_order", sq);
- db.insert(APPID_TABLE_NAME, null, values);
- if (LOCAL_LOGV) Log.v(LOG_TAG, "add:" + x_app_id + ":" + content_type
- + " " + package_name + "." + class_name
- + ", newsq:" + sq);
- ret = true;
- }
-
+ boolean ret = insertPackage(dbh, db, x_app_id, content_type, package_name, class_name,
+ app_type, need_signature, further_processing);
db.close();
return ret;
@@ -404,11 +383,91 @@
protected WapPushManDBHelper getDatabase(Context context) {
if (mDbHelper == null) {
if (LOCAL_LOGV) Log.v(LOG_TAG, "create new db inst.");
- mDbHelper = new WapPushManDBHelper(context);
+ mDbHelper = new WapPushManDBHelper(context.createDeviceProtectedStorageContext());
}
+ // Migrate existing legacy database into the device encrypted storage.
+ migrateWapPushManDBIfNeeded(context);
return mDbHelper;
}
+ /**
+ * Inserts a package information into a database
+ */
+ @VisibleForTesting
+ public boolean insertPackage(WapPushManDBHelper dbh, SQLiteDatabase db, String appId,
+ String contentType, String packageName, String className, int appType,
+ boolean needSignature, boolean furtherProcessing) {
+
+ WapPushManDBHelper.queryData lastapp = dbh.queryLastApp(db, appId, contentType);
+ boolean insert = false;
+ int sq = 0;
+
+ if (lastapp == null) {
+ insert = true;
+ sq = 0;
+ } else if (!lastapp.packageName.equals(packageName)
+ || !lastapp.className.equals(className)) {
+ insert = true;
+ sq = lastapp.installOrder + 1;
+ }
+
+ if (insert) {
+ ContentValues values = new ContentValues();
+
+ values.put("x_wap_application", appId);
+ values.put("content_type", contentType);
+ values.put("package_name", packageName);
+ values.put("class_name", className);
+ values.put("app_type", appType);
+ values.put("need_signature", needSignature ? 1 : 0);
+ values.put("further_processing", furtherProcessing ? 1 : 0);
+ values.put("install_order", sq);
+ db.insert(APPID_TABLE_NAME, null, values);
+ if (LOCAL_LOGV) {
+ Log.v(LOG_TAG, "add:" + appId + ":" + contentType + " " + packageName
+ + "." + className + ", newsq:" + sq);
+ }
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Migrates a legacy database into the device encrypted storage
+ */
+ private void migrateWapPushManDBIfNeeded(Context context) {
+ UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
+ File file = context.getDatabasePath(DATABASE_NAME);
+ if (!userManager.isUserUnlocked() || !file.exists()) {
+ // Check if the device is unlocked because a legacy database can't access during
+ // DirectBoot.
+ return;
+ }
+
+ // Migration steps below:
+ // 1. Merge the package info to legacy database if there is any package info which is
+ // registered during DirectBoot.
+ // 2. Move the data base to the device encryped storage.
+ WapPushManDBHelper legacyDbHelper = new WapPushManDBHelper(context);
+ SQLiteDatabase legacyDb = legacyDbHelper.getWritableDatabase();
+ SQLiteDatabase db = mDbHelper.getWritableDatabase();
+ Cursor cur = db.query(APPID_TABLE_NAME, null, null, null, null, null, null);
+ while (cur.moveToNext()) {
+ insertPackage(legacyDbHelper, legacyDb,
+ cur.getString(cur.getColumnIndex("x_wap_application")),
+ cur.getString(cur.getColumnIndex("content_type")),
+ cur.getString(cur.getColumnIndex("package_name")),
+ cur.getString(cur.getColumnIndex("class_name")),
+ cur.getInt(cur.getColumnIndex("app_type")),
+ cur.getInt(cur.getColumnIndex("need_signature")) == 1,
+ cur.getInt(cur.getColumnIndex("further_processing")) == 1);
+ }
+ cur.close();
+ legacyDb.close();
+ db.close();
+ context.createDeviceProtectedStorageContext().moveDatabaseFrom(context, DATABASE_NAME);
+ Log.i(LOG_TAG, "Migrated the legacy database.");
+ }
/**
* This method is used for testing
diff --git a/packages/WAPPushManager/tests/src/com/android/smspush/unitTests/WapPushTest.java b/packages/WAPPushManager/tests/src/com/android/smspush/unitTests/WapPushTest.java
index f7afc57..b9dac4e 100644
--- a/packages/WAPPushManager/tests/src/com/android/smspush/unitTests/WapPushTest.java
+++ b/packages/WAPPushManager/tests/src/com/android/smspush/unitTests/WapPushTest.java
@@ -21,6 +21,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
+import android.database.sqlite.SQLiteDatabase;
import android.os.IBinder;
import android.os.RemoteException;
import android.provider.Telephony.Sms.Intents;
@@ -33,7 +34,9 @@
import com.android.internal.telephony.uicc.IccUtils;
import com.android.internal.util.HexDump;
import com.android.smspush.WapPushManager;
+import com.android.smspush.WapPushManager.WapPushManDBHelper;
+import java.io.File;
import java.util.Random;
/**
@@ -467,8 +470,9 @@
try {
super.setUp();
// get verifier
- getContext().bindService(new Intent(IDataVerify.class.getName()),
- mConn, Context.BIND_AUTO_CREATE);
+ Intent intent = new Intent(IDataVerify.class.getName());
+ intent.setPackage("com.android.smspush.unitTests");
+ getContext().bindService(intent, mConn, Context.BIND_AUTO_CREATE);
} catch (Exception e) {
Log.w(LOG_TAG, "super exception");
}
@@ -552,15 +556,15 @@
}
/**
- * Add sqlite injection test
+ * Sqlite injection test
*/
- public void testAddPackage0() {
+ public void testSqliteInjection() {
String inject = "' union select 0,'com.android.settings','com.android.settings.Settings',0,0,0--";
- // insert new data
+ // update data
IWapPushManager iwapman = getInterface();
try {
- assertFalse(iwapman.addPackage(
+ assertFalse(iwapman.updatePackage(
inject,
Integer.toString(mContentTypeValue),
mPackageName, mClassName,
@@ -2528,4 +2532,45 @@
mMessageBody = originalMessageBody;
}
+ /**
+ * DataBase migration test.
+ */
+ public void testDataBaseMigration() {
+ IWapPushManager iwapman = getInterface();
+ WapPushManager wpman = getService();
+ Context context = getContext();
+
+ addPackageToLegacyDB(mAppIdValue, mContentTypeValue, mPackageName, mClassName,
+ WapPushManagerParams.APP_TYPE_SERVICE, true, true);
+ addPackageToLegacyDB(mAppIdValue + 10, mContentTypeValue, mPackageName, mClassName,
+ WapPushManagerParams.APP_TYPE_SERVICE, true, true);
+
+ File oldDbFile = context.getDatabasePath("wappush.db");
+ assertTrue(oldDbFile.exists());
+ assertTrue(wpman.verifyData(Integer.toString(mAppIdValue),
+ Integer.toString(mContentTypeValue),
+ mPackageName, mClassName,
+ WapPushManagerParams.APP_TYPE_SERVICE, true, true));
+ assertFalse(oldDbFile.exists());
+
+ // Clean up DB
+ try {
+ iwapman.deletePackage(Integer.toString(mAppIdValue),
+ Integer.toString(mContentTypeValue), mPackageName, mClassName);
+ iwapman.deletePackage(Integer.toString(mAppIdValue + 10),
+ Integer.toString(mContentTypeValue), mPackageName, mClassName);
+ } catch (RemoteException e) {
+ assertTrue(false);
+ }
+ }
+
+ private void addPackageToLegacyDB(int appId, int contextType, String packagename,
+ String classnName, int appType, boolean signature, boolean furtherProcessing) {
+ WapPushManager wpman = getService();
+ WapPushManDBHelper dbh = new WapPushManDBHelper(getContext());
+ SQLiteDatabase db = dbh.getWritableDatabase();
+
+ wpman.insertPackage(dbh, db, Integer.toString(appId), Integer.toString(contextType),
+ packagename, classnName, appType, signature, furtherProcessing);
+ }
}
diff --git a/rs/java/Android.bp b/rs/java/Android.bp
new file mode 100644
index 0000000..1c2b575
--- /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 0000000..0ed69e4
--- /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/Android.bp b/services/Android.bp
index 872b118..0a01c95 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -107,6 +107,7 @@
libs: [
"android.hidl.manager-V1.0-java",
"framework-tethering.stubs.module_lib",
+ "service-art.stubs.system_server",
],
// Uncomment to enable output of certain warnings (deprecated, unchecked)
@@ -146,7 +147,7 @@
" --hide DeprecationMismatch" +
" --hide HiddenTypedefConstant",
visibility: ["//visibility:private"],
- filter_packages: ["com.android."]
+ filter_packages: ["com.android."],
}
droidstubs {
@@ -161,7 +162,7 @@
last_released: {
api_file: ":android.api.system-server.latest",
removed_api_file: ":removed.api.system-server.latest",
- baseline_file: ":android-incompatibilities.api.system-server.latest"
+ baseline_file: ":android-incompatibilities.api.system-server.latest",
},
api_lint: {
enabled: true,
@@ -171,18 +172,24 @@
},
dists: [
{
- targets: ["sdk", "win_sdk"],
+ targets: [
+ "sdk",
+ "win_sdk",
+ ],
dir: "apistubs/android/system-server/api",
dest: "android.txt",
- tag: ".api.txt"
+ tag: ".api.txt",
},
{
- targets: ["sdk", "win_sdk"],
+ targets: [
+ "sdk",
+ "win_sdk",
+ ],
dir: "apistubs/android/system-server/api",
dest: "removed.txt",
tag: ".removed-api.txt",
},
- ]
+ ],
}
java_library {
@@ -216,16 +223,22 @@
},
dists: [
{
- targets: ["sdk", "win_sdk"],
+ targets: [
+ "sdk",
+ "win_sdk",
+ ],
dir: "apistubs/android/system-server/api",
dest: "android-non-updatable.txt",
- tag: ".api.txt"
+ tag: ".api.txt",
},
{
- targets: ["sdk", "win_sdk"],
+ targets: [
+ "sdk",
+ "win_sdk",
+ ],
dir: "apistubs/android/system-server/api",
dest: "android-non-updatable-removed.tx",
tag: ".removed-api.txt",
},
- ]
-}
\ No newline at end of file
+ ],
+}
diff --git a/services/api/current.txt b/services/api/current.txt
index 17ca369..7c5c01e 100644
--- a/services/api/current.txt
+++ b/services/api/current.txt
@@ -80,6 +80,14 @@
}
+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 647739f..6419b70 100644
--- a/services/api/non-updatable-current.txt
+++ b/services/api/non-updatable-current.txt
@@ -35,6 +35,14 @@
}
+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/backup/OWNERS b/services/backup/OWNERS
index ba2a63a..cc36b47 100644
--- a/services/backup/OWNERS
+++ b/services/backup/OWNERS
@@ -9,4 +9,3 @@
niamhfw@google.com
philippov@google.com
rthakohov@google.com
-tobiast@google.com
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index b737189..5aa3e5b 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.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.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 @@
// 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 @@
protected final PermissionMonitor mPermissionMonitor;
private final PerUidCounter mNetworkRequestCounter;
+ private final PerUidCounter mSystemNetworkRequestCounter;
private volatile boolean mLockdownEnabled;
@@ -1146,8 +1153,8 @@
/**
* @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 @@
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();
@@ -1273,14 +1281,22 @@
mPermissionMonitor = new PermissionMonitor(mContext, mNetd);
+ mUserAllContext = mContext.createContextAsUser(UserHandle.ALL, 0 /* flags */);
// Listen for user add/removes to inform PermissionMonitor.
// Should run on mHandler to avoid any races.
- IntentFilter intentFilter = new IntentFilter();
- intentFilter.addAction(Intent.ACTION_USER_ADDED);
- intentFilter.addAction(Intent.ACTION_USER_REMOVED);
+ final IntentFilter userIntentFilter = new IntentFilter();
+ userIntentFilter.addAction(Intent.ACTION_USER_ADDED);
+ userIntentFilter.addAction(Intent.ACTION_USER_REMOVED);
+ mUserAllContext.registerReceiver(mUserIntentReceiver, userIntentFilter,
+ null /* broadcastPermission */, mHandler);
- mUserAllContext = mContext.createContextAsUser(UserHandle.ALL, 0 /* flags */);
- mUserAllContext.registerReceiver(mIntentReceiver, intentFilter,
+ // Listen to package add/removes for netd
+ final IntentFilter packageIntentFilter = new IntentFilter();
+ packageIntentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
+ packageIntentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+ packageIntentFilter.addAction(Intent.ACTION_PACKAGE_REPLACED);
+ packageIntentFilter.addDataScheme("package");
+ mUserAllContext.registerReceiver(mPackageIntentReceiver, packageIntentFilter,
null /* broadcastPermission */, mHandler);
mNetworkActivityTracker = new LegacyNetworkActivityTracker(mContext, mHandler, mNetd);
@@ -1548,16 +1564,16 @@
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)));
}
/**
@@ -1887,6 +1903,10 @@
newNc.setNetworkSpecifier(newNc.getNetworkSpecifier().redact());
}
newNc.setAdministratorUids(new int[0]);
+ if (!checkAnyPermissionOf(
+ callerPid, callerUid, android.Manifest.permission.NETWORK_FACTORY)) {
+ newNc.setSubIds(Collections.emptySet());
+ }
return newNc;
}
@@ -2338,15 +2358,15 @@
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 +3139,13 @@
}
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 +3716,23 @@
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 +3745,7 @@
mDnsManager.removeNetwork(nai.network);
}
mNetIdManager.releaseNetId(nai.network.getNetId());
+ nai.onNetworkDestroyed();
}
private boolean createNativeNetwork(@NonNull NetworkAgentInfo networkAgent) {
@@ -3728,6 +3773,10 @@
private void destroyNativeNetwork(@NonNull NetworkAgentInfo networkAgent) {
try {
mNetd.networkDestroy(networkAgent.network.getNetId());
+ } catch (RemoteException | ServiceSpecificException e) {
+ loge("Exception destroying network(networkDestroy): " + e);
+ }
+ try {
mDnsResolver.destroyNetworkCache(networkAgent.network.getNetId());
} catch (RemoteException | ServiceSpecificException e) {
loge("Exception destroying network: " + e);
@@ -4001,7 +4050,7 @@
}
}
}
- mNetworkRequestCounter.decrementCount(nri.mUid);
+ nri.decrementRequestCount();
mNetworkRequestInfoLogs.log("RELEASE " + nri);
if (null != nri.getActiveRequest()) {
@@ -4112,6 +4161,12 @@
}
}
+ private PerUidCounter getRequestCounter(NetworkRequestInfo nri) {
+ return checkAnyPermissionOf(
+ nri.mPid, nri.mUid, NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK)
+ ? mSystemNetworkRequestCounter : mNetworkRequestCounter;
+ }
+
@Override
public void setAcceptUnvalidated(Network network, boolean accept, boolean always) {
enforceNetworkStackSettingsOrSetup();
@@ -4839,6 +4894,42 @@
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 +4950,7 @@
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);
@@ -4879,7 +4970,7 @@
}
@Override
- public void setGlobalProxy(final ProxyInfo proxyProperties) {
+ public void setGlobalProxy(@Nullable final ProxyInfo proxyProperties) {
PermissionUtils.enforceNetworkStackPermission(mContext);
mProxyTracker.setGlobalProxy(proxyProperties);
}
@@ -5224,14 +5315,14 @@
}
}
- private void onUserAdded(UserHandle user) {
+ private void onUserAdded(@NonNull final UserHandle user) {
mPermissionMonitor.onUserAdded(user);
if (mOemNetworkPreferences.getNetworkPreferences().size() > 0) {
handleSetOemNetworkPreference(mOemNetworkPreferences, null);
}
}
- private void onUserRemoved(UserHandle user) {
+ private void onUserRemoved(@NonNull final UserHandle user) {
mPermissionMonitor.onUserRemoved(user);
// If there was a network preference for this user, remove it.
handleSetProfileNetworkPreference(new ProfileNetworkPreferences.Preference(user, null),
@@ -5241,7 +5332,18 @@
}
}
- private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
+ private void onPackageChanged(@NonNull final String packageName) {
+ // This is necessary in case a package is added or removed, but also when it's replaced to
+ // run as a new UID by its manifest rules. Also, if a separate package shares the same UID
+ // as one in the preferences, then it should follow the same routing as that other package,
+ // which means updating the rules is never to be needed in this case (whether it joins or
+ // leaves a UID with a preference).
+ if (isMappedInOemNetworkPreference(packageName)) {
+ handleSetOemNetworkPreference(mOemNetworkPreferences, null);
+ }
+ }
+
+ private final BroadcastReceiver mUserIntentReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
ensureRunningOnConnectivityServiceThread();
@@ -5264,6 +5366,22 @@
}
};
+ private final BroadcastReceiver mPackageIntentReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ ensureRunningOnConnectivityServiceThread();
+ switch (intent.getAction()) {
+ case Intent.ACTION_PACKAGE_ADDED:
+ case Intent.ACTION_PACKAGE_REMOVED:
+ case Intent.ACTION_PACKAGE_REPLACED:
+ onPackageChanged(intent.getData().getSchemeSpecificPart());
+ break;
+ default:
+ Log.wtf(TAG, "received unexpected intent: " + intent.getAction());
+ }
+ }
+ };
+
private final HashMap<Messenger, NetworkProviderInfo> mNetworkProviderInfos = new HashMap<>();
private final HashMap<NetworkRequest, NetworkRequestInfo> mNetworkRequests = new HashMap<>();
@@ -5374,6 +5492,9 @@
@Nullable
final String mCallingAttributionTag;
+ // Counter keeping track of this NRI.
+ final PerUidCounter mPerUidCounter;
+
// Effective UID of this request. This is different from mUid when a privileged process
// files a request on behalf of another UID. This UID is used to determine blocked status,
// UID matching, and so on. mUid above is used for permission checks and to enforce the
@@ -5424,7 +5545,8 @@
mPid = getCallingPid();
mUid = mDeps.getCallingUid();
mAsUid = asUid;
- mNetworkRequestCounter.incrementCountOrThrow(mUid);
+ mPerUidCounter = getRequestCounter(this);
+ mPerUidCounter.incrementCountOrThrow(mUid);
/**
* Location sensitive data not included in pending intent. Only included in
* {@link NetworkCallback}.
@@ -5456,15 +5578,11 @@
mUid = mDeps.getCallingUid();
mAsUid = asUid;
mPendingIntent = null;
- mNetworkRequestCounter.incrementCountOrThrow(mUid);
+ mPerUidCounter = getRequestCounter(this);
+ mPerUidCounter.incrementCountOrThrow(mUid);
mCallbackFlags = callbackFlags;
mCallingAttributionTag = callingAttributionTag;
-
- try {
- mBinder.linkToDeath(this, 0);
- } catch (RemoteException e) {
- binderDied();
- }
+ linkDeathRecipient();
}
NetworkRequestInfo(@NonNull final NetworkRequestInfo nri,
@@ -5499,9 +5617,11 @@
mUid = nri.mUid;
mAsUid = nri.mAsUid;
mPendingIntent = nri.mPendingIntent;
- mNetworkRequestCounter.incrementCountOrThrow(mUid);
+ mPerUidCounter = getRequestCounter(this);
+ mPerUidCounter.incrementCountOrThrow(mUid);
mCallbackFlags = nri.mCallbackFlags;
mCallingAttributionTag = nri.mCallingAttributionTag;
+ linkDeathRecipient();
}
NetworkRequestInfo(int asUid, @NonNull final NetworkRequest r) {
@@ -5530,8 +5650,22 @@
return Collections.unmodifiableList(tempRequests);
}
+ void decrementRequestCount() {
+ mPerUidCounter.decrementCount(mUid);
+ }
+
+ 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);
}
}
@@ -5552,7 +5686,7 @@
+ mNetworkRequestForCallback.requestId
+ " " + mRequests
+ (mPendingIntent == null ? "" : " to trigger " + mPendingIntent)
- + "callback flags: " + mCallbackFlags;
+ + " callback flags: " + mCallbackFlags;
}
}
@@ -5577,6 +5711,10 @@
"Insufficient permissions to request a specific signal strength");
}
mAppOpsManager.checkPackage(callerUid, callerPackageName);
+
+ if (!nc.getSubIds().isEmpty()) {
+ enforceNetworkFactoryPermission();
+ }
}
private int[] getSignalStrengthThresholds(@NonNull final NetworkAgentInfo nai) {
@@ -6067,6 +6205,15 @@
@NonNull
private ProfileNetworkPreferences mProfileNetworkPreferences = new ProfileNetworkPreferences();
+ /**
+ * Determine whether a given package has a mapping in the current OemNetworkPreferences.
+ * @param packageName the package name to check existence of a mapping for.
+ * @return true if a mapping exists, false otherwise
+ */
+ private boolean isMappedInOemNetworkPreference(@NonNull final String packageName) {
+ return mOemNetworkPreferences.getNetworkPreferences().containsKey(packageName);
+ }
+
// The always-on request for an Internet-capable network that apps without a specific default
// fall back to.
@VisibleForTesting
@@ -6087,7 +6234,7 @@
* @return the NetworkRequestInfo tracking the given uid.
*/
@NonNull
- private NetworkRequestInfo getDefaultRequestTrackingUid(@NonNull final int uid) {
+ private NetworkRequestInfo getDefaultRequestTrackingUid(final int uid) {
for (final NetworkRequestInfo nri : mDefaultNetworkRequests) {
if (nri == mDefaultRequest) {
continue;
@@ -6213,8 +6360,8 @@
// 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
@@ -6534,7 +6681,7 @@
mDeps.reportNetworkInterfaceForTransports(mContext, iface,
caps.getTransportTypes());
} catch (Exception e) {
- loge("Exception adding interface: " + e);
+ logw("Exception adding interface: " + e);
}
}
}
@@ -7308,7 +7455,7 @@
break;
}
case ConnectivityManager.CALLBACK_BLK_CHANGED: {
- maybeLogBlockedStatusChanged(nri, networkAgent.network, arg1 != 0);
+ maybeLogBlockedStatusChanged(nri, networkAgent.network, arg1);
msg.arg1 = arg1;
break;
}
@@ -8052,12 +8199,11 @@
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 +8212,21 @@
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 +8234,10 @@
* 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 +8246,18 @@
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 +8267,23 @@
* @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 +8831,7 @@
// 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);
+ nri.decrementRequestCount();
return;
}
@@ -8739,7 +8897,7 @@
// 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);
+ nri.decrementRequestCount();
iCb.unlinkToDeath(cbInfo, 0);
}
@@ -9315,14 +9473,8 @@
throw new IllegalArgumentException("Must explicitly specify a user handle ("
+ "UserHandle.CURRENT not supported)");
}
- final UserManager um;
- try {
- um = mContext.createContextAsUser(profile, 0 /* flags */)
- .getSystemService(UserManager.class);
- } catch (IllegalStateException e) {
- throw new IllegalArgumentException("Profile does not exist");
- }
- if (!um.isManagedProfile()) {
+ final UserManager um = mContext.getSystemService(UserManager.class);
+ if (!um.isManagedProfile(profile.getIdentifier())) {
throw new IllegalArgumentException("Profile must be a managed profile");
}
// Strictly speaking, mOemNetworkPreferences should only be touched on the
@@ -9489,7 +9641,6 @@
new OemNetworkRequestFactory().createNrisFromOemNetworkPreferences(preference);
replaceDefaultNetworkRequestsForPreference(nris);
mOemNetworkPreferences = preference;
- // TODO http://b/176496396 persist data to shared preferences.
if (null != listener) {
try {
@@ -9646,7 +9797,6 @@
// packages are sent on a network preference as the system will watch for
// package installations associated with this network preference and update
// accordingly. This is done so as to minimize race conditions on app install.
- // TODO b/177092163 add app install watching.
continue;
}
}
diff --git a/services/core/java/com/android/server/OWNERS b/services/core/java/com/android/server/OWNERS
index 3bcde12..9821cdc 100644
--- a/services/core/java/com/android/server/OWNERS
+++ b/services/core/java/com/android/server/OWNERS
@@ -20,6 +20,7 @@
per-file *Alarm* = file:/apex/jobscheduler/OWNERS
per-file *AppOp* = file:/core/java/android/permission/OWNERS
per-file *Battery* = file:/BATTERY_STATS_OWNERS
+per-file *Binder* = file:/core/java/com/android/internal/os/BINDER_OWNERS
per-file *Bluetooth* = file:/core/java/android/bluetooth/OWNERS
per-file *Gnss* = file:/services/core/java/com/android/server/location/OWNERS
per-file *Location* = file:/services/core/java/com/android/server/location/OWNERS
diff --git a/services/core/java/com/android/server/PersistentDataBlockService.java b/services/core/java/com/android/server/PersistentDataBlockService.java
index 351e616..c6fdb9d 100644
--- a/services/core/java/com/android/server/PersistentDataBlockService.java
+++ b/services/core/java/com/android/server/PersistentDataBlockService.java
@@ -23,7 +23,6 @@
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Binder;
-import android.os.FileUtils;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.SystemProperties;
@@ -45,6 +44,7 @@
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.security.MessageDigest;
@@ -131,13 +131,13 @@
private static final String FLASH_LOCK_UNLOCKED = "0";
private final Context mContext;
+ private final String mDataBlockFile;
private final boolean mIsRunningDSU;
private final Object mLock = new Object();
private final CountDownLatch mInitDoneSignal = new CountDownLatch(1);
private int mAllowedUid = -1;
private long mBlockDeviceSize;
- private String mDataBlockFile;
@GuardedBy("mLock")
private boolean mIsWritable = true;
@@ -145,8 +145,12 @@
public PersistentDataBlockService(Context context) {
super(context);
mContext = context;
- mDataBlockFile = SystemProperties.get(PERSISTENT_DATA_BLOCK_PROP);
mIsRunningDSU = SystemProperties.getBoolean(GSI_RUNNING_PROP, false);
+ if (mIsRunningDSU) {
+ mDataBlockFile = GSI_SANDBOX;
+ } else {
+ mDataBlockFile = SystemProperties.get(PERSISTENT_DATA_BLOCK_PROP);
+ }
mBlockDeviceSize = -1; // Load lazily
}
@@ -260,7 +264,11 @@
private long getBlockDeviceSize() {
synchronized (mLock) {
if (mBlockDeviceSize == -1) {
- mBlockDeviceSize = nativeGetBlockDeviceSize(mDataBlockFile);
+ if (mIsRunningDSU) {
+ mBlockDeviceSize = MAX_DATA_BLOCK_SIZE;
+ } else {
+ mBlockDeviceSize = nativeGetBlockDeviceSize(mDataBlockFile);
+ }
}
}
@@ -290,40 +298,30 @@
return true;
}
- private FileOutputStream getBlockOutputStream() throws IOException {
- if (!mIsRunningDSU) {
- return new FileOutputStream(new File(mDataBlockFile));
- } else {
- File sandbox = new File(GSI_SANDBOX);
- File realpdb = new File(SystemProperties.get(PERSISTENT_DATA_BLOCK_PROP));
- if (!sandbox.exists()) {
- FileUtils.copy(realpdb, sandbox);
- mDataBlockFile = GSI_SANDBOX;
- }
- Slog.i(TAG, "PersistentDataBlock copy-on-write");
- return new FileOutputStream(sandbox);
- }
+ private FileChannel getBlockOutputChannel() throws IOException {
+ return new RandomAccessFile(mDataBlockFile, "rw").getChannel();
}
private boolean computeAndWriteDigestLocked() {
byte[] digest = computeDigestLocked(null);
if (digest != null) {
- DataOutputStream outputStream;
+ FileChannel channel;
try {
- outputStream = new DataOutputStream(getBlockOutputStream());
+ channel = getBlockOutputChannel();
} catch (IOException e) {
Slog.e(TAG, "partition not available?", e);
return false;
}
try {
- outputStream.write(digest, 0, DIGEST_SIZE_BYTES);
- outputStream.flush();
+ ByteBuffer buf = ByteBuffer.allocate(DIGEST_SIZE_BYTES);
+ buf.put(digest);
+ buf.flip();
+ channel.write(buf);
+ channel.force(true);
} catch (IOException e) {
Slog.e(TAG, "failed to write block checksum", e);
return false;
- } finally {
- IoUtils.closeQuietly(outputStream);
}
return true;
} else {
@@ -374,25 +372,18 @@
}
private void formatPartitionLocked(boolean setOemUnlockEnabled) {
- DataOutputStream outputStream;
- try {
- outputStream = new DataOutputStream(getBlockOutputStream());
- } catch (IOException e) {
- Slog.e(TAG, "partition not available?", e);
- return;
- }
- byte[] data = new byte[DIGEST_SIZE_BYTES];
try {
- outputStream.write(data, 0, DIGEST_SIZE_BYTES);
- outputStream.writeInt(PARTITION_TYPE_MARKER);
- outputStream.writeInt(0); // data size
- outputStream.flush();
+ FileChannel channel = getBlockOutputChannel();
+ ByteBuffer buf = ByteBuffer.allocate(DIGEST_SIZE_BYTES + HEADER_SIZE);
+ buf.put(new byte[DIGEST_SIZE_BYTES]);
+ buf.putInt(PARTITION_TYPE_MARKER);
+ buf.putInt(0);
+ channel.write(buf);
+ channel.force(true);
} catch (IOException e) {
Slog.e(TAG, "failed to format block", e);
return;
- } finally {
- IoUtils.closeQuietly(outputStream);
}
doSetOemUnlockEnabledLocked(setOemUnlockEnabled);
@@ -400,16 +391,9 @@
}
private void doSetOemUnlockEnabledLocked(boolean enabled) {
- FileOutputStream outputStream;
- try {
- outputStream = getBlockOutputStream();
- } catch (IOException e) {
- Slog.e(TAG, "partition not available", e);
- return;
- }
try {
- FileChannel channel = outputStream.getChannel();
+ FileChannel channel = getBlockOutputChannel();
channel.position(getBlockDeviceSize() - 1);
@@ -417,13 +401,12 @@
data.put(enabled ? (byte) 1 : (byte) 0);
data.flip();
channel.write(data);
- outputStream.flush();
+ channel.force(true);
} catch (IOException e) {
Slog.e(TAG, "unable to access persistent partition", e);
return;
} finally {
SystemProperties.set(OEM_UNLOCK_PROP, enabled ? "1" : "0");
- IoUtils.closeQuietly(outputStream);
}
}
@@ -477,35 +460,32 @@
return (int) -maxBlockSize;
}
- DataOutputStream outputStream;
+ FileChannel channel;
try {
- outputStream = new DataOutputStream(getBlockOutputStream());
+ channel = getBlockOutputChannel();
} catch (IOException e) {
Slog.e(TAG, "partition not available?", e);
- return -1;
+ return -1;
}
- ByteBuffer headerAndData = ByteBuffer.allocate(data.length + HEADER_SIZE);
+ ByteBuffer headerAndData = ByteBuffer.allocate(
+ data.length + HEADER_SIZE + DIGEST_SIZE_BYTES);
+ headerAndData.put(new byte[DIGEST_SIZE_BYTES]);
headerAndData.putInt(PARTITION_TYPE_MARKER);
headerAndData.putInt(data.length);
headerAndData.put(data);
-
+ headerAndData.flip();
synchronized (mLock) {
if (!mIsWritable) {
- IoUtils.closeQuietly(outputStream);
return -1;
}
try {
- byte[] checksum = new byte[DIGEST_SIZE_BYTES];
- outputStream.write(checksum, 0, DIGEST_SIZE_BYTES);
- outputStream.write(headerAndData.array());
- outputStream.flush();
+ channel.write(headerAndData);
+ channel.force(true);
} catch (IOException e) {
Slog.e(TAG, "failed writing to the persistent data block", e);
return -1;
- } finally {
- IoUtils.closeQuietly(outputStream);
}
if (computeAndWriteDigestLocked()) {
@@ -565,17 +545,6 @@
public void wipe() {
enforceOemUnlockWritePermission();
- if (mIsRunningDSU) {
- File sandbox = new File(GSI_SANDBOX);
- if (sandbox.exists()) {
- if (sandbox.delete()) {
- mDataBlockFile = SystemProperties.get(PERSISTENT_DATA_BLOCK_PROP);
- } else {
- Slog.e(TAG, "Failed to wipe sandbox persistent data block");
- }
- }
- return;
- }
synchronized (mLock) {
int ret = nativeWipe(mDataBlockFile);
@@ -733,28 +702,18 @@
}
private void writeDataBuffer(long offset, ByteBuffer dataBuffer) {
- FileOutputStream outputStream;
- try {
- outputStream = getBlockOutputStream();
- } catch (IOException e) {
- Slog.e(TAG, "partition not available", e);
- return;
- }
synchronized (mLock) {
if (!mIsWritable) {
- IoUtils.closeQuietly(outputStream);
return;
}
try {
- FileChannel channel = outputStream.getChannel();
+ FileChannel channel = getBlockOutputChannel();
channel.position(offset);
channel.write(dataBuffer);
- outputStream.flush();
+ channel.force(true);
} catch (IOException e) {
Slog.e(TAG, "unable to access persistent partition", e);
return;
- } finally {
- IoUtils.closeQuietly(outputStream);
}
computeAndWriteDigestLocked();
diff --git a/services/core/java/com/android/server/PinnerService.java b/services/core/java/com/android/server/PinnerService.java
index 3148a62..1241b77 100644
--- a/services/core/java/com/android/server/PinnerService.java
+++ b/services/core/java/com/android/server/PinnerService.java
@@ -270,18 +270,9 @@
* 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 @@
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 a95589b..0affda4 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -402,10 +402,15 @@
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 @@
}
@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 @@
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 4622e98..f7ae58c 100644
--- a/services/core/java/com/android/server/VcnManagementService.java
+++ b/services/core/java/com/android/server/VcnManagementService.java
@@ -16,6 +16,8 @@
package com.android.server;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
+import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE;
import static android.net.vcn.VcnManager.VCN_STATUS_CODE_INACTIVE;
import static android.net.vcn.VcnManager.VCN_STATUS_CODE_NOT_CONFIGURED;
@@ -35,13 +37,13 @@
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.LinkProperties;
+import android.net.Network;
import android.net.NetworkCapabilities;
-import android.net.TelephonyNetworkSpecifier;
+import android.net.NetworkRequest;
import android.net.vcn.IVcnManagementService;
import android.net.vcn.IVcnStatusCallback;
import android.net.vcn.IVcnUnderlyingNetworkPolicyListener;
import android.net.vcn.VcnConfig;
-import android.net.vcn.VcnManager;
import android.net.vcn.VcnManager.VcnErrorCode;
import android.net.vcn.VcnManager.VcnStatusCode;
import android.net.vcn.VcnUnderlyingNetworkPolicy;
@@ -163,6 +165,9 @@
@NonNull private final VcnContext mVcnContext;
@NonNull private final BroadcastReceiver mPkgChangeReceiver;
+ @NonNull
+ private final TrackingNetworkCallback mTrackingNetworkCallback = new TrackingNetworkCallback();
+
/** Can only be assigned when {@link #systemReady()} is called, since it uses AppOpsManager. */
@Nullable private LocationPermissionChecker mLocationPermissionChecker;
@@ -359,6 +364,10 @@
public void systemReady() {
mContext.getSystemService(ConnectivityManager.class)
.registerNetworkProvider(mNetworkProvider);
+ mContext.getSystemService(ConnectivityManager.class)
+ .registerNetworkCallback(
+ new NetworkRequest.Builder().clearCapabilities().build(),
+ mTrackingNetworkCallback);
mTelephonySubscriptionTracker.register();
mLocationPermissionChecker = mDeps.newLocationPermissionChecker(mVcnContext.getContext());
}
@@ -533,15 +542,7 @@
if (mVcns.containsKey(subscriptionGroup)) {
final Vcn vcn = mVcns.get(subscriptionGroup);
- final boolean isActive = vcn.isActive();
vcn.updateConfig(config);
-
- // Only notify VcnStatusCallbacks if this VCN was previously in Safe Mode
- if (!isActive) {
- // TODO(b/181789060): invoke asynchronously after Vcn notifies through VcnCallback
- notifyAllPermissionedStatusCallbacksLocked(
- subscriptionGroup, VCN_STATUS_CODE_ACTIVE);
- }
} else {
startVcnLocked(subscriptionGroup, config);
}
@@ -717,19 +718,29 @@
});
}
- 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;
}
- return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+ // 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 subGrp;
}
/**
@@ -754,23 +765,19 @@
// 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);
+ synchronized (mLock) {
+ final Vcn vcn = mVcns.get(subGrp);
+ if (vcn != null) {
+ if (vcn.getStatus() == VCN_STATUS_CODE_ACTIVE) {
+ isVcnManagedNetwork = true;
+ }
- final Vcn vcn = mVcns.get(subGroup);
- 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;
}
}
}
@@ -787,8 +794,9 @@
NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
}
+ final NetworkCapabilities result = ncBuilder.build();
return new VcnUnderlyingNetworkPolicy(
- false /* isTearDownRequested */, ncBuilder.build());
+ mTrackingNetworkCallback.requiresRestartForCarrierWifi(result), result);
});
}
@@ -875,20 +883,23 @@
// now that callback is registered, send it the VCN's current status
final VcnConfig vcnConfig = mConfigs.get(subGroup);
final Vcn vcn = mVcns.get(subGroup);
- final int vcnStatus;
+ final int vcnStatus =
+ vcn == null ? VCN_STATUS_CODE_NOT_CONFIGURED : vcn.getStatus();
+ final int resultStatus;
if (vcnConfig == null || !isCallbackPermissioned(cbInfo, subGroup)) {
- vcnStatus = VcnManager.VCN_STATUS_CODE_NOT_CONFIGURED;
+ resultStatus = VCN_STATUS_CODE_NOT_CONFIGURED;
} else if (vcn == null) {
- vcnStatus = VcnManager.VCN_STATUS_CODE_INACTIVE;
- } else if (vcn.isActive()) {
- vcnStatus = VcnManager.VCN_STATUS_CODE_ACTIVE;
+ resultStatus = VCN_STATUS_CODE_INACTIVE;
+ } else if (vcnStatus == VCN_STATUS_CODE_ACTIVE
+ || vcnStatus == VCN_STATUS_CODE_SAFE_MODE) {
+ resultStatus = vcnStatus;
} else {
- // TODO(b/181789060): create Vcn.getStatus() and Log.WTF() for unknown status
- vcnStatus = VcnManager.VCN_STATUS_CODE_SAFE_MODE;
+ Slog.wtf(TAG, "Unknown VCN status: " + vcnStatus);
+ resultStatus = VCN_STATUS_CODE_NOT_CONFIGURED;
}
try {
- cbInfo.mCallback.onVcnStatusChanged(vcnStatus);
+ cbInfo.mCallback.onVcnStatusChanged(resultStatus);
} catch (RemoteException e) {
Slog.d(TAG, "VcnStatusCallback threw on VCN status change", e);
}
@@ -921,17 +932,60 @@
// TODO(b/180452282): Make name more generic and implement directly with VcnManagementService
/** Callback for Vcn signals sent up to VcnManagementService. */
public interface VcnCallback {
- /** Called by a Vcn to signal that it has entered safe mode. */
- void onEnteredSafeMode();
+ /** Called by a Vcn to signal that its safe mode status has changed. */
+ void onSafeModeStatusChanged(boolean isInSafeMode);
/** Called by a Vcn to signal that an error occurred. */
void onGatewayConnectionError(
- @NonNull int[] networkCapabilities,
+ @NonNull String gatewayConnectionName,
@VcnErrorCode int errorCode,
@Nullable String exceptionClass,
@Nullable String exceptionMessage);
}
+ /**
+ * TrackingNetworkCallback tracks all active networks
+ *
+ * <p>This is used to ensure that no underlying networks have immutable capabilities changed
+ * without requiring a Network restart.
+ */
+ private class TrackingNetworkCallback extends ConnectivityManager.NetworkCallback {
+ private final Map<Network, NetworkCapabilities> mCaps = new ArrayMap<>();
+
+ @Override
+ public void onCapabilitiesChanged(Network network, NetworkCapabilities caps) {
+ synchronized (mCaps) {
+ mCaps.put(network, caps);
+ }
+ }
+
+ @Override
+ public void onLost(Network network) {
+ synchronized (mCaps) {
+ mCaps.remove(network);
+ }
+ }
+
+ private boolean requiresRestartForCarrierWifi(NetworkCapabilities caps) {
+ if (!caps.hasTransport(TRANSPORT_WIFI) || caps.getSubIds() == null) {
+ return false;
+ }
+
+ synchronized (mCaps) {
+ for (NetworkCapabilities existing : mCaps.values()) {
+ if (existing.hasTransport(TRANSPORT_WIFI)
+ && caps.getSubIds().equals(existing.getSubIds())) {
+ // Restart if any immutable capabilities have changed
+ return existing.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)
+ != caps.hasCapability(NET_CAPABILITY_NOT_RESTRICTED);
+ }
+ }
+ }
+
+ return false;
+ }
+ }
+
/** VcnCallbackImpl for Vcn signals sent up to VcnManagementService. */
private class VcnCallbackImpl implements VcnCallback {
@NonNull private final ParcelUuid mSubGroup;
@@ -941,21 +995,24 @@
}
@Override
- public void onEnteredSafeMode() {
+ public void onSafeModeStatusChanged(boolean isInSafeMode) {
synchronized (mLock) {
// Ignore if this subscription group doesn't exist anymore
if (!mVcns.containsKey(mSubGroup)) {
return;
}
+ final int status =
+ isInSafeMode ? VCN_STATUS_CODE_SAFE_MODE : VCN_STATUS_CODE_ACTIVE;
+
notifyAllPolicyListenersLocked();
- notifyAllPermissionedStatusCallbacksLocked(mSubGroup, VCN_STATUS_CODE_SAFE_MODE);
+ notifyAllPermissionedStatusCallbacksLocked(mSubGroup, status);
}
}
@Override
public void onGatewayConnectionError(
- @NonNull int[] networkCapabilities,
+ @NonNull String gatewayConnectionName,
@VcnErrorCode int errorCode,
@Nullable String exceptionClass,
@Nullable String exceptionMessage) {
@@ -971,7 +1028,7 @@
Binder.withCleanCallingIdentity(
() ->
cbInfo.mCallback.onGatewayConnectionError(
- networkCapabilities,
+ gatewayConnectionName,
errorCode,
exceptionClass,
exceptionMessage));
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index cc5a25a..2744f11 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -236,6 +236,7 @@
import android.hardware.display.DisplayManagerInternal;
import android.location.LocationManager;
import android.media.audiofx.AudioEffect;
+import android.net.ConnectivityManager;
import android.net.Proxy;
import android.net.Uri;
import android.os.AppZygote;
@@ -16458,7 +16459,7 @@
stats.noteCurrentTimeChangedLocked();
}
break;
- case Intent.ACTION_CLEAR_DNS_CACHE:
+ case ConnectivityManager.ACTION_CLEAR_DNS_CACHE:
mHandler.sendEmptyMessage(CLEAR_DNS_CACHE_MSG);
break;
case Proxy.PROXY_CHANGE_ACTION:
diff --git a/services/core/java/com/android/server/clipboard/ClipboardService.java b/services/core/java/com/android/server/clipboard/ClipboardService.java
index d4eb104..72160c2 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.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.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 @@
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,37 +100,66 @@
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 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[] 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) {
mHostClipboardCallback = cb;
}
@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
@@ -131,25 +167,23 @@
while ((mPipe == null) && !openPipe()) {
Thread.sleep(100);
}
- int size = mPipe.readInt();
- size = Integer.reverseBytes(size);
- byte[] receivedData = new byte[size];
- mPipe.readFully(receivedData);
+
+ final byte[] receivedData = receiveMessage();
mHostClipboardCallback.onHostClipboardUpdated(
new String(receivedData));
- } catch (IOException e) {
+ } catch (ErrnoException | InterruptedIOException e) {
closePipe();
- } catch (InterruptedException e) {}
+ } catch (InterruptedException e) {
+ }
}
}
public void setHostClipboard(String content) {
try {
if (mPipe != null) {
- mPipe.writeInt(Integer.reverseBytes(content.getBytes().length));
- mPipe.write(content.getBytes());
+ sendMessage(content.getBytes());
}
- } catch(IOException e) {
+ } catch (ErrnoException | InterruptedIOException e) {
Slog.e("HostClipboardMonitor",
"Failed to set host clipboard " + e.getMessage());
}
diff --git a/services/core/java/com/android/server/connectivity/DnsManager.java b/services/core/java/com/android/server/connectivity/DnsManager.java
index ffeb77d..cf4fe1e 100644
--- a/services/core/java/com/android/server/connectivity/DnsManager.java
+++ b/services/core/java/com/android/server/connectivity/DnsManager.java
@@ -420,7 +420,7 @@
/*
* Tell the VMs to toss their DNS caches
*/
- final Intent intent = new Intent(Intent.ACTION_CLEAR_DNS_CACHE);
+ final Intent intent = new Intent(ConnectivityManager.ACTION_CLEAR_DNS_CACHE);
intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
/*
* Connectivity events can happen before boot has completed ...
diff --git a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
index 7b20ded..058dac8 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_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 @@
}
} 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 f3d2012..6ea84ce 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 @@
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 @@
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 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 @@
}
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 @@
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 4963353..ee32fbf 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 @@
// 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 @@
}
}
+ /**
+ * 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 @@
@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/NetworkDiagnostics.java b/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java
index 5e6b9f3..2e51be3 100644
--- a/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java
+++ b/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java
@@ -36,7 +36,7 @@
import android.util.Pair;
import com.android.internal.util.IndentingPrintWriter;
-import com.android.internal.util.TrafficStatsConstants;
+import com.android.net.module.util.NetworkStackConstants;
import libcore.io.IoUtils;
@@ -446,7 +446,7 @@
int sockType, int protocol, long writeTimeout, long readTimeout, int dstPort)
throws ErrnoException, IOException {
final int oldTag = TrafficStats.getAndSetThreadStatsTag(
- TrafficStatsConstants.TAG_SYSTEM_PROBE);
+ NetworkStackConstants.TAG_SYSTEM_PROBE);
try {
mFileDescriptor = Os.socket(mAddressFamily, sockType, protocol);
} finally {
@@ -745,7 +745,7 @@
if (ensureMeasurementNecessary()) return;
// No need to restore the tag, since this thread is only used for this measurement.
- TrafficStats.getAndSetThreadStatsTag(TrafficStatsConstants.TAG_SYSTEM_PROBE);
+ TrafficStats.getAndSetThreadStatsTag(NetworkStackConstants.TAG_SYSTEM_PROBE);
try (SSLSocket sslSocket = setupSSLSocket()) {
sendDoTProbe(sslSocket);
diff --git a/services/core/java/com/android/server/connectivity/PermissionMonitor.java b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
index 488677a..3711679 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 @@
return mApps.containsKey(uid);
}
+ /**
+ * Returns whether the given uid has permission to use restricted networks.
+ */
+ public synchronized boolean hasRestrictedNetworksPermission(int uid) {
+ return Boolean.TRUE.equals(mApps.get(uid));
+ }
+
private void update(Set<UserHandle> users, Map<Integer, Boolean> apps, boolean add) {
List<Integer> network = new ArrayList<>();
List<Integer> system = new ArrayList<>();
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index e5ce4f0..0a76bdc 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -101,7 +101,6 @@
import android.provider.Settings;
import android.security.Credentials;
import android.security.KeyStore2;
-import android.security.keystore.AndroidKeyStoreProvider;
import android.security.keystore.KeyProperties;
import android.system.keystore2.Domain;
import android.system.keystore2.KeyDescriptor;
@@ -463,7 +462,7 @@
.addTransportType(NetworkCapabilities.TRANSPORT_VPN)
.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED)
- .setTransportInfo(new VpnTransportInfo(VpnManager.TYPE_VPN_NONE))
+ .setTransportInfo(new VpnTransportInfo(VpnManager.TYPE_VPN_NONE, null))
.build();
loadAlwaysOnPackage();
@@ -527,7 +526,7 @@
private void resetNetworkCapabilities() {
mNetworkCapabilities = new NetworkCapabilities.Builder(mNetworkCapabilities)
.setUids(null)
- .setTransportInfo(new VpnTransportInfo(VpnManager.TYPE_VPN_NONE))
+ .setTransportInfo(new VpnTransportInfo(VpnManager.TYPE_VPN_NONE, null))
.build();
}
@@ -1257,7 +1256,7 @@
capsBuilder.setUids(createUserAndRestrictedProfilesRanges(mUserId,
mConfig.allowedApplications, mConfig.disallowedApplications));
- capsBuilder.setTransportInfo(new VpnTransportInfo(getActiveVpnType()));
+ capsBuilder.setTransportInfo(new VpnTransportInfo(getActiveVpnType(), mConfig.session));
// Only apps targeting Q and above can explicitly declare themselves as metered.
// These VPNs are assumed metered unless they state otherwise.
@@ -2055,10 +2054,6 @@
if (alias == null) {
return null;
}
- // If Keystore 2.0 is not enabled the legacy private key prefix is used.
- if (!AndroidKeyStoreProvider.isKeystore2Enabled()) {
- return Credentials.USER_PRIVATE_KEY + alias;
- }
final KeyStore2 keystore2 = KeyStore2.getInstance();
KeyDescriptor key = new KeyDescriptor();
diff --git a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
index 6f12155..6a407e9 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 @@
}
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/HdmiCecLocalDeviceSource.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java
index 470a25b..3d1a49e 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceSource.java
@@ -201,7 +201,6 @@
// Only source devices that react to routing control messages should implement
// this method (e.g. a TV with built in switch).
- // TODO(): decide which type will handle the routing when multi device type is supported
protected void handleRoutingChangeAndInformation(int physicalAddress, HdmiCecMessage message) {
// do nothing
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index 58a7025..8bb5204 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -800,7 +800,9 @@
assertRunOnServiceThread();
if (!mService.isPowerStandbyOrTransient()) {
addAndStartAction(new SystemAudioAutoInitiationAction(this, avr.getLogicalAddress()));
- if (isConnected(avr.getPortId()) && isArcFeatureEnabled(avr.getPortId())
+ if (!isDirectConnectAddress(avr.getPhysicalAddress())) {
+ startArcAction(false);
+ } else if (isConnected(avr.getPortId()) && isArcFeatureEnabled(avr.getPortId())
&& !hasAction(SetArcTransmissionStateAction.class)) {
startArcAction(true);
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlShellCommand.java b/services/core/java/com/android/server/hdmi/HdmiControlShellCommand.java
index ee3427f..740407c 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 @@
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 @@
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 @@
return oneTouchPlay(pw);
case "vendorcommand":
return vendorCommand(pw);
+ case "setsystemaudiomode":
+ case "setsam":
+ return setSystemAudioMode(pw);
}
getErrPrintWriter().println("Unhandled command: " + cmd);
@@ -88,28 +107,14 @@
}
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 @@
mBinderService.sendVendorCommand(deviceType, destination, params, hasVendorId);
return 0;
}
+
+ private int setSystemAudioMode(PrintWriter pw) throws RemoteException {
+ if (1 > getRemainingArgsCount()) {
+ throw new IllegalArgumentException(
+ "Please indicate if System Audio Mode should be turned \"on\" or \"off\".");
+ }
+
+ String arg = getNextArg();
+ if (arg.equals("on")) {
+ pw.println("Setting System Audio Mode on");
+ mBinderService.setSystemAudioMode(true, mHdmiControlCallback);
+ } else if (arg.equals("off")) {
+ pw.println("Setting System Audio Mode off");
+ mBinderService.setSystemAudioMode(false, mHdmiControlCallback);
+ } else {
+ throw new IllegalArgumentException(
+ "Please indicate if System Audio Mode should be turned \"on\" or \"off\".");
+ }
+
+ if (!receiveCallback("Set System Audio Mode")) {
+ return 1;
+ }
+
+ return mCecResult.get() == HdmiControlManager.RESULT_SUCCESS ? 0 : 1;
+ }
+
+ private boolean receiveCallback(String command) {
+ try {
+ if (!mLatch.await(HdmiConfig.TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
+ getErrPrintWriter().println(command + " timed out.");
+ return false;
+ }
+ } catch (InterruptedException e) {
+ getErrPrintWriter().println("Caught InterruptedException");
+ Thread.currentThread().interrupt();
+ }
+ return true;
+ }
+
+ private String getResultString(int result) {
+ switch (result) {
+ case HdmiControlManager.RESULT_SUCCESS:
+ return "Success";
+ case HdmiControlManager.RESULT_TIMEOUT:
+ return "Timeout";
+ case HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE:
+ return "Source not available";
+ case HdmiControlManager.RESULT_TARGET_NOT_AVAILABLE:
+ return "Target not available";
+ case HdmiControlManager.RESULT_EXCEPTION:
+ return "Exception";
+ case HdmiControlManager.RESULT_INCORRECT_MODE:
+ return "Incorrect mode";
+ case HdmiControlManager.RESULT_COMMUNICATION_FAILED:
+ return "Communication Failed";
+ }
+ return Integer.toString(result);
+ }
}
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 0215188..f96fa09 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -99,6 +99,7 @@
import android.security.keystore.recovery.KeyChainSnapshot;
import android.security.keystore.recovery.RecoveryCertPath;
import android.security.keystore.recovery.WrappedApplicationKey;
+import android.security.keystore2.AndroidKeyStoreProvider;
import android.service.gatekeeper.GateKeeperResponse;
import android.service.gatekeeper.IGateKeeperService;
import android.text.TextUtils;
@@ -262,7 +263,7 @@
@Override
public void onStart() {
- android.security.keystore2.AndroidKeyStoreProvider.install();
+ AndroidKeyStoreProvider.install();
mLockSettingsService = new LockSettingsService(getContext());
publishBinderService("lock_settings", mLockSettingsService);
}
@@ -796,10 +797,6 @@
// Notify keystore that a new user was added.
final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
AndroidKeyStoreMaintenance.onUserAdded(userHandle);
- final KeyStore ks = KeyStore.getInstance();
- final UserInfo parentInfo = mUserManager.getProfileParent(userHandle);
- final int parentHandle = parentInfo != null ? parentInfo.id : -1;
- ks.onUserAdded(userHandle, parentHandle);
} else if (Intent.ACTION_USER_STARTING.equals(intent.getAction())) {
final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
mStorage.prefetchUser(userHandle);
@@ -1264,19 +1261,11 @@
private void setKeystorePassword(byte[] password, int userHandle) {
AndroidKeyStoreMaintenance.onUserPasswordChanged(userHandle, password);
- final KeyStore ks = KeyStore.getInstance();
- // TODO(b/120484642): Update keystore to accept byte[] passwords
- String passwordString = password == null ? null : new String(password);
- ks.onUserPasswordChanged(userHandle, passwordString);
}
private void unlockKeystore(byte[] password, int userHandle) {
if (DEBUG) Slog.v(TAG, "Unlock keystore for user: " + userHandle);
Authorization.onLockScreenEvent(false, userHandle, password);
- // TODO(b/120484642): Update keystore to accept byte[] passwords
- String passwordString = password == null ? null : new String(password);
- final KeyStore ks = KeyStore.getInstance();
- ks.unlock(userHandle, passwordString);
}
@VisibleForTesting /** Note: this method is overridden in unit tests */
@@ -2296,8 +2285,6 @@
mStrongAuth.removeUser(userId);
AndroidKeyStoreMaintenance.onUserRemoved(userId);
- final KeyStore ks = KeyStore.getInstance();
- ks.onUserRemoved(userId);
mManagedProfilePasswordCache.removePassword(userId);
gateKeeperClearSecureUserId(userId);
diff --git a/services/core/java/com/android/server/locksettings/ManagedProfilePasswordCache.java b/services/core/java/com/android/server/locksettings/ManagedProfilePasswordCache.java
index 7950fcf..fa477c8 100644
--- a/services/core/java/com/android/server/locksettings/ManagedProfilePasswordCache.java
+++ b/services/core/java/com/android/server/locksettings/ManagedProfilePasswordCache.java
@@ -20,10 +20,10 @@
import android.content.pm.UserInfo;
import android.os.UserHandle;
import android.os.UserManager;
-import android.security.keystore.AndroidKeyStoreSpi;
import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyProperties;
import android.security.keystore.UserNotAuthenticatedException;
+import android.security.keystore2.AndroidKeyStoreSpi;
import android.util.Slog;
import android.util.SparseArray;
diff --git a/services/core/java/com/android/server/locksettings/RebootEscrowKeyStoreManager.java b/services/core/java/com/android/server/locksettings/RebootEscrowKeyStoreManager.java
index bae029c..da29368 100644
--- a/services/core/java/com/android/server/locksettings/RebootEscrowKeyStoreManager.java
+++ b/services/core/java/com/android/server/locksettings/RebootEscrowKeyStoreManager.java
@@ -16,11 +16,10 @@
package com.android.server.locksettings;
-import android.security.keystore.AndroidKeyStoreSpi;
import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyProperties;
import android.security.keystore2.AndroidKeyStoreLoadStoreParameter;
-import android.security.keystore2.AndroidKeyStoreProvider;
+import android.security.keystore2.AndroidKeyStoreSpi;
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
@@ -67,9 +66,7 @@
KeyStore keyStore = KeyStore.getInstance(ANDROID_KEY_STORE_PROVIDER);
KeyStore.LoadStoreParameter loadStoreParameter = null;
// Load from the specific namespace if keystore2 is enabled.
- if (AndroidKeyStoreProvider.isInstalled()) {
- loadStoreParameter = new AndroidKeyStoreLoadStoreParameter(KEY_STORE_NAMESPACE);
- }
+ loadStoreParameter = new AndroidKeyStoreLoadStoreParameter(KEY_STORE_NAMESPACE);
keyStore.load(loadStoreParameter);
return (SecretKey) keyStore.getKey(REBOOT_ESCROW_KEY_STORE_ENCRYPTION_KEY_NAME,
null);
@@ -91,9 +88,7 @@
KeyStore keyStore = KeyStore.getInstance(ANDROID_KEY_STORE_PROVIDER);
KeyStore.LoadStoreParameter loadStoreParameter = null;
// Load from the specific namespace if keystore2 is enabled.
- if (AndroidKeyStoreProvider.isInstalled()) {
- loadStoreParameter = new AndroidKeyStoreLoadStoreParameter(KEY_STORE_NAMESPACE);
- }
+ loadStoreParameter = new AndroidKeyStoreLoadStoreParameter(KEY_STORE_NAMESPACE);
keyStore.load(loadStoreParameter);
keyStore.deleteEntry(REBOOT_ESCROW_KEY_STORE_ENCRYPTION_KEY_NAME);
} catch (IOException | GeneralSecurityException e) {
@@ -119,9 +114,7 @@
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE);
// Generate the key with the correct namespace if keystore2 is enabled.
- if (AndroidKeyStoreProvider.isInstalled()) {
- parameterSpecBuilder.setNamespace(KEY_STORE_NAMESPACE);
- }
+ parameterSpecBuilder.setNamespace(KEY_STORE_NAMESPACE);
generator.init(parameterSpecBuilder.build());
return generator.generateKey();
} catch (GeneralSecurityException e) {
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/ApplicationKeyStorage.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/ApplicationKeyStorage.java
index 2398f56..8582c67 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/ApplicationKeyStorage.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/ApplicationKeyStorage.java
@@ -20,8 +20,6 @@
import android.annotation.Nullable;
import android.os.ServiceSpecificException;
-import android.security.Credentials;
-import android.security.KeyStore;
import android.security.KeyStore2;
import android.security.keystore.KeyProperties;
import android.security.keystore.KeyProtection;
@@ -75,13 +73,7 @@
public @Nullable String getGrantAlias(int userId, int uid, String alias) {
Log.i(TAG, String.format(Locale.US, "Get %d/%d/%s", userId, uid, alias));
String keystoreAlias = getInternalAlias(userId, uid, alias);
- if (useKeyStore2()) {
- return makeKeystoreEngineGrantString(uid, keystoreAlias);
- } else {
- // Aliases used by {@link KeyStore} are different than used by public API.
- // {@code USER_PRIVATE_KEY} prefix is used secret keys.
- return KeyStore.getInstance().grant(Credentials.USER_PRIVATE_KEY + keystoreAlias, uid);
- }
+ return makeKeystoreEngineGrantString(uid, keystoreAlias);
}
public void setSymmetricKeyEntry(int userId, int uid, String alias, byte[] secretKey)
@@ -148,9 +140,4 @@
}
return String.format("%s%016X", APPLICATION_KEY_GRANT_PREFIX, key.nspace);
}
-
- private static boolean useKeyStore2() {
- return android.security.keystore2.AndroidKeyStoreProvider.isInstalled();
- }
-
}
diff --git a/services/core/java/com/android/server/net/IpConfigStore.java b/services/core/java/com/android/server/net/IpConfigStore.java
index cc3a002..df1eb6d 100644
--- a/services/core/java/com/android/server/net/IpConfigStore.java
+++ b/services/core/java/com/android/server/net/IpConfigStore.java
@@ -22,7 +22,6 @@
import android.net.IpConfiguration.ProxySettings;
import android.net.LinkAddress;
import android.net.ProxyInfo;
-import android.net.RouteInfo;
import android.net.StaticIpConfiguration;
import android.net.Uri;
import android.util.ArrayMap;
@@ -42,6 +41,8 @@
import java.io.InputStream;
import java.net.Inet4Address;
import java.net.InetAddress;
+import java.util.ArrayList;
+import java.util.List;
public class IpConfigStore {
private static final String TAG = "IpConfigStore";
@@ -83,25 +84,25 @@
boolean written = false;
try {
- switch (config.ipAssignment) {
+ switch (config.getIpAssignment()) {
case STATIC:
out.writeUTF(IP_ASSIGNMENT_KEY);
- out.writeUTF(config.ipAssignment.toString());
- StaticIpConfiguration staticIpConfiguration = config.staticIpConfiguration;
+ out.writeUTF(config.getIpAssignment().toString());
+ StaticIpConfiguration staticIpConfiguration = config.getStaticIpConfiguration();
if (staticIpConfiguration != null) {
- if (staticIpConfiguration.ipAddress != null) {
- LinkAddress ipAddress = staticIpConfiguration.ipAddress;
+ if (staticIpConfiguration.getIpAddress() != null) {
+ LinkAddress ipAddress = staticIpConfiguration.getIpAddress();
out.writeUTF(LINK_ADDRESS_KEY);
out.writeUTF(ipAddress.getAddress().getHostAddress());
out.writeInt(ipAddress.getPrefixLength());
}
- if (staticIpConfiguration.gateway != null) {
+ if (staticIpConfiguration.getGateway() != null) {
out.writeUTF(GATEWAY_KEY);
out.writeInt(0); // Default route.
out.writeInt(1); // Have a gateway.
- out.writeUTF(staticIpConfiguration.gateway.getHostAddress());
+ out.writeUTF(staticIpConfiguration.getGateway().getHostAddress());
}
- for (InetAddress inetAddr : staticIpConfiguration.dnsServers) {
+ for (InetAddress inetAddr : staticIpConfiguration.getDnsServers()) {
out.writeUTF(DNS_KEY);
out.writeUTF(inetAddr.getHostAddress());
}
@@ -110,7 +111,7 @@
break;
case DHCP:
out.writeUTF(IP_ASSIGNMENT_KEY);
- out.writeUTF(config.ipAssignment.toString());
+ out.writeUTF(config.getIpAssignment().toString());
written = true;
break;
case UNASSIGNED:
@@ -121,13 +122,13 @@
break;
}
- switch (config.proxySettings) {
+ switch (config.getProxySettings()) {
case STATIC:
- ProxyInfo proxyProperties = config.httpProxy;
+ ProxyInfo proxyProperties = config.getHttpProxy();
String exclusionList = ProxyUtils.exclusionListAsString(
proxyProperties.getExclusionList());
out.writeUTF(PROXY_SETTINGS_KEY);
- out.writeUTF(config.proxySettings.toString());
+ out.writeUTF(config.getProxySettings().toString());
out.writeUTF(PROXY_HOST_KEY);
out.writeUTF(proxyProperties.getHost());
out.writeUTF(PROXY_PORT_KEY);
@@ -139,16 +140,16 @@
written = true;
break;
case PAC:
- ProxyInfo proxyPacProperties = config.httpProxy;
+ ProxyInfo proxyPacProperties = config.getHttpProxy();
out.writeUTF(PROXY_SETTINGS_KEY);
- out.writeUTF(config.proxySettings.toString());
+ out.writeUTF(config.getProxySettings().toString());
out.writeUTF(PROXY_PAC_FILE);
out.writeUTF(proxyPacProperties.getPacFileUrl().toString());
written = true;
break;
case NONE:
out.writeUTF(PROXY_SETTINGS_KEY);
- out.writeUTF(config.proxySettings.toString());
+ out.writeUTF(config.getProxySettings().toString());
written = true;
break;
case UNASSIGNED:
@@ -267,11 +268,14 @@
IpAssignment ipAssignment = IpAssignment.DHCP;
ProxySettings proxySettings = ProxySettings.NONE;
StaticIpConfiguration staticIpConfiguration = new StaticIpConfiguration();
+ LinkAddress linkAddress = null;
+ InetAddress gatewayAddress = null;
String proxyHost = null;
String pacFileUrl = null;
int proxyPort = -1;
String exclusionList = null;
String key;
+ final List<InetAddress> dnsServers = new ArrayList<>();
do {
key = in.readUTF();
@@ -286,15 +290,15 @@
} else if (key.equals(IP_ASSIGNMENT_KEY)) {
ipAssignment = IpAssignment.valueOf(in.readUTF());
} else if (key.equals(LINK_ADDRESS_KEY)) {
- LinkAddress linkAddr =
+ LinkAddress parsedLinkAddress =
new LinkAddress(
InetAddresses.parseNumericAddress(in.readUTF()),
in.readInt());
- if (linkAddr.getAddress() instanceof Inet4Address &&
- staticIpConfiguration.ipAddress == null) {
- staticIpConfiguration.ipAddress = linkAddr;
+ if (parsedLinkAddress.getAddress() instanceof Inet4Address
+ && linkAddress == null) {
+ linkAddress = parsedLinkAddress;
} else {
- loge("Non-IPv4 or duplicate address: " + linkAddr);
+ loge("Non-IPv4 or duplicate address: " + parsedLinkAddress);
}
} else if (key.equals(GATEWAY_KEY)) {
LinkAddress dest = null;
@@ -302,8 +306,8 @@
if (version == 1) {
// only supported default gateways - leave the dest/prefix empty
gateway = InetAddresses.parseNumericAddress(in.readUTF());
- if (staticIpConfiguration.gateway == null) {
- staticIpConfiguration.gateway = gateway;
+ if (gatewayAddress == null) {
+ gatewayAddress = gateway;
} else {
loge("Duplicate gateway: " + gateway.getHostAddress());
}
@@ -317,17 +321,18 @@
if (in.readInt() == 1) {
gateway = InetAddresses.parseNumericAddress(in.readUTF());
}
- RouteInfo route = new RouteInfo(dest, gateway);
- if (route.isIPv4Default() &&
- staticIpConfiguration.gateway == null) {
- staticIpConfiguration.gateway = gateway;
+ // If the destination is a default IPv4 route, use the gateway
+ // address unless already set.
+ if (dest.getAddress() instanceof Inet4Address
+ && dest.getPrefixLength() == 0 && gatewayAddress == null) {
+ gatewayAddress = gateway;
} else {
- loge("Non-IPv4 default or duplicate route: " + route);
+ loge("Non-IPv4 default or duplicate route: "
+ + dest.getAddress());
}
}
} else if (key.equals(DNS_KEY)) {
- staticIpConfiguration.dnsServers.add(
- InetAddresses.parseNumericAddress(in.readUTF()));
+ dnsServers.add(InetAddresses.parseNumericAddress(in.readUTF()));
} else if (key.equals(PROXY_SETTINGS_KEY)) {
proxySettings = ProxySettings.valueOf(in.readUTF());
} else if (key.equals(PROXY_HOST_KEY)) {
@@ -348,25 +353,31 @@
}
} while (true);
+ staticIpConfiguration = new StaticIpConfiguration.Builder()
+ .setIpAddress(linkAddress)
+ .setGateway(gatewayAddress)
+ .setDnsServers(dnsServers)
+ .build();
+
if (uniqueToken != null) {
IpConfiguration config = new IpConfiguration();
networks.put(uniqueToken, config);
switch (ipAssignment) {
case STATIC:
- config.staticIpConfiguration = staticIpConfiguration;
- config.ipAssignment = ipAssignment;
+ config.setStaticIpConfiguration(staticIpConfiguration);
+ config.setIpAssignment(ipAssignment);
break;
case DHCP:
- config.ipAssignment = ipAssignment;
+ config.setIpAssignment(ipAssignment);
break;
case UNASSIGNED:
loge("BUG: Found UNASSIGNED IP on file, use DHCP");
- config.ipAssignment = IpAssignment.DHCP;
+ config.setIpAssignment(IpAssignment.DHCP);
break;
default:
loge("Ignore invalid ip assignment while reading.");
- config.ipAssignment = IpAssignment.UNASSIGNED;
+ config.setIpAssignment(IpAssignment.UNASSIGNED);
break;
}
@@ -374,25 +385,25 @@
case STATIC:
ProxyInfo proxyInfo = ProxyInfo.buildDirectProxy(proxyHost, proxyPort,
ProxyUtils.exclusionStringAsList(exclusionList));
- config.proxySettings = proxySettings;
- config.httpProxy = proxyInfo;
+ config.setProxySettings(proxySettings);
+ config.setHttpProxy(proxyInfo);
break;
case PAC:
ProxyInfo proxyPacProperties =
ProxyInfo.buildPacProxy(Uri.parse(pacFileUrl));
- config.proxySettings = proxySettings;
- config.httpProxy = proxyPacProperties;
+ config.setProxySettings(proxySettings);
+ config.setHttpProxy(proxyPacProperties);
break;
case NONE:
- config.proxySettings = proxySettings;
+ config.setProxySettings(proxySettings);
break;
case UNASSIGNED:
loge("BUG: Found UNASSIGNED proxy on file, use NONE");
- config.proxySettings = ProxySettings.NONE;
+ config.setProxySettings(ProxySettings.NONE);
break;
default:
loge("Ignore invalid proxy settings while reading");
- config.proxySettings = ProxySettings.UNASSIGNED;
+ config.setProxySettings(ProxySettings.UNASSIGNED);
break;
}
} else {
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java b/services/core/java/com/android/server/net/NetworkPolicyManagerInternal.java
index 39ed7e8..2e4d41c 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 @@
/**
* 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 f16496c..319800d 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.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_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 @@
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 @@
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);
+ 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 (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;
+ // 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 @@
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 @@
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 @@
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 @@
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 @@
}
}
- 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 setInterfaceQuota(String iface, long quotaBytes) {
+ private void setInterfaceQuotasAsync(@NonNull String iface,
+ long warningBytes, long limitBytes) {
+ mHandler.obtainMessage(MSG_UPDATE_INTERFACE_QUOTAS,
+ new IfaceQuotas(iface, warningBytes, limitBytes)).sendToTarget();
+ }
+
+ 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 @@
}
}
- 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) {
@@ -5557,17 +5581,6 @@
}
@Override
- public boolean checkUidNetworkingBlocked(int uid, int uidRules,
- boolean isNetworkMetered, boolean isBackgroundRestricted) {
- mContext.enforceCallingOrSelfPermission(OBSERVE_NETWORK_POLICY, TAG);
- // Log of invoking this function is disabled because it will be called very frequently. And
- // metrics are unlikely needed on this method because the callers are external and this
- // method doesn't take any locks or perform expensive operations.
- return isUidNetworkingBlockedInternal(uid, uidRules, isNetworkMetered,
- isBackgroundRestricted, null);
- }
-
- @Override
public boolean isUidRestrictedOnMeteredNetworks(int uid) {
mContext.enforceCallingOrSelfPermission(OBSERVE_NETWORK_POLICY, TAG);
final int uidRules;
@@ -5728,9 +5741,9 @@
}
@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();
}
}
@@ -5844,7 +5857,8 @@
return (bundle != null) ? bundle.getBoolean(key, defaultValue) : defaultValue;
}
- private class UidBlockedState {
+ @VisibleForTesting
+ static final class UidBlockedState {
public int blockedReasons;
public int allowedReasons;
public int effectiveBlockedReasons;
@@ -5856,16 +5870,21 @@
}
void updateEffectiveBlockedReasons() {
- effectiveBlockedReasons = blockedReasons;
+ effectiveBlockedReasons = getEffectiveBlockedReasons(blockedReasons, allowedReasons);
+ }
+
+ @VisibleForTesting
+ static int getEffectiveBlockedReasons(int blockedReasons, int allowedReasons) {
+ int effectiveBlockedReasons = blockedReasons;
// If the uid is not subject to any blocked reasons, then return early
if (blockedReasons == BLOCKED_REASON_NONE) {
- return;
+ return effectiveBlockedReasons;
}
if ((allowedReasons & ALLOWED_REASON_SYSTEM) != 0) {
- effectiveBlockedReasons = (blockedReasons & ALLOWED_METERED_REASON_MASK);
+ effectiveBlockedReasons &= ALLOWED_METERED_REASON_MASK;
}
if ((allowedReasons & ALLOWED_METERED_REASON_SYSTEM) != 0) {
- effectiveBlockedReasons = (blockedReasons & ~ALLOWED_METERED_REASON_MASK);
+ effectiveBlockedReasons &= ~ALLOWED_METERED_REASON_MASK;
}
if ((allowedReasons & ALLOWED_REASON_FOREGROUND) != 0) {
effectiveBlockedReasons &= ~BLOCKED_REASON_BATTERY_SAVER;
@@ -5891,6 +5910,7 @@
if ((allowedReasons & ALLOWED_METERED_REASON_USER_EXEMPTED) != 0) {
effectiveBlockedReasons &= ~BLOCKED_METERED_REASON_DATA_SAVER;
}
+ return effectiveBlockedReasons;
}
}
diff --git a/services/core/java/com/android/server/net/NetworkStatsManagerInternal.java b/services/core/java/com/android/server/net/NetworkStatsManagerInternal.java
index 0cb0bc2c..0e9a9da 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 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 fe43c31..19f5e3c 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_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_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.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 @@
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 @@
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 @@
}
@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 @@
}
@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 cc6a824..ed1f5f5 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 @@
int pid = 0;
int uid = 0;
- String processName = "";
+ String processName = null;
String crashReason = "";
String selinuxLabel = "";
@@ -407,8 +407,10 @@
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 @@
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 6ad43ce..ca9c75f 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 @@
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,
+ pkg.getUid(),
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 @@
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 c8dc1b1..d67796b 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.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 @@
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,29 @@
ART_COMPILATION_FILTER_FAKE_RUN_FROM_VDEX_FALLBACK);
}
+ private static final Map<String, Integer> ISA_MAP = new HashMap();
+
+ static {
+ ISA_MAP.put("arm", ArtStatsLog.ART_DATUM_REPORTED__ISA__ART_ISA_ARM);
+ ISA_MAP.put("arm64", ArtStatsLog.ART_DATUM_REPORTED__ISA__ART_ISA_ARM64);
+ ISA_MAP.put("x86", ArtStatsLog.ART_DATUM_REPORTED__ISA__ART_ISA_X86);
+ ISA_MAP.put("x86_64", ArtStatsLog.ART_DATUM_REPORTED__ISA__ART_ISA_X86_64);
+ ISA_MAP.put("mips", ArtStatsLog.ART_DATUM_REPORTED__ISA__ART_ISA_MIPS);
+ ISA_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 +156,19 @@
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 +176,47 @@
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 +275,9 @@
String compilerFilter,
int kind,
long value,
- int dexMetadataType) {
+ int dexMetadataType,
+ int apkType,
+ String isa) {
ArtStatsLog.write(
ArtStatsLog.ART_DATUM_REPORTED,
sessionId,
@@ -220,7 +290,10 @@
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 0000000..b187b87
--- /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 0000000..9b9f6b50
--- /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/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index afcf81f..ff763fc 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -54,7 +54,6 @@
import android.os.UserManager;
import android.provider.Settings;
import android.security.Authorization;
-import android.security.KeyStore;
import android.service.trust.TrustAgentService;
import android.text.TextUtils;
import android.util.ArrayMap;
@@ -701,13 +700,11 @@
dispatchDeviceLocked(userId, locked);
Authorization.onLockScreenEvent(locked, userId, null);
- KeyStore.getInstance().onUserLockedStateChanged(userId, locked);
// Also update the user's profiles who have unified challenge, since they
// share the same unlocked state (see {@link #isDeviceLocked(int)})
for (int profileHandle : mUserManager.getEnabledProfileIds(userId)) {
if (mLockPatternUtils.isManagedProfileWithUnifiedChallenge(profileHandle)) {
mAuthorizationService.onLockScreenEvent(locked, profileHandle, null);
- KeyStore.getInstance().onUserLockedStateChanged(profileHandle, locked);
}
}
}
@@ -1259,7 +1256,6 @@
}
Authorization.onLockScreenEvent(locked, userId, null);
- KeyStore.getInstance().onUserLockedStateChanged(userId, locked);
if (locked) {
try {
diff --git a/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java b/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java
index 8dcc547..ab9de77 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.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 @@
@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,95 @@
mConnectivityManager = mVcnContext.getContext().getSystemService(ConnectivityManager.class);
- registerNetworkRequests();
+ registerOrUpdateNetworkRequests();
}
- private void registerNetworkRequests() {
- // register bringup requests for underlying Networks
- mConnectivityManager.requestBackgroundNetwork(
- getWifiNetworkRequest(), mHandler, mWifiBringupCallback);
- updateSubIdsAndCellularRequests();
+ private void registerOrUpdateNetworkRequests() {
+ NetworkCallback oldRouteSelectionCallback = mRouteSelectionCallback;
+ NetworkCallback oldWifiCallback = mWifiBringupCallback;
+ List<NetworkCallback> oldCellCallbacks = new ArrayList<>(mCellBringupCallbacks);
+ mCellBringupCallbacks.clear();
- // 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);
+ // Register new callbacks. Make-before-break; always register new callbacks before removal
+ // of old callbacks
+ if (!mIsQuitting) {
+ mRouteSelectionCallback = new RouteSelectionCallback();
+ mConnectivityManager.requestBackgroundNetwork(
+ getRouteSelectionRequest(), 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 */)
- .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
+ /**
+ * Builds the Route selection request
+ *
+ * <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 getRouteSelectionRequest() {
+ return getBaseNetworkRequestBuilder()
+ .setSubIds(mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup))
.build();
}
+ /**
+ * Builds the WiFi bringup request
+ *
+ * <p>This request is built specifically to match only carrier-owned WiFi networks, but is also
+ * built to ONLY keep Carrier WiFi Networks alive (but never bring them up). This is a result of
+ * the WifiNetworkFactory not advertising a list of subIds, and therefore not accepting this
+ * request. As such, it will bind to a Carrier WiFi Network that has already been brought up,
+ * but will NEVER bring up a Carrier WiFi network itself.
+ */
+ private NetworkRequest getWifiNetworkRequest() {
+ return getBaseNetworkRequestBuilder()
+ .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
+ .setSubIds(mLastSnapshot.getAllSubIdsInGroup(mSubscriptionGroup))
+ .build();
+ }
+
+ /**
+ * Builds a Cellular bringup request for a given subId
+ *
+ * <p>This request is filed in order to ensure that the Telephony stack always has a
+ * NetworkRequest to bring up a VCN underlying cellular network. It is required in order to
+ * ensure that even when a VCN (appears as Cellular) satisfies the default request, Telephony
+ * will bring up additional underlying Cellular networks.
+ *
+ * <p>Since this request MUST make it to the TelephonyNetworkFactory, subIds are not specified
+ * in the NetworkCapabilities, but rather in the TelephonyNetworkSpecifier.
+ */
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();
@@ -142,68 +200,13 @@
/**
* 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.
*/
- 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);
}
/**
@@ -217,22 +220,16 @@
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 +287,6 @@
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 +344,11 @@
@Override
public void onCapabilitiesChanged(
@NonNull Network network, @NonNull NetworkCapabilities networkCapabilities) {
+ if (networkCapabilities.equals(mRecordInProgress.getNetworkCapabilities())) return;
handleCapabilitiesChanged(network, networkCapabilities);
}
@Override
- public void onNetworkSuspended(@NonNull Network network) {
- handleNetworkSuspended(network, true /* isSuspended */);
- }
-
- @Override
- public void onNetworkResumed(@NonNull Network network) {
- handleNetworkSuspended(network, false /* isSuspended */);
- }
-
- @Override
public void onLinkPropertiesChanged(
@NonNull Network network, @NonNull LinkProperties linkProperties) {
handlePropertiesChanged(network, linkProperties);
diff --git a/services/core/java/com/android/server/vcn/Vcn.java b/services/core/java/com/android/server/vcn/Vcn.java
index 89ed956..ae806aa 100644
--- a/services/core/java/com/android/server/vcn/Vcn.java
+++ b/services/core/java/com/android/server/vcn/Vcn.java
@@ -17,6 +17,10 @@
package com.android.server.vcn;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED;
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE;
+import static android.net.vcn.VcnManager.VCN_STATUS_CODE_INACTIVE;
+import static android.net.vcn.VcnManager.VCN_STATUS_CODE_SAFE_MODE;
import static com.android.server.VcnManagementService.VDBG;
@@ -44,7 +48,6 @@
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Set;
-import java.util.concurrent.atomic.AtomicBoolean;
/**
* Represents an single instance of a VCN.
@@ -94,17 +97,21 @@
*/
private static final int MSG_EVENT_GATEWAY_CONNECTION_QUIT = MSG_EVENT_BASE + 3;
+ /**
+ * Triggers reevaluation of safe mode conditions.
+ *
+ * <p>Upon entering safe mode, the VCN will only provide gateway connections opportunistically,
+ * leaving the underlying networks marked as NOT_VCN_MANAGED.
+ *
+ * <p>Any VcnGatewayConnection in safe mode will result in the entire Vcn instance being put
+ * into safe mode. Upon receiving this message, the Vcn MUST query all VcnGatewayConnections to
+ * determine if any are in safe mode.
+ */
+ private static final int MSG_EVENT_SAFE_MODE_STATE_CHANGED = MSG_EVENT_BASE + 4;
+
/** Triggers an immediate teardown of the entire Vcn, including GatewayConnections. */
private static final int MSG_CMD_TEARDOWN = MSG_CMD_BASE;
- /**
- * Causes this VCN to immediately enter safe mode.
- *
- * <p>Upon entering safe mode, the VCN will unregister its RequestListener, tear down all of its
- * VcnGatewayConnections, and notify VcnManagementService that it is in safe mode.
- */
- private static final int MSG_CMD_ENTER_SAFE_MODE = MSG_CMD_BASE + 1;
-
@NonNull private final VcnContext mVcnContext;
@NonNull private final ParcelUuid mSubscriptionGroup;
@NonNull private final Dependencies mDeps;
@@ -137,17 +144,14 @@
@NonNull private TelephonySubscriptionSnapshot mLastSnapshot;
/**
- * Whether this Vcn instance is active and running.
+ * The current status of this Vcn instance
*
- * <p>The value will be {@code true} while running. It will be {@code false} if the VCN has been
- * shut down or has entered safe mode.
- *
- * <p>This AtomicBoolean is required in order to ensure consistency and correctness across
- * multiple threads. Unlike the rest of the Vcn, this is queried synchronously on Binder threads
- * from VcnManagementService, and therefore cannot rely on guarantees of running on the VCN
- * Looper.
+ * <p>The value will be {@link VCN_STATUS_CODE_ACTIVE} while all VcnGatewayConnections are in
+ * good standing, {@link VCN_STATUS_CODE_SAFE_MODE} if any VcnGatewayConnections are in safe
+ * mode, and {@link VCN_STATUS_CODE_INACTIVE} once a teardown has been commanded.
*/
- private final AtomicBoolean mIsActive = new AtomicBoolean(true);
+ // Accessed from different threads, but always under lock in VcnManagementService
+ private volatile int mCurrentStatus = VCN_STATUS_CODE_ACTIVE;
public Vcn(
@NonNull VcnContext vcnContext,
@@ -199,9 +203,15 @@
sendMessageAtFrontOfQueue(obtainMessage(MSG_CMD_TEARDOWN));
}
- /** Synchronously checks whether this Vcn is active. */
- public boolean isActive() {
- return mIsActive.get();
+ /** Synchronously retrieves the current status code. */
+ public int getStatus() {
+ return mCurrentStatus;
+ }
+
+ /** Sets the status of this VCN */
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ public void setStatus(int status) {
+ mCurrentStatus = status;
}
/** Get current Gateways for testing purposes */
@@ -217,12 +227,6 @@
return Collections.unmodifiableMap(new HashMap<>(mVcnGatewayConnections));
}
- /** Set whether this Vcn is active for testing purposes */
- @VisibleForTesting(visibility = Visibility.PRIVATE)
- public void setIsActive(boolean isActive) {
- mIsActive.set(isActive);
- }
-
private class VcnNetworkRequestListener implements VcnNetworkProvider.NetworkRequestListener {
@Override
public void onNetworkRequested(@NonNull NetworkRequest request, int score, int providerId) {
@@ -234,6 +238,11 @@
@Override
public void handleMessage(@NonNull Message msg) {
+ if (mCurrentStatus != VCN_STATUS_CODE_ACTIVE
+ && mCurrentStatus != VCN_STATUS_CODE_SAFE_MODE) {
+ return;
+ }
+
switch (msg.what) {
case MSG_EVENT_CONFIG_UPDATED:
handleConfigUpdated((VcnConfig) msg.obj);
@@ -247,12 +256,12 @@
case MSG_EVENT_GATEWAY_CONNECTION_QUIT:
handleGatewayConnectionQuit((VcnGatewayConnectionConfig) msg.obj);
break;
+ case MSG_EVENT_SAFE_MODE_STATE_CHANGED:
+ handleSafeModeStatusChanged();
+ break;
case MSG_CMD_TEARDOWN:
handleTeardown();
break;
- case MSG_CMD_ENTER_SAFE_MODE:
- handleEnterSafeMode();
- break;
default:
Slog.wtf(getLogTag(), "Unknown msg.what: " + msg.what);
}
@@ -264,35 +273,28 @@
mConfig = config;
- if (mIsActive.getAndSet(true)) {
- // VCN is already active - teardown any GatewayConnections whose configs have been
- // removed and get all current requests
- for (final Entry<VcnGatewayConnectionConfig, VcnGatewayConnection> entry :
- mVcnGatewayConnections.entrySet()) {
- final VcnGatewayConnectionConfig gatewayConnectionConfig = entry.getKey();
- final VcnGatewayConnection gatewayConnection = entry.getValue();
+ // Teardown any GatewayConnections whose configs have been removed and get all current
+ // requests
+ for (final Entry<VcnGatewayConnectionConfig, VcnGatewayConnection> entry :
+ mVcnGatewayConnections.entrySet()) {
+ final VcnGatewayConnectionConfig gatewayConnectionConfig = entry.getKey();
+ final VcnGatewayConnection gatewayConnection = entry.getValue();
- // GatewayConnectionConfigs must match exactly (otherwise authentication or
- // connection details may have changed).
- if (!mConfig.getGatewayConnectionConfigs().contains(gatewayConnectionConfig)) {
- if (gatewayConnection == null) {
- Slog.wtf(
- getLogTag(),
- "Found gatewayConnectionConfig without GatewayConnection");
- } else {
- gatewayConnection.teardownAsynchronously();
- }
+ // GatewayConnectionConfigs must match exactly (otherwise authentication or
+ // connection details may have changed).
+ if (!mConfig.getGatewayConnectionConfigs().contains(gatewayConnectionConfig)) {
+ if (gatewayConnection == null) {
+ Slog.wtf(
+ getLogTag(), "Found gatewayConnectionConfig without GatewayConnection");
+ } else {
+ gatewayConnection.teardownAsynchronously();
}
}
-
- // Trigger a re-evaluation of all NetworkRequests (to make sure any that can be
- // satisfied start a new GatewayConnection)
- mVcnContext.getVcnNetworkProvider().resendAllRequests(mRequestListener);
- } else {
- // If this VCN was not previously active, it is exiting Safe Mode. Re-register the
- // request listener to get NetworkRequests again (and all cached requests).
- mVcnContext.getVcnNetworkProvider().registerListener(mRequestListener);
}
+
+ // Trigger a re-evaluation of all NetworkRequests (to make sure any that can be
+ // satisfied start a new GatewayConnection)
+ mVcnContext.getVcnNetworkProvider().resendAllRequests(mRequestListener);
}
private void handleTeardown() {
@@ -302,22 +304,30 @@
gatewayConnection.teardownAsynchronously();
}
- mIsActive.set(false);
+ mCurrentStatus = VCN_STATUS_CODE_INACTIVE;
}
- private void handleEnterSafeMode() {
- handleTeardown();
+ private void handleSafeModeStatusChanged() {
+ boolean hasSafeModeGatewayConnection = false;
- mVcnCallback.onEnteredSafeMode();
+ // If any VcnGatewayConnection is in safe mode, mark the entire VCN as being in safe mode
+ for (VcnGatewayConnection gatewayConnection : mVcnGatewayConnections.values()) {
+ if (gatewayConnection.isInSafeMode()) {
+ hasSafeModeGatewayConnection = true;
+ break;
+ }
+ }
+
+ final int oldStatus = mCurrentStatus;
+ mCurrentStatus =
+ hasSafeModeGatewayConnection ? VCN_STATUS_CODE_SAFE_MODE : VCN_STATUS_CODE_ACTIVE;
+ if (oldStatus != mCurrentStatus) {
+ mVcnCallback.onSafeModeStatusChanged(hasSafeModeGatewayConnection);
+ }
}
private void handleNetworkRequested(
@NonNull NetworkRequest request, int score, int providerId) {
- if (!isActive()) {
- Slog.v(getLogTag(), "Received NetworkRequest while inactive. Ignore for now");
- return;
- }
-
if (score > getNetworkScore()) {
if (VDBG) {
Slog.v(
@@ -370,25 +380,23 @@
mVcnGatewayConnections.remove(config);
// Trigger a re-evaluation of all NetworkRequests (to make sure any that can be satisfied
- // start a new GatewayConnection), but only if the Vcn is still active
- if (isActive()) {
- mVcnContext.getVcnNetworkProvider().resendAllRequests(mRequestListener);
- }
+ // start a new GatewayConnection). VCN is always alive here, courtesy of the liveness check
+ // in handleMessage()
+ mVcnContext.getVcnNetworkProvider().resendAllRequests(mRequestListener);
}
private void handleSubscriptionsChanged(@NonNull TelephonySubscriptionSnapshot snapshot) {
mLastSnapshot = snapshot;
- if (isActive()) {
- for (VcnGatewayConnection gatewayConnection : mVcnGatewayConnections.values()) {
- gatewayConnection.updateSubscriptionSnapshot(mLastSnapshot);
- }
+ for (VcnGatewayConnection gatewayConnection : mVcnGatewayConnections.values()) {
+ gatewayConnection.updateSubscriptionSnapshot(mLastSnapshot);
}
}
private boolean isRequestSatisfiedByGatewayConnectionConfig(
@NonNull NetworkRequest request, @NonNull VcnGatewayConnectionConfig config) {
final NetworkCapabilities.Builder builder = new NetworkCapabilities.Builder();
+ builder.addTransportType(TRANSPORT_CELLULAR);
builder.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
for (int cap : config.getAllExposedCapabilities()) {
builder.addCapability(cap);
@@ -412,12 +420,12 @@
/** Callback used for passing status signals from a VcnGatewayConnection to its managing Vcn. */
@VisibleForTesting(visibility = Visibility.PACKAGE)
public interface VcnGatewayStatusCallback {
- /** Called by a VcnGatewayConnection to indicate that it has entered safe mode. */
- void onEnteredSafeMode();
+ /** Called by a VcnGatewayConnection to indicate that it's safe mode status has changed. */
+ void onSafeModeStatusChanged();
/** Callback by a VcnGatewayConnection to indicate that an error occurred. */
void onGatewayConnectionError(
- @NonNull int[] networkCapabilities,
+ @NonNull String gatewayConnectionName,
@VcnErrorCode int errorCode,
@Nullable String exceptionClass,
@Nullable String exceptionMessage);
@@ -439,18 +447,18 @@
}
@Override
- public void onEnteredSafeMode() {
- sendMessage(obtainMessage(MSG_CMD_ENTER_SAFE_MODE));
+ public void onSafeModeStatusChanged() {
+ sendMessage(obtainMessage(MSG_EVENT_SAFE_MODE_STATE_CHANGED));
}
@Override
public void onGatewayConnectionError(
- @NonNull int[] networkCapabilities,
+ @NonNull String gatewayConnectionName,
@VcnErrorCode int errorCode,
@Nullable String exceptionClass,
@Nullable String exceptionMessage) {
mVcnCallback.onGatewayConnectionError(
- networkCapabilities, errorCode, exceptionClass, exceptionMessage);
+ gatewayConnectionName, errorCode, exceptionClass, exceptionMessage);
}
}
diff --git a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
index 9589505..20c08eb 100644
--- a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
+++ b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
@@ -32,6 +32,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
+import android.net.ConnectivityManager;
import android.net.InetAddresses;
import android.net.IpPrefix;
import android.net.IpSecManager;
@@ -44,6 +45,7 @@
import android.net.NetworkAgent;
import android.net.NetworkAgentConfig;
import android.net.NetworkCapabilities;
+import android.net.NetworkProvider;
import android.net.RouteInfo;
import android.net.TelephonyNetworkSpecifier;
import android.net.Uri;
@@ -92,6 +94,7 @@
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
/**
* A single VCN Gateway Connection, providing a single public-facing VCN network.
@@ -504,6 +507,15 @@
private boolean mIsQuitting = false;
/**
+ * Whether the VcnGatewayConnection is in safe mode.
+ *
+ * <p>Upon hitting the safe mode timeout, this will be set to {@code true}. In safe mode, this
+ * VcnGatewayConnection will continue attempting to connect, and if a successful connection is
+ * made, safe mode will be exited.
+ */
+ private boolean mIsInSafeMode = false;
+
+ /**
* The token used by the primary/current/active session.
*
* <p>This token MUST be updated when a new stateful/async session becomes the
@@ -562,8 +574,7 @@
* <p>Set in Connected state, always @NonNull in Connected, Migrating states, @Nullable
* otherwise.
*/
- @VisibleForTesting(visibility = Visibility.PRIVATE)
- NetworkAgent mNetworkAgent;
+ private NetworkAgent mNetworkAgent;
@Nullable private WakeupMessage mTeardownTimeoutAlarm;
@Nullable private WakeupMessage mDisconnectRequestAlarm;
@@ -628,6 +639,14 @@
start();
}
+ /** Queries whether this VcnGatewayConnection is in safe mode. */
+ public boolean isInSafeMode() {
+ // Accessing internal state; must only be done on looper thread.
+ mVcnContext.ensureRunningOnLooperThread();
+
+ return mIsInSafeMode;
+ }
+
/**
* Asynchronously tears down this GatewayConnection, and any resources used.
*
@@ -980,7 +999,7 @@
// IkeSessionCallback.onClosedExceptionally(), which calls sessionClosed()
if (exception != null) {
mGatewayStatusCallback.onGatewayConnectionError(
- mConnectionConfig.getExposedCapabilities(),
+ mConnectionConfig.getGatewayConnectionName(),
VCN_ERROR_CODE_INTERNAL_ERROR,
RuntimeException.class.getName(),
"Received "
@@ -1017,7 +1036,7 @@
}
mGatewayStatusCallback.onGatewayConnectionError(
- mConnectionConfig.getExposedCapabilities(),
+ mConnectionConfig.getGatewayConnectionName(),
errorCode,
exceptionClass,
exceptionMessage);
@@ -1162,6 +1181,15 @@
}
}
+ protected void handleSafeModeTimeoutExceeded() {
+ mSafeModeTimeoutAlarm = null;
+
+ // Connectivity for this GatewayConnection is broken; tear down the Network.
+ teardownNetwork();
+ mIsInSafeMode = true;
+ mGatewayStatusCallback.onSafeModeStatusChanged();
+ }
+
protected void logUnexpectedEvent(int what) {
Slog.d(TAG, String.format(
"Unexpected event code %d in state %s", what, this.getClass().getSimpleName()));
@@ -1315,8 +1343,7 @@
}
break;
case EVENT_SAFE_MODE_TIMEOUT_EXCEEDED:
- mGatewayStatusCallback.onEnteredSafeMode();
- mSafeModeTimeoutAlarm = null;
+ handleSafeModeTimeoutExceeded();
break;
default:
logUnhandledMessage(msg);
@@ -1401,8 +1428,7 @@
handleDisconnectRequested((EventDisconnectRequestedInfo) msg.obj);
break;
case EVENT_SAFE_MODE_TIMEOUT_EXCEEDED:
- mGatewayStatusCallback.onEnteredSafeMode();
- mSafeModeTimeoutAlarm = null;
+ handleSafeModeTimeoutExceeded();
break;
default:
logUnhandledMessage(msg);
@@ -1432,30 +1458,35 @@
buildNetworkCapabilities(mConnectionConfig, mUnderlying);
final LinkProperties lp =
buildConnectedLinkProperties(mConnectionConfig, tunnelIface, childConfig);
+ final NetworkAgentConfig nac =
+ new NetworkAgentConfig.Builder()
+ .setLegacyType(ConnectivityManager.TYPE_MOBILE)
+ .build();
final NetworkAgent agent =
- new NetworkAgent(
- mVcnContext.getContext(),
- mVcnContext.getLooper(),
+ mDeps.newNetworkAgent(
+ mVcnContext,
TAG,
caps,
lp,
Vcn.getNetworkScore(),
- new NetworkAgentConfig.Builder().build(),
- mVcnContext.getVcnNetworkProvider()) {
- @Override
- public void onNetworkUnwanted() {
- Slog.d(TAG, "NetworkAgent was unwanted");
- teardownAsynchronously();
- }
-
- @Override
- public void onValidationStatus(int status, @Nullable Uri redirectUri) {
- if (status == NetworkAgent.VALIDATION_STATUS_VALID) {
- clearFailedAttemptCounterAndSafeModeAlarm();
- }
- }
- };
+ nac,
+ mVcnContext.getVcnNetworkProvider(),
+ () -> {
+ Slog.d(TAG, "NetworkAgent was unwanted");
+ // If network agent has already been torn down, skip sending the
+ // disconnect. Unwanted() is always called, even when networkAgents
+ // are unregistered in teardownNetwork(), so prevent duplicate
+ // notifications.
+ if (mNetworkAgent != null) {
+ teardownAsynchronously();
+ }
+ } /* networkUnwantedCallback */,
+ (status) -> {
+ if (status == NetworkAgent.VALIDATION_STATUS_VALID) {
+ clearFailedAttemptCounterAndSafeModeAlarm();
+ }
+ } /* validationStatusCallback */);
agent.register();
agent.markConnected();
@@ -1469,6 +1500,11 @@
// Validated connection, clear failed attempt counter
mFailedAttempts = 0;
cancelSafeModeAlarm();
+
+ if (mIsInSafeMode) {
+ mIsInSafeMode = false;
+ mGatewayStatusCallback.onSafeModeStatusChanged();
+ }
}
protected void applyTransform(
@@ -1491,13 +1527,6 @@
protected void setupInterface(
int token,
@NonNull IpSecTunnelInterface tunnelIface,
- @NonNull VcnChildSessionConfiguration childConfig) {
- setupInterface(token, tunnelIface, childConfig, null);
- }
-
- protected void setupInterface(
- int token,
- @NonNull IpSecTunnelInterface tunnelIface,
@NonNull VcnChildSessionConfiguration childConfig,
@Nullable VcnChildSessionConfiguration oldChildConfig) {
try {
@@ -1579,16 +1608,17 @@
transformCreatedInfo.direction);
break;
case EVENT_SETUP_COMPLETED:
+ final VcnChildSessionConfiguration oldChildConfig = mChildConfig;
mChildConfig = ((EventSetupCompletedInfo) msg.obj).childSessionConfig;
- setupInterfaceAndNetworkAgent(mCurrentToken, mTunnelIface, mChildConfig);
+ setupInterfaceAndNetworkAgent(
+ mCurrentToken, mTunnelIface, mChildConfig, oldChildConfig);
break;
case EVENT_DISCONNECT_REQUESTED:
handleDisconnectRequested((EventDisconnectRequestedInfo) msg.obj);
break;
case EVENT_SAFE_MODE_TIMEOUT_EXCEEDED:
- mGatewayStatusCallback.onEnteredSafeMode();
- mSafeModeTimeoutAlarm = null;
+ handleSafeModeTimeoutExceeded();
break;
default:
logUnhandledMessage(msg);
@@ -1626,8 +1656,9 @@
protected void setupInterfaceAndNetworkAgent(
int token,
@NonNull IpSecTunnelInterface tunnelIface,
- @NonNull VcnChildSessionConfiguration childConfig) {
- setupInterface(token, tunnelIface, childConfig);
+ @NonNull VcnChildSessionConfiguration childConfig,
+ @NonNull VcnChildSessionConfiguration oldChildConfig) {
+ setupInterface(token, tunnelIface, childConfig, oldChildConfig);
if (mNetworkAgent == null) {
mNetworkAgent = buildNetworkAgent(tunnelIface, childConfig);
@@ -1692,8 +1723,7 @@
handleDisconnectRequested((EventDisconnectRequestedInfo) msg.obj);
break;
case EVENT_SAFE_MODE_TIMEOUT_EXCEEDED:
- mGatewayStatusCallback.onEnteredSafeMode();
- mSafeModeTimeoutAlarm = null;
+ handleSafeModeTimeoutExceeded();
break;
default:
logUnhandledMessage(msg);
@@ -1935,6 +1965,16 @@
}
@VisibleForTesting(visibility = Visibility.PRIVATE)
+ NetworkAgent getNetworkAgent() {
+ return mNetworkAgent;
+ }
+
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ void setNetworkAgent(@Nullable NetworkAgent networkAgent) {
+ mNetworkAgent = networkAgent;
+ }
+
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
void sendDisconnectRequestedAndAcquireWakelock(String reason, boolean shouldQuit) {
sendMessageAndAcquireWakeLock(
EVENT_DISCONNECT_REQUESTED,
@@ -2018,6 +2058,38 @@
return new WakeupMessage(vcnContext.getContext(), handler, tag, runnable);
}
+ /** Builds a new NetworkAgent. */
+ public NetworkAgent newNetworkAgent(
+ @NonNull VcnContext vcnContext,
+ @NonNull String tag,
+ @NonNull NetworkCapabilities caps,
+ @NonNull LinkProperties lp,
+ @NonNull int score,
+ @NonNull NetworkAgentConfig nac,
+ @NonNull NetworkProvider provider,
+ @NonNull Runnable networkUnwantedCallback,
+ @NonNull Consumer<Integer> validationStatusCallback) {
+ return new NetworkAgent(
+ vcnContext.getContext(),
+ vcnContext.getLooper(),
+ tag,
+ caps,
+ lp,
+ score,
+ nac,
+ provider) {
+ @Override
+ public void onNetworkUnwanted() {
+ networkUnwantedCallback.run();
+ }
+
+ @Override
+ public void onValidationStatus(int status, @Nullable Uri redirectUri) {
+ validationStatusCallback.accept(status);
+ }
+ };
+ }
+
/** Gets the elapsed real time since boot, in millis. */
public long getElapsedRealTime() {
return SystemClock.elapsedRealtime();
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index ea47a27..d0bd8b3 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -102,6 +102,7 @@
"libaudioclient",
"libbase",
"libappfuse",
+ "libbinder_ndk",
"libbinder",
"libcutils",
"libcrypto",
@@ -110,7 +111,7 @@
"libhardware",
"libhardware_legacy",
"libhidlbase",
- "libkeystore_binder",
+ "libmemtrackproxy",
"libmtp",
"libnativehelper",
"libprocessgroup",
@@ -155,6 +156,7 @@
"android.hardware.input.classifier@1.0",
"android.hardware.ir@1.0",
"android.hardware.light@2.0",
+ "android.hardware.memtrack-V1-ndk_platform",
"android.hardware.power@1.0",
"android.hardware.power@1.1",
"android.hardware.power-V1-cpp",
diff --git a/services/core/jni/com_android_server_SystemServer.cpp b/services/core/jni/com_android_server_SystemServer.cpp
index d18043f..b93b8ab 100644
--- a/services/core/jni/com_android_server_SystemServer.cpp
+++ b/services/core/jni/com_android_server_SystemServer.cpp
@@ -23,11 +23,14 @@
#include <jni.h>
#include <nativehelper/JNIHelp.h>
+#include <android/binder_manager.h>
+#include <android/binder_stability.h>
#include <android/hidl/manager/1.2/IServiceManager.h>
#include <binder/IServiceManager.h>
#include <hidl/HidlTransportSupport.h>
#include <incremental_service.h>
+#include <memtrackproxy/MemtrackProxy.h>
#include <schedulerservice/SchedulingPolicyService.h>
#include <sensorservice/SensorService.h>
#include <sensorservicehidl/SensorManager.h>
@@ -57,6 +60,21 @@
}
+static void android_server_SystemServer_startMemtrackProxyService(JNIEnv* env,
+ jobject /* clazz */) {
+ using aidl::android::hardware::memtrack::MemtrackProxy;
+
+ const char* memtrackProxyService = "memtrack.proxy";
+
+ std::shared_ptr<MemtrackProxy> memtrack_proxy = ndk::SharedRefBase::make<MemtrackProxy>();
+ auto binder = memtrack_proxy->asBinder();
+
+ AIBinder_forceDowngradeToLocalStability(binder.get());
+
+ const binder_exception_t err = AServiceManager_addService(binder.get(), memtrackProxyService);
+ LOG_ALWAYS_FATAL_IF(err != EX_NONE, "Cannot register %s: %d", memtrackProxyService, err);
+}
+
static void android_server_SystemServer_startHidlServices(JNIEnv* env, jobject /* clazz */) {
using ::android::frameworks::schedulerservice::V1_0::ISchedulingPolicyService;
using ::android::frameworks::schedulerservice::V1_0::implementation::SchedulingPolicyService;
@@ -121,6 +139,8 @@
static const JNINativeMethod gMethods[] = {
/* name, signature, funcPtr */
{"startSensorService", "()V", (void*)android_server_SystemServer_startSensorService},
+ {"startMemtrackProxyService", "()V",
+ (void*)android_server_SystemServer_startMemtrackProxyService},
{"startHidlServices", "()V", (void*)android_server_SystemServer_startHidlServices},
{"initZygoteChildHeapProfiling", "()V",
(void*)android_server_SystemServer_initZygoteChildHeapProfiling},
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 46ec65d..81ec8f4 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -96,6 +96,7 @@
import com.android.internal.widget.ILockSettings;
import com.android.server.am.ActivityManagerService;
import com.android.server.appbinding.AppBindingService;
+import com.android.server.art.ArtManagerLocal;
import com.android.server.attention.AttentionManagerService;
import com.android.server.audio.AudioService;
import com.android.server.biometrics.AuthService;
@@ -392,6 +393,11 @@
private static native void startSensorService();
/**
+ * Start the memtrack proxy service.
+ */
+ private static native void startMemtrackProxyService();
+
+ /**
* Start all HIDL services that are run inside the system server. This may take some time.
*/
private static native void startHidlServices();
@@ -829,6 +835,12 @@
mSystemServiceManager.startService(UriGrantsManagerService.Lifecycle.class);
t.traceEnd();
+ // Start MemtrackProxyService before ActivityManager, so that early calls
+ // to Memtrack::getMemory() don't fail.
+ t.traceBegin("MemtrackProxyService");
+ startMemtrackProxyService();
+ t.traceEnd();
+
// Activity manager runs the show.
t.traceBegin("StartActivityManager");
// TODO: Might need to move after migration to WM.
@@ -2330,6 +2342,10 @@
}
t.traceEnd();
+ t.traceBegin("ArtManagerLocal");
+ LocalManagerRegistry.addManager(ArtManagerLocal.class, new ArtManagerLocal());
+ t.traceEnd();
+
t.traceBegin("StartBootPhaseDeviceSpecificServicesReady");
mSystemServiceManager.startBootPhase(t, SystemService.PHASE_DEVICE_SPECIFIC_SERVICES_READY);
t.traceEnd();
diff --git a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
index 29aedce..1208ecc 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.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 @@
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 @@
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 fb01ff6..e9e2486 100644
--- a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
@@ -18,6 +18,12 @@
import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS;
import static android.Manifest.permission.NETWORK_STACK;
+import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_DATA_SAVER;
+import static android.net.ConnectivityManager.BLOCKED_METERED_REASON_USER_RESTRICTED;
+import static android.net.ConnectivityManager.BLOCKED_REASON_APP_STANDBY;
+import static android.net.ConnectivityManager.BLOCKED_REASON_BATTERY_SAVER;
+import static android.net.ConnectivityManager.BLOCKED_REASON_DOZE;
+import static android.net.ConnectivityManager.BLOCKED_REASON_NONE;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
import static android.net.ConnectivityManager.TYPE_MOBILE;
import static android.net.ConnectivityManager.TYPE_WIFI;
@@ -29,16 +35,17 @@
import static android.net.NetworkPolicy.LIMIT_DISABLED;
import static android.net.NetworkPolicy.SNOOZE_NEVER;
import static android.net.NetworkPolicy.WARNING_DISABLED;
+import static android.net.NetworkPolicyManager.ALLOWED_METERED_REASON_FOREGROUND;
+import static android.net.NetworkPolicyManager.ALLOWED_METERED_REASON_SYSTEM;
+import static android.net.NetworkPolicyManager.ALLOWED_REASON_FOREGROUND;
+import static android.net.NetworkPolicyManager.ALLOWED_REASON_NONE;
+import static android.net.NetworkPolicyManager.ALLOWED_REASON_SYSTEM;
import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT;
import static android.net.NetworkPolicyManager.POLICY_ALLOW_METERED_BACKGROUND;
import static android.net.NetworkPolicyManager.POLICY_NONE;
import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
-import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
-import static android.net.NetworkPolicyManager.RULE_ALLOW_METERED;
-import static android.net.NetworkPolicyManager.RULE_NONE;
-import static android.net.NetworkPolicyManager.RULE_REJECT_ALL;
-import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
-import static android.net.NetworkPolicyManager.RULE_TEMPORARY_ALLOW_METERED;
+import static android.net.NetworkPolicyManager.allowedReasonsToString;
+import static android.net.NetworkPolicyManager.blockedReasonsToString;
import static android.net.NetworkPolicyManager.uidPoliciesToString;
import static android.net.NetworkPolicyManager.uidRulesToString;
import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
@@ -49,7 +56,6 @@
import static android.net.NetworkTemplate.buildTemplateMobileAll;
import static android.net.NetworkTemplate.buildTemplateWifi;
import static android.net.TrafficStats.MB_IN_BYTES;
-import static android.os.Process.SYSTEM_UID;
import static android.telephony.CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED;
import static android.telephony.CarrierConfigManager.DATA_CYCLE_THRESHOLD_DISABLED;
import static android.telephony.CarrierConfigManager.DATA_CYCLE_USE_PLATFORM_DEFAULT;
@@ -66,6 +72,7 @@
import static com.android.server.net.NetworkPolicyManagerService.TYPE_LIMIT_SNOOZED;
import static com.android.server.net.NetworkPolicyManagerService.TYPE_RAPID;
import static com.android.server.net.NetworkPolicyManagerService.TYPE_WARNING;
+import static com.android.server.net.NetworkPolicyManagerService.UidBlockedState.getEffectiveBlockedReasons;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -144,6 +151,7 @@
import android.util.Pair;
import android.util.Range;
import android.util.RecurrenceRule;
+import android.util.SparseArray;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.FlakyTest;
@@ -1773,119 +1781,75 @@
true);
}
- /**
- * Test that when StatsProvider triggers limit reached, new limit will be calculated and
- * re-armed.
- */
- @Test
- public void testStatsProviderLimitReached() throws Exception {
- final int CYCLE_DAY = 15;
-
- final NetworkStats stats = new NetworkStats(0L, 1);
+ private void increaseMockedTotalBytes(NetworkStats stats, long rxBytes, long txBytes) {
stats.insertEntry(TEST_IFACE, UID_A, SET_ALL, TAG_NONE,
- 2999, 1, 2000, 1, 0);
+ 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 warning and limit reached, new quotas will be
+ * calculated and re-armed.
+ */
+ @Test
+ public void testStatsProviderWarningAndLimitReached() throws Exception {
+ final int CYCLE_DAY = 15;
+
+ final NetworkStats stats = new NetworkStats(0L, 1);
+ 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);
- }
-
- /**
- * Exhaustively test checkUidNetworkingBlocked to output the expected results based on external
- * conditions.
- */
- @Test
- public void testCheckUidNetworkingBlocked() {
- final ArrayList<Pair<Boolean, Integer>> expectedBlockedStates = new ArrayList<>();
-
- // Metered network. Data saver on.
- expectedBlockedStates.add(new Pair<>(true, RULE_NONE));
- expectedBlockedStates.add(new Pair<>(false, RULE_ALLOW_METERED));
- expectedBlockedStates.add(new Pair<>(false, RULE_TEMPORARY_ALLOW_METERED));
- expectedBlockedStates.add(new Pair<>(true, RULE_REJECT_METERED));
- expectedBlockedStates.add(new Pair<>(true, RULE_ALLOW_ALL));
- expectedBlockedStates.add(new Pair<>(true, RULE_REJECT_ALL));
- verifyNetworkBlockedState(
- true /* metered */, true /* backgroundRestricted */, expectedBlockedStates);
- expectedBlockedStates.clear();
-
- // Metered network. Data saver off.
- expectedBlockedStates.add(new Pair<>(false, RULE_NONE));
- expectedBlockedStates.add(new Pair<>(false, RULE_ALLOW_METERED));
- expectedBlockedStates.add(new Pair<>(false, RULE_TEMPORARY_ALLOW_METERED));
- expectedBlockedStates.add(new Pair<>(true, RULE_REJECT_METERED));
- expectedBlockedStates.add(new Pair<>(false, RULE_ALLOW_ALL));
- expectedBlockedStates.add(new Pair<>(true, RULE_REJECT_ALL));
- verifyNetworkBlockedState(
- true /* metered */, false /* backgroundRestricted */, expectedBlockedStates);
- expectedBlockedStates.clear();
-
- // Non-metered network. Data saver on.
- expectedBlockedStates.add(new Pair<>(false, RULE_NONE));
- expectedBlockedStates.add(new Pair<>(false, RULE_ALLOW_METERED));
- expectedBlockedStates.add(new Pair<>(false, RULE_TEMPORARY_ALLOW_METERED));
- expectedBlockedStates.add(new Pair<>(false, RULE_REJECT_METERED));
- expectedBlockedStates.add(new Pair<>(false, RULE_ALLOW_ALL));
- expectedBlockedStates.add(new Pair<>(true, RULE_REJECT_ALL));
- verifyNetworkBlockedState(
- false /* metered */, true /* backgroundRestricted */, expectedBlockedStates);
-
- // Non-metered network. Data saver off. The result is the same as previous case since
- // the network is blocked only for RULE_REJECT_ALL regardless of data saver.
- verifyNetworkBlockedState(
- false /* metered */, false /* backgroundRestricted */, expectedBlockedStates);
- expectedBlockedStates.clear();
- }
-
- private void verifyNetworkBlockedState(boolean metered, boolean backgroundRestricted,
- ArrayList<Pair<Boolean, Integer>> expectedBlockedStateForRules) {
-
- for (Pair<Boolean, Integer> pair : expectedBlockedStateForRules) {
- final boolean expectedResult = pair.first;
- final int rule = pair.second;
- assertEquals(formatBlockedStateError(UID_A, rule, metered, backgroundRestricted),
- expectedResult, mService.checkUidNetworkingBlocked(UID_A, rule,
- metered, backgroundRestricted));
- assertFalse(formatBlockedStateError(SYSTEM_UID, rule, metered, backgroundRestricted),
- mService.checkUidNetworkingBlocked(SYSTEM_UID, rule, metered,
- backgroundRestricted));
- }
+ // 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);
}
private void enableRestrictedMode(boolean enable) throws Exception {
@@ -1948,6 +1912,65 @@
assertFalse(mService.isUidNetworkingBlocked(UID_E, false));
}
+ @Test
+ public void testUpdateEffectiveBlockedReasons() {
+ final SparseArray<Pair<Integer, Integer>> effectiveBlockedReasons = new SparseArray<>();
+ effectiveBlockedReasons.put(BLOCKED_REASON_NONE,
+ Pair.create(BLOCKED_REASON_NONE, ALLOWED_REASON_NONE));
+
+ effectiveBlockedReasons.put(BLOCKED_REASON_NONE,
+ Pair.create(BLOCKED_REASON_BATTERY_SAVER, ALLOWED_REASON_SYSTEM));
+ effectiveBlockedReasons.put(BLOCKED_REASON_NONE,
+ Pair.create(BLOCKED_REASON_BATTERY_SAVER | BLOCKED_REASON_DOZE,
+ ALLOWED_REASON_SYSTEM));
+ effectiveBlockedReasons.put(BLOCKED_REASON_NONE,
+ Pair.create(BLOCKED_METERED_REASON_DATA_SAVER,
+ ALLOWED_METERED_REASON_SYSTEM));
+ effectiveBlockedReasons.put(BLOCKED_REASON_NONE,
+ Pair.create(BLOCKED_METERED_REASON_DATA_SAVER
+ | BLOCKED_METERED_REASON_USER_RESTRICTED,
+ ALLOWED_METERED_REASON_SYSTEM));
+
+ effectiveBlockedReasons.put(BLOCKED_METERED_REASON_DATA_SAVER,
+ Pair.create(BLOCKED_REASON_BATTERY_SAVER | BLOCKED_METERED_REASON_DATA_SAVER,
+ ALLOWED_REASON_SYSTEM));
+ effectiveBlockedReasons.put(BLOCKED_REASON_APP_STANDBY,
+ Pair.create(BLOCKED_REASON_APP_STANDBY | BLOCKED_METERED_REASON_USER_RESTRICTED,
+ ALLOWED_METERED_REASON_SYSTEM));
+
+ effectiveBlockedReasons.put(BLOCKED_REASON_NONE,
+ Pair.create(BLOCKED_REASON_BATTERY_SAVER, ALLOWED_REASON_FOREGROUND));
+ effectiveBlockedReasons.put(BLOCKED_REASON_NONE,
+ Pair.create(BLOCKED_REASON_BATTERY_SAVER | BLOCKED_REASON_DOZE,
+ ALLOWED_REASON_FOREGROUND));
+ effectiveBlockedReasons.put(BLOCKED_REASON_NONE,
+ Pair.create(BLOCKED_METERED_REASON_DATA_SAVER, ALLOWED_METERED_REASON_FOREGROUND));
+ effectiveBlockedReasons.put(BLOCKED_REASON_NONE,
+ Pair.create(BLOCKED_METERED_REASON_DATA_SAVER
+ | BLOCKED_METERED_REASON_USER_RESTRICTED,
+ ALLOWED_METERED_REASON_FOREGROUND));
+ effectiveBlockedReasons.put(BLOCKED_METERED_REASON_DATA_SAVER,
+ Pair.create(BLOCKED_REASON_BATTERY_SAVER | BLOCKED_METERED_REASON_DATA_SAVER,
+ ALLOWED_REASON_FOREGROUND));
+ effectiveBlockedReasons.put(BLOCKED_REASON_BATTERY_SAVER,
+ Pair.create(BLOCKED_REASON_BATTERY_SAVER
+ | BLOCKED_METERED_REASON_USER_RESTRICTED,
+ ALLOWED_METERED_REASON_FOREGROUND));
+ // TODO: test more combinations of blocked reasons.
+
+ for (int i = 0; i < effectiveBlockedReasons.size(); ++i) {
+ final int expectedEffectiveBlockedReasons = effectiveBlockedReasons.keyAt(i);
+ final int blockedReasons = effectiveBlockedReasons.valueAt(i).first;
+ final int allowedReasons = effectiveBlockedReasons.valueAt(i).second;
+ final String errorMsg = "Expected="
+ + blockedReasonsToString(expectedEffectiveBlockedReasons)
+ + "; blockedReasons=" + blockedReasonsToString(blockedReasons)
+ + ", allowedReasons=" + allowedReasonsToString(allowedReasons);
+ assertEquals(errorMsg, expectedEffectiveBlockedReasons,
+ getEffectiveBlockedReasons(blockedReasons, allowedReasons));
+ }
+ }
+
private String formatBlockedStateError(int uid, int rule, boolean metered,
boolean backgroundRestricted) {
return String.format(
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 13d75a7..7d6f4ac 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.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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 0000000..3bd5953
--- /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 973b20a..ae5db3d 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -1153,6 +1153,10 @@
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 0000000..201ab53
--- /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 0000000..3941b30
--- /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 0ba96a9..f027cd1 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.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 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 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 @@
// 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 @@
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 9ea624b..ce2f3f9 100644
--- a/telephony/java/android/telephony/PreciseDataConnectionState.java
+++ b/telephony/java/android/telephony/PreciseDataConnectionState.java
@@ -166,14 +166,12 @@
/**
* @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/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 85fe14e..47a802f 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -2465,7 +2465,10 @@
if (subInfo != null) {
overrideConfig.mcc = subInfo.getMcc();
overrideConfig.mnc = subInfo.getMnc();
- if (overrideConfig.mnc == 0) overrideConfig.mnc = Configuration.MNC_ZERO;
+ if (overrideConfig.mnc == 0) {
+ overrideConfig.mnc = Configuration.MNC_ZERO;
+ cacheKey = null;
+ }
}
if (useRootLocale) {
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 7c39cf0..a2467f2 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -99,6 +99,7 @@
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.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 @@
}
/**
+ * 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 @@
/**
* 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 @@
};
/**
+ * 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 @@
@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 @@
}
}, getOpPackageName(), getAttributionTag());
} catch (RemoteException ex) {
+ runOnBackgroundThread(() -> executor.execute(
+ () -> callback.onError(CellInfoCallback.ERROR_MODEM_ERROR, ex)));
}
}
@@ -5966,7 +6012,14 @@
@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 @@
}
}, getOpPackageName(), getAttributionTag(), workSource);
} catch (RemoteException ex) {
+ runOnBackgroundThread(() -> executor.execute(
+ () -> callback.onError(CellInfoCallback.ERROR_MODEM_ERROR, ex)));
}
}
@@ -6960,14 +7015,21 @@
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 @@
}
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 @@
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 @@
try {
IOns iOpportunisticNetworkService = getIOns();
if (iOpportunisticNetworkService == null) {
- if (executor == null || callback == null) {
- return;
+ 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!");
}
- 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);
- }
- return;
}
ISetOpportunisticDataCallback callbackStub = new ISetOpportunisticDataCallback.Stub() {
@Override
@@ -12812,9 +12873,18 @@
.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 @@
@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 @@
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/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java
index b503733..08f5613 100644
--- a/telephony/java/android/telephony/data/ApnSetting.java
+++ b/telephony/java/android/telephony/data/ApnSetting.java
@@ -114,11 +114,15 @@
public static final int TYPE_MCX = ApnTypes.MCX;
/** APN type for XCAP. */
public static final int TYPE_XCAP = ApnTypes.XCAP;
+ /** APN type for VSIM. */
+ public static final int TYPE_VSIM = 1 << 12; // TODO: Refer to ApnTypes.VSIM
+ /** APN type for BIP. */
+ public static final int TYPE_BIP = 1 << 13; // TODO: Refer to ApnTypes.BIP
/**
* APN type for ENTERPRISE.
* @hide
*/
- public static final int TYPE_ENTERPRISE = TYPE_XCAP << 1;
+ public static final int TYPE_ENTERPRISE = TYPE_BIP << 1;
/** @hide */
@IntDef(flag = true, prefix = {"TYPE_"}, value = {
@@ -134,6 +138,8 @@
TYPE_EMERGENCY,
TYPE_MCX,
TYPE_XCAP,
+ TYPE_BIP,
+ TYPE_VSIM,
TYPE_ENTERPRISE,
})
@Retention(RetentionPolicy.SOURCE)
@@ -174,6 +180,8 @@
TYPE_MMS_STRING,
TYPE_SUPL_STRING,
TYPE_XCAP_STRING,
+ TYPE_VSIM_STRING,
+ TYPE_BIP_STRING,
TYPE_ENTERPRISE_STRING,
}, prefix = "TYPE_", suffix = "_STRING")
@Retention(RetentionPolicy.SOURCE)
@@ -315,8 +323,33 @@
@SystemApi
public static final String TYPE_XCAP_STRING = "xcap";
+
+
+ /**
+ * APN type for Virtual SIM service.
+ *
+ * Note: String representations of APN types are intended for system apps to communicate with
+ * modem components or carriers. Non-system apps should use the integer variants instead.
+ * @hide
+ */
+ @SystemApi
+ public static final String TYPE_VSIM_STRING = "vsim";
+
+ /**
+ * APN type for Bearer Independent Protocol.
+ *
+ * Note: String representations of APN types are intended for system apps to communicate with
+ * modem components or carriers. Non-system apps should use the integer variants instead.
+ * @hide
+ */
+ @SystemApi
+ public static final String TYPE_BIP_STRING = "bip";
+
/**
* APN type for ENTERPRISE traffic.
+ *
+ * Note: String representations of APN types are intended for system apps to communicate with
+ * modem components or carriers. Non-system apps should use the integer variants instead.
* @hide
*/
public static final String TYPE_ENTERPRISE_STRING = "enterprise";
@@ -401,6 +434,8 @@
APN_TYPE_STRING_MAP.put(TYPE_MCX_STRING, TYPE_MCX);
APN_TYPE_STRING_MAP.put(TYPE_XCAP_STRING, TYPE_XCAP);
APN_TYPE_STRING_MAP.put(TYPE_ENTERPRISE_STRING, TYPE_ENTERPRISE);
+ APN_TYPE_STRING_MAP.put(TYPE_VSIM_STRING, TYPE_VSIM);
+ APN_TYPE_STRING_MAP.put(TYPE_BIP_STRING, TYPE_BIP);
APN_TYPE_INT_MAP = new ArrayMap<>();
APN_TYPE_INT_MAP.put(TYPE_DEFAULT, TYPE_DEFAULT_STRING);
@@ -416,6 +451,8 @@
APN_TYPE_INT_MAP.put(TYPE_MCX, TYPE_MCX_STRING);
APN_TYPE_INT_MAP.put(TYPE_XCAP, TYPE_XCAP_STRING);
APN_TYPE_INT_MAP.put(TYPE_ENTERPRISE, TYPE_ENTERPRISE_STRING);
+ APN_TYPE_INT_MAP.put(TYPE_VSIM, TYPE_VSIM_STRING);
+ APN_TYPE_INT_MAP.put(TYPE_BIP, TYPE_BIP_STRING);
PROTOCOL_STRING_MAP = new ArrayMap<>();
PROTOCOL_STRING_MAP.put("IP", PROTOCOL_IP);
@@ -2194,7 +2231,7 @@
public ApnSetting build() {
if ((mApnTypeBitmask & (TYPE_DEFAULT | TYPE_MMS | TYPE_SUPL | TYPE_DUN | TYPE_HIPRI
| TYPE_FOTA | TYPE_IMS | TYPE_CBS | TYPE_IA | TYPE_EMERGENCY | TYPE_MCX
- | TYPE_XCAP | TYPE_ENTERPRISE)) == 0
+ | TYPE_XCAP | TYPE_VSIM | TYPE_BIP | TYPE_ENTERPRISE)) == 0
|| TextUtils.isEmpty(mApnName) || TextUtils.isEmpty(mEntryName)) {
return null;
}
diff --git a/telephony/java/android/telephony/data/DataCallResponse.java b/telephony/java/android/telephony/data/DataCallResponse.java
index a5e5ab01..ad57b91 100644
--- a/telephony/java/android/telephony/data/DataCallResponse.java
+++ b/telephony/java/android/telephony/data/DataCallResponse.java
@@ -70,6 +70,7 @@
/** {@hide} */
@IntDef(prefix = "HANDOVER_FAILURE_MODE_", value = {
+ HANDOVER_FAILURE_MODE_UNKNOWN,
HANDOVER_FAILURE_MODE_LEGACY,
HANDOVER_FAILURE_MODE_DO_FALLBACK,
HANDOVER_FAILURE_MODE_NO_FALLBACK_RETRY_HANDOVER,
diff --git a/telephony/java/android/telephony/ims/RcsConfig.java b/telephony/java/android/telephony/ims/RcsConfig.java
index 07e95cc..8a31211 100644
--- a/telephony/java/android/telephony/ims/RcsConfig.java
+++ b/telephony/java/android/telephony/ims/RcsConfig.java
@@ -48,6 +48,9 @@
private static final String LOG_TAG = "RcsConfig";
private static final boolean DBG = Build.IS_ENG;
+ // Tag for Rcs Volte single registration defined in RCC.07 A.1.6.2
+ private static final String TAG_SINGLE_REGISTRATION = "rcsVolteSingleRegistration";
+
private final HashMap<String, String> mValues = new HashMap<>();
private RcsConfig(HashMap<String, String> values) {
@@ -145,6 +148,14 @@
return mValues.containsKey(tag);
}
+ /**
+ * Check whether Rcs Volte single registration is supported by the config.
+ */
+ public boolean isRcsVolteSingleRegistrationSupported() {
+ return getBoolean(TAG_SINGLE_REGISTRATION, false)
+ || getInteger(TAG_SINGLE_REGISTRATION, 0) != 0;
+ }
+
@Override
public String toString() {
final StringBuilder sb = new StringBuilder();
diff --git a/telephony/java/android/telephony/ims/RcsContactUceCapability.java b/telephony/java/android/telephony/ims/RcsContactUceCapability.java
index a133ead..acfa133 100644
--- a/telephony/java/android/telephony/ims/RcsContactUceCapability.java
+++ b/telephony/java/android/telephony/ims/RcsContactUceCapability.java
@@ -282,20 +282,6 @@
* <p>
* Note: this is only populated if {@link #getCapabilityMechanism} is
* {@link RcsContactUceCapability#CAPABILITY_MECHANISM_OPTIONS}
- * @hide
- */
- public @NonNull List<String> getOptionsFeatureTags() {
- if (mCapabilityMechanism != CAPABILITY_MECHANISM_OPTIONS) {
- return Collections.emptyList();
- }
- return Collections.unmodifiableList(new ArrayList<>(mFeatureTags));
- }
-
- /**
- * @return The feature tags present in the OPTIONS response from the network.
- * <p>
- * Note: this is only populated if {@link #getCapabilityMechanism} is
- * {@link RcsContactUceCapability#CAPABILITY_MECHANISM_OPTIONS}
*/
public @NonNull Set<String> getFeatureTags() {
if (mCapabilityMechanism != CAPABILITY_MECHANISM_OPTIONS) {
diff --git a/telephony/java/android/telephony/ims/SipMessage.java b/telephony/java/android/telephony/ims/SipMessage.java
index ad6d73c..d21fcab 100644
--- a/telephony/java/android/telephony/ims/SipMessage.java
+++ b/telephony/java/android/telephony/ims/SipMessage.java
@@ -24,6 +24,7 @@
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
+import android.text.TextUtils;
import com.android.internal.telephony.SipMessageParsingUtils;
@@ -60,14 +61,19 @@
*/
public SipMessage(@NonNull String startLine, @NonNull String headerSection,
@NonNull byte[] content) {
- if (startLine == null || headerSection == null || content == null) {
- throw new IllegalArgumentException("One or more null parameters entered");
- }
+ Objects.requireNonNull(startLine, "Required parameter is null: startLine");
+ Objects.requireNonNull(headerSection, "Required parameter is null: headerSection");
+ Objects.requireNonNull(content, "Required parameter is null: content");
+
mStartLine = startLine;
mHeaderSection = headerSection;
mContent = content;
mViaBranchParam = SipMessageParsingUtils.getTransactionId(mHeaderSection);
+ if (TextUtils.isEmpty(mViaBranchParam)) {
+ throw new IllegalArgumentException("header section MUST contain a branch parameter "
+ + "inside of the Via header.");
+ }
mCallIdParam = SipMessageParsingUtils.getCallId(mHeaderSection);
}
@@ -107,11 +113,9 @@
/**
* @return the branch parameter enclosed in the Via header key's value. See RFC 3261 section
- * 20.42 for more information on the Via header. If {@code null}, then there was either no
- * Via parameter found in this SIP message's headers or no branch parameter found in the
- * Via header.
+ * 20.42 for more information on the Via header.
*/
- public @Nullable String getViaBranchParameter() {
+ public @NonNull String getViaBranchParameter() {
return mViaBranchParam;
}
@@ -200,7 +204,9 @@
/**
* @return the UTF-8 encoded SIP message.
+ * @deprecated Use {@link #toEncodedMessage} instead
*/
+ @Deprecated
public @NonNull byte[] getEncodedMessage() {
byte[] header = new StringBuilder()
.append(mStartLine)
@@ -212,4 +218,26 @@
System.arraycopy(mContent, 0, sipMessage, header.length, mContent.length);
return sipMessage;
}
+
+ /**
+ * According RFC-3261 section 7, SIP is a text protocol and uses the UTF-8 charset. Its format
+ * consists of a start-line, one or more header fields, an empty line indicating the end of the
+ * header fields, and an optional message-body.
+ *
+ * <p>
+ * Returns a byte array with UTF-8 format representation of the encoded SipMessage.
+ *
+ * @return byte array with UTF-8 format representation of the encoded SipMessage.
+ */
+ public @NonNull byte[] toEncodedMessage() {
+ byte[] header = new StringBuilder()
+ .append(mStartLine)
+ .append(mHeaderSection)
+ .append(CRLF)
+ .toString().getBytes(UTF_8);
+ byte[] sipMessage = new byte[header.length + mContent.length];
+ System.arraycopy(header, 0, sipMessage, 0, header.length);
+ System.arraycopy(mContent, 0, sipMessage, header.length, mContent.length);
+ return sipMessage;
+ }
}
diff --git a/telephony/java/android/telephony/ims/aidl/SipDelegateAidlWrapper.java b/telephony/java/android/telephony/ims/aidl/SipDelegateAidlWrapper.java
index 739946b..5c9ec53 100644
--- a/telephony/java/android/telephony/ims/aidl/SipDelegateAidlWrapper.java
+++ b/telephony/java/android/telephony/ims/aidl/SipDelegateAidlWrapper.java
@@ -28,8 +28,6 @@
import android.telephony.ims.SipDelegateManager;
import android.telephony.ims.SipMessage;
import android.telephony.ims.stub.SipDelegate;
-import android.text.TextUtils;
-import android.util.Log;
import java.util.ArrayList;
import java.util.Set;
@@ -187,11 +185,6 @@
private void notifyLocalMessageFailedToBeReceived(SipMessage m, int reason) {
String transactionId = m.getViaBranchParameter();
- if (TextUtils.isEmpty(transactionId)) {
- Log.w(LOG_TAG, "failure to parse SipMessage.");
- throw new IllegalArgumentException("Malformed SipMessage, can not determine "
- + "transaction ID.");
- }
SipDelegate d = mDelegate;
if (d != null) {
mExecutor.execute(() -> d.notifyMessageReceiveError(transactionId, reason));
diff --git a/telephony/java/android/telephony/ims/aidl/SipDelegateConnectionAidlWrapper.java b/telephony/java/android/telephony/ims/aidl/SipDelegateConnectionAidlWrapper.java
index 3cd2726..ad02fe5 100644
--- a/telephony/java/android/telephony/ims/aidl/SipDelegateConnectionAidlWrapper.java
+++ b/telephony/java/android/telephony/ims/aidl/SipDelegateConnectionAidlWrapper.java
@@ -28,7 +28,6 @@
import android.telephony.ims.stub.DelegateConnectionMessageCallback;
import android.telephony.ims.stub.DelegateConnectionStateCallback;
import android.telephony.ims.stub.SipDelegate;
-import android.text.TextUtils;
import android.util.ArraySet;
import android.util.Log;
@@ -267,12 +266,6 @@
private void notifyLocalMessageFailedToSend(SipMessage m, int reason) {
String transactionId = m.getViaBranchParameter();
- if (TextUtils.isEmpty(transactionId)) {
- Log.w(LOG_TAG, "sendMessage detected a malformed SipMessage and can not get a "
- + "transaction ID.");
- throw new IllegalArgumentException("Could not send SipMessage due to malformed header");
- }
- mExecutor.execute(() ->
- mMessageCallback.onMessageSendFailure(transactionId, reason));
+ mExecutor.execute(() -> mMessageCallback.onMessageSendFailure(transactionId, reason));
}
}
diff --git a/telephony/java/android/telephony/ims/feature/RcsFeature.java b/telephony/java/android/telephony/ims/feature/RcsFeature.java
index 6315b24..b384e50 100644
--- a/telephony/java/android/telephony/ims/feature/RcsFeature.java
+++ b/telephony/java/android/telephony/ims/feature/RcsFeature.java
@@ -391,6 +391,7 @@
* 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 @@
}
/**
+ * 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 25b9446..57616d35 100644
--- a/telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java
@@ -356,12 +356,13 @@
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 @@
}
/**
+ * 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
@@ -434,30 +441,6 @@
* @param contactUri The URI of the remote user that we wish to get the capabilities of.
* @param myCapabilities The capabilities of this device to send to the remote user.
* @param callback The callback of this request which is sent from the remote user.
- * @hide
- */
- // executor used is defined in the constructor.
- @SuppressLint("ExecutorRegistration")
- public void sendOptionsCapabilityRequest(@NonNull Uri contactUri,
- @NonNull List<String> myCapabilities, @NonNull OptionsResponseCallback callback) {
- // Stub - to be implemented by service
- Log.w(LOG_TAG, "sendOptionsCapabilityRequest called with no implementation.");
- try {
- callback.onCommandError(COMMAND_CODE_NOT_SUPPORTED);
- } catch (ImsException e) {
- // Do not do anything, this is a stub implementation.
- }
- }
-
- /**
- * Push one's own capabilities to a remote user via the SIP OPTIONS presence exchange mechanism
- * in order to receive the capabilities of the remote user in response.
- * <p>
- * The implementer must use {@link OptionsResponseCallback} to send the response of
- * this query from the network back to the framework.
- * @param contactUri The URI of the remote user that we wish to get the capabilities of.
- * @param myCapabilities The capabilities of this device to send to the remote user.
- * @param callback The callback of this request which is sent from the remote user.
*/
// executor used is defined in the constructor.
@SuppressLint("ExecutorRegistration")
diff --git a/tests/SilkFX/OWNERS b/tests/SilkFX/OWNERS
new file mode 100644
index 0000000..c88a9f8
--- /dev/null
+++ b/tests/SilkFX/OWNERS
@@ -0,0 +1 @@
+include /libs/hwui/OWNERS
diff --git a/tests/net/common/java/android/net/NetworkAgentConfigTest.kt b/tests/net/common/java/android/net/NetworkAgentConfigTest.kt
index a4d8353..1e54093 100644
--- a/tests/net/common/java/android/net/NetworkAgentConfigTest.kt
+++ b/tests/net/common/java/android/net/NetworkAgentConfigTest.kt
@@ -19,6 +19,7 @@
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 @@
setPartialConnectivityAcceptable(false)
setUnvalidatedConnectivityAcceptable(true)
}.build()
- assertParcelSane(config, 10)
+ if (isAtLeastS()) {
+ // From S, the config will have 12 items
+ assertParcelSane(config, 12)
+ } else {
+ // For R or below, the config will have 10 items
+ assertParcelSane(config, 10)
+ }
}
@Test @IgnoreUpTo(Build.VERSION_CODES.Q)
diff --git a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
index 1f50e31..e7718b5 100644
--- a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
+++ b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
@@ -38,14 +38,12 @@
import static android.net.NetworkCapabilities.REDACT_FOR_ACCESS_FINE_LOCATION;
import static android.net.NetworkCapabilities.REDACT_FOR_LOCAL_MAC_ADDRESS;
import static android.net.NetworkCapabilities.REDACT_FOR_NETWORK_SETTINGS;
-import static android.net.NetworkCapabilities.RESTRICTED_CAPABILITIES;
import static android.net.NetworkCapabilities.SIGNAL_STRENGTH_UNSPECIFIED;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_TEST;
import static android.net.NetworkCapabilities.TRANSPORT_VPN;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI_AWARE;
-import static android.net.NetworkCapabilities.UNRESTRICTED_CAPABILITIES;
import static android.os.Process.INVALID_UID;
import static com.android.modules.utils.build.SdkLevel.isAtLeastR;
@@ -103,20 +101,6 @@
@Test
public void testMaybeMarkCapabilitiesRestricted() {
- // verify EIMS is restricted
- assertEquals((1 << NET_CAPABILITY_EIMS) & RESTRICTED_CAPABILITIES,
- (1 << NET_CAPABILITY_EIMS));
-
- // verify CBS is also restricted
- assertEquals((1 << NET_CAPABILITY_CBS) & RESTRICTED_CAPABILITIES,
- (1 << NET_CAPABILITY_CBS));
-
- // verify default is not restricted
- assertEquals((1 << NET_CAPABILITY_INTERNET) & RESTRICTED_CAPABILITIES, 0);
-
- // just to see
- assertEquals(RESTRICTED_CAPABILITIES & UNRESTRICTED_CAPABILITIES, 0);
-
// check that internet does not get restricted
NetworkCapabilities netCap = new NetworkCapabilities();
netCap.addCapability(NET_CAPABILITY_INTERNET);
@@ -985,26 +969,6 @@
assertNotEquals(-50, nc.getSignalStrength());
}
- @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
- public void testDeduceRestrictedCapability() {
- final NetworkCapabilities nc = new NetworkCapabilities();
- // Default capabilities don't have restricted capability.
- assertFalse(nc.deduceRestrictedCapability());
- // If there is a force restricted capability, then the network capabilities is restricted.
- nc.addCapability(NET_CAPABILITY_OEM_PAID);
- nc.addCapability(NET_CAPABILITY_INTERNET);
- assertTrue(nc.deduceRestrictedCapability());
- // Except for the force restricted capability, if there is any unrestricted capability in
- // capabilities, then the network capabilities is not restricted.
- nc.removeCapability(NET_CAPABILITY_OEM_PAID);
- nc.addCapability(NET_CAPABILITY_CBS);
- assertFalse(nc.deduceRestrictedCapability());
- // Except for the force restricted capability, the network capabilities will only be treated
- // as restricted when there is no any unrestricted capability.
- nc.removeCapability(NET_CAPABILITY_INTERNET);
- assertTrue(nc.deduceRestrictedCapability());
- }
-
private void assertNoTransport(NetworkCapabilities nc) {
for (int i = MIN_TRANSPORT; i <= MAX_TRANSPORT; i++) {
assertFalse(nc.hasTransport(i));
diff --git a/tests/net/integration/AndroidManifest.xml b/tests/net/integration/AndroidManifest.xml
index f5a4234..db18500 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 36f205b..6cbdd25 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.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/android/net/VpnTransportInfoTest.java b/tests/net/java/android/net/VpnTransportInfoTest.java
index b7a42ec..fee65f0 100644
--- a/tests/net/java/android/net/VpnTransportInfoTest.java
+++ b/tests/net/java/android/net/VpnTransportInfoTest.java
@@ -16,6 +16,9 @@
package android.net;
+import static android.net.NetworkCapabilities.REDACT_FOR_NETWORK_SETTINGS;
+import static android.net.NetworkCapabilities.REDACT_NONE;
+
import static com.android.testutils.ParcelUtils.assertParcelSane;
import static org.junit.Assert.assertEquals;
@@ -33,23 +36,33 @@
@Test
public void testParceling() {
- VpnTransportInfo v = new VpnTransportInfo(VpnManager.TYPE_VPN_PLATFORM);
- assertParcelSane(v, 1 /* fieldCount */);
+ VpnTransportInfo v = new VpnTransportInfo(VpnManager.TYPE_VPN_PLATFORM, "12345");
+ assertParcelSane(v, 2 /* fieldCount */);
}
@Test
public void testEqualsAndHashCode() {
- VpnTransportInfo v1 = new VpnTransportInfo(VpnManager.TYPE_VPN_PLATFORM);
- VpnTransportInfo v2 = new VpnTransportInfo(VpnManager.TYPE_VPN_SERVICE);
- VpnTransportInfo v3 = new VpnTransportInfo(VpnManager.TYPE_VPN_PLATFORM);
- VpnTransportInfo v4 = new VpnTransportInfo(VpnManager.TYPE_VPN_LEGACY);
- VpnTransportInfo v5 = new VpnTransportInfo(VpnManager.TYPE_VPN_OEM);
+ String session1 = "12345";
+ String session2 = "6789";
+ VpnTransportInfo v11 = new VpnTransportInfo(VpnManager.TYPE_VPN_PLATFORM, session1);
+ VpnTransportInfo v12 = new VpnTransportInfo(VpnManager.TYPE_VPN_SERVICE, session1);
+ VpnTransportInfo v13 = new VpnTransportInfo(VpnManager.TYPE_VPN_PLATFORM, session1);
+ VpnTransportInfo v14 = new VpnTransportInfo(VpnManager.TYPE_VPN_LEGACY, session1);
+ VpnTransportInfo v15 = new VpnTransportInfo(VpnManager.TYPE_VPN_OEM, session1);
+ VpnTransportInfo v21 = new VpnTransportInfo(VpnManager.TYPE_VPN_LEGACY, session2);
- assertNotEquals(v1, v2);
- assertNotEquals(v3, v4);
- assertNotEquals(v4, v5);
+ VpnTransportInfo v31 = v11.makeCopy(REDACT_FOR_NETWORK_SETTINGS);
+ VpnTransportInfo v32 = v13.makeCopy(REDACT_FOR_NETWORK_SETTINGS);
- assertEquals(v1, v3);
- assertEquals(v1.hashCode(), v3.hashCode());
+ assertNotEquals(v11, v12);
+ assertNotEquals(v13, v14);
+ assertNotEquals(v14, v15);
+ assertNotEquals(v14, v21);
+
+ assertEquals(v11, v13);
+ assertEquals(v31, v32);
+ assertEquals(v11.hashCode(), v13.hashCode());
+ assertEquals(REDACT_FOR_NETWORK_SETTINGS, v32.getApplicableRedactions());
+ assertEquals(session1, v15.makeCopy(REDACT_NONE).sessionId);
}
-}
\ No newline at end of file
+}
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 8938c1d..e050495 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -18,7 +18,12 @@
import static android.Manifest.permission.CHANGE_NETWORK_STATE;
import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS;
+import static android.Manifest.permission.NETWORK_FACTORY;
+import static android.Manifest.permission.NETWORK_SETTINGS;
import static android.app.PendingIntent.FLAG_IMMUTABLE;
+import static android.content.Intent.ACTION_PACKAGE_ADDED;
+import static android.content.Intent.ACTION_PACKAGE_REMOVED;
+import static android.content.Intent.ACTION_PACKAGE_REPLACED;
import static android.content.Intent.ACTION_USER_ADDED;
import static android.content.Intent.ACTION_USER_REMOVED;
import static android.content.Intent.ACTION_USER_UNLOCKED;
@@ -31,6 +36,7 @@
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;
@@ -57,6 +63,7 @@
import static android.net.INetworkMonitor.NETWORK_VALIDATION_PROBE_PRIVDNS;
import static android.net.INetworkMonitor.NETWORK_VALIDATION_RESULT_PARTIAL;
import static android.net.INetworkMonitor.NETWORK_VALIDATION_RESULT_VALID;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_BIP;
import static android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL;
import static android.net.NetworkCapabilities.NET_CAPABILITY_CBS;
import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
@@ -83,6 +90,7 @@
import static android.net.NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_VSIM;
import static android.net.NetworkCapabilities.NET_CAPABILITY_WIFI_P2P;
import static android.net.NetworkCapabilities.NET_CAPABILITY_XCAP;
import static android.net.NetworkCapabilities.REDACT_FOR_ACCESS_FINE_LOCATION;
@@ -575,6 +583,7 @@
final UserManager umMock = createContextAsUser(userHandle, 0 /* flags */)
.getSystemService(UserManager.class);
doReturn(value).when(umMock).isManagedProfile();
+ doReturn(value).when(mUserManager).isManagedProfile(eq(userHandle.getIdentifier()));
}
@Override
@@ -715,6 +724,9 @@
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 +781,24 @@
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 +1000,18 @@
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;
+ }
}
/**
@@ -1193,10 +1235,12 @@
if (mAgentRegistered) throw new IllegalStateException("already registered");
updateState(NetworkInfo.DetailedState.CONNECTING, "registerAgent");
mConfig = new VpnConfig();
+ mConfig.session = "MySession12345";
setUids(uids);
if (!isAlwaysMetered) mNetworkCapabilities.addCapability(NET_CAPABILITY_NOT_METERED);
mInterface = VPN_IFNAME;
- mNetworkCapabilities.setTransportInfo(new VpnTransportInfo(getActiveVpnType()));
+ mNetworkCapabilities.setTransportInfo(new VpnTransportInfo(getActiveVpnType(),
+ mConfig.session));
mMockNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN, lp,
mNetworkCapabilities);
mMockNetworkAgent.waitForIdle(TIMEOUT_MS);
@@ -1373,10 +1417,21 @@
}
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 +1626,7 @@
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 +2493,7 @@
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 +2501,7 @@
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 +2509,7 @@
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 */);
}
@@ -2746,10 +2800,14 @@
}
private void grantUsingBackgroundNetworksPermissionForUid(final int uid) throws Exception {
- final String myPackageName = mContext.getPackageName();
- when(mPackageManager.getPackageInfo(eq(myPackageName), eq(GET_PERMISSIONS)))
+ grantUsingBackgroundNetworksPermissionForUid(uid, mContext.getPackageName());
+ }
+
+ private void grantUsingBackgroundNetworksPermissionForUid(
+ final int uid, final String packageName) throws Exception {
+ when(mPackageManager.getPackageInfo(eq(packageName), eq(GET_PERMISSIONS)))
.thenReturn(buildPackageInfo(true, uid));
- mService.mPermissionMonitor.onPackageAdded(myPackageName, uid);
+ mService.mPermissionMonitor.onPackageAdded(packageName, uid);
}
@Test
@@ -2799,6 +2857,94 @@
}
@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)
@@ -2898,10 +3044,11 @@
// Verify NOT_RESTRICTED is set appropriately
final NetworkCapabilities nc = new NetworkRequest.Builder().addCapability(capability)
.build().networkCapabilities;
- if (capability == NET_CAPABILITY_CBS || capability == NET_CAPABILITY_DUN ||
- capability == NET_CAPABILITY_EIMS || capability == NET_CAPABILITY_FOTA ||
- capability == NET_CAPABILITY_IA || capability == NET_CAPABILITY_IMS ||
- capability == NET_CAPABILITY_RCS || capability == NET_CAPABILITY_XCAP
+ if (capability == NET_CAPABILITY_CBS || capability == NET_CAPABILITY_DUN
+ || capability == NET_CAPABILITY_EIMS || capability == NET_CAPABILITY_FOTA
+ || capability == NET_CAPABILITY_IA || capability == NET_CAPABILITY_IMS
+ || capability == NET_CAPABILITY_RCS || capability == NET_CAPABILITY_XCAP
+ || capability == NET_CAPABILITY_VSIM || capability == NET_CAPABILITY_BIP
|| capability == NET_CAPABILITY_ENTERPRISE) {
assertFalse(nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
} else {
@@ -3011,6 +3158,8 @@
tryNetworkFactoryRequests(NET_CAPABILITY_INTERNET);
tryNetworkFactoryRequests(NET_CAPABILITY_TRUSTED);
tryNetworkFactoryRequests(NET_CAPABILITY_NOT_VPN);
+ tryNetworkFactoryRequests(NET_CAPABILITY_VSIM);
+ tryNetworkFactoryRequests(NET_CAPABILITY_BIP);
// Skipping VALIDATED and CAPTIVE_PORTAL as they're disallowed.
}
@@ -3439,8 +3588,7 @@
@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 +3622,7 @@
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 +4056,7 @@
@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 +4215,7 @@
() -> 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 +5536,11 @@
}
@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 +5589,33 @@
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 +5642,30 @@
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 +6658,7 @@
@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 +7150,7 @@
@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 +7236,7 @@
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 +7471,20 @@
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 +7492,16 @@
.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 +7509,23 @@
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 +7533,8 @@
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 +7544,8 @@
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 +7555,10 @@
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 +7566,7 @@
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 +7574,13 @@
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 +7590,14 @@
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 +7724,7 @@
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 +7960,7 @@
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 +8149,12 @@
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 +9090,7 @@
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,
@@ -8927,7 +9157,7 @@
final int expectedOwnerUidWithoutIncludeFlag =
shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag
- ? Process.myUid() : INVALID_UID;
+ ? myUid : INVALID_UID;
assertEquals(expectedOwnerUidWithoutIncludeFlag, getOwnerUidNetCapsPermission(
myUid, myUid, false /* includeLocationSensitiveInfo */));
@@ -8946,22 +9176,26 @@
}
+ private void verifyOwnerUidAndTransportInfoNetCapsPermissionPreS() {
+ verifyOwnerUidAndTransportInfoNetCapsPermission(
+ // Ensure that owner uid is included even if the request asks to remove it (which is
+ // the default) since the app has necessary permissions and targetSdk < S.
+ true, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */
+ true, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */
+ // Ensure that location info is removed if the request asks to remove it even if the
+ // app has necessary permissions.
+ false, /* shouldInclLocationSensitiveTransportInfoWithoutIncludeFlag */
+ true /* shouldInclLocationSensitiveTransportInfoWithIncludeFlag */
+ );
+ }
+
@Test
- public void testCreateWithLocationInfoSanitizedWithFineLocationAfterQ()
+ public void testCreateWithLocationInfoSanitizedWithFineLocationAfterQPreS()
throws Exception {
setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION);
- verifyOwnerUidAndTransportInfoNetCapsPermission(
- // Ensure that we include owner uid even if the request asks to remove it since the
- // app has necessary permissions and targetSdk < S.
- true, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */
- true, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */
- false, /* shouldInclLocationSensitiveTransportInfoWithoutIncludeFlag */
- // Ensure that we remove location info if the request asks to remove it even if the
- // app has necessary permissions.
- true /* shouldInclLocationSensitiveTransportInfoWithIncludeFlag */
- );
+ verifyOwnerUidAndTransportInfoNetCapsPermissionPreS();
}
@Test
@@ -8970,16 +9204,7 @@
setupLocationPermissions(Build.VERSION_CODES.R, true, AppOpsManager.OPSTR_FINE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION);
- verifyOwnerUidAndTransportInfoNetCapsPermission(
- // Ensure that we include owner uid even if the request asks to remove it since the
- // app has necessary permissions and targetSdk < S.
- true, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */
- true, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */
- false, /* shouldInclLocationSensitiveTransportInfoWithoutIncludeFlag */
- // Ensure that we remove location info if the request asks to remove it even if the
- // app has necessary permissions.
- true /* shouldInclLocationSensitiveTransportInfoWithIncludeFlag */
- );
+ verifyOwnerUidAndTransportInfoNetCapsPermissionPreS();
}
@Test
@@ -8990,13 +9215,13 @@
Manifest.permission.ACCESS_FINE_LOCATION);
verifyOwnerUidAndTransportInfoNetCapsPermission(
- // Ensure that we owner UID if the request asks us to remove it even if the app
- // has necessary permissions since targetSdk >= S.
+ // Ensure that the owner UID is removed if the request asks us to remove it even
+ // if the app has necessary permissions since targetSdk >= S.
false, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */
true, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */
- false, /* shouldInclLocationSensitiveTransportInfoWithoutIncludeFlag */
- // Ensure that we remove location info if the request asks to remove it even if the
+ // Ensure that location info is removed if the request asks to remove it even if the
// app has necessary permissions.
+ false, /* shouldInclLocationSensitiveTransportInfoWithoutIncludeFlag */
true /* shouldInclLocationSensitiveTransportInfoWithIncludeFlag */
);
}
@@ -9007,15 +9232,15 @@
setupLocationPermissions(Build.VERSION_CODES.P, true, AppOpsManager.OPSTR_COARSE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION);
+ verifyOwnerUidAndTransportInfoNetCapsPermissionPreS();
+ }
+
+ private void verifyOwnerUidAndTransportInfoNetCapsNotIncluded() {
verifyOwnerUidAndTransportInfoNetCapsPermission(
- // Ensure that we owner UID if the request asks us to remove it even if the app
- // has necessary permissions since targetSdk >= S.
- true, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */
- true, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */
+ false, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */
+ false, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */
false, /* shouldInclLocationSensitiveTransportInfoWithoutIncludeFlag */
- // Ensure that we remove location info if the request asks to remove it even if the
- // app has necessary permissions.
- true /* shouldInclLocationSensitiveTransportInfoWithIncludeFlag */
+ false /* shouldInclLocationSensitiveTransportInfoWithIncludeFlag */
);
}
@@ -9025,12 +9250,7 @@
setupLocationPermissions(Build.VERSION_CODES.Q, false, AppOpsManager.OPSTR_FINE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION);
- verifyOwnerUidAndTransportInfoNetCapsPermission(
- false, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */
- false, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */
- false, /* shouldInclLocationSensitiveTransportInfoWithoutIncludeFlag */
- false /* shouldInclLocationSensitiveTransportInfoWithIncludeFlag */
- );
+ verifyOwnerUidAndTransportInfoNetCapsNotIncluded();
}
@Test
@@ -9052,26 +9272,17 @@
setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_COARSE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION);
- verifyOwnerUidAndTransportInfoNetCapsPermission(
- false, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */
- false, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */
- false, /* shouldInclLocationSensitiveTransportInfoWithoutIncludeFlag */
- false /* shouldInclLocationSensitiveTransportInfoWithIncludeFlag */
- );
+ verifyOwnerUidAndTransportInfoNetCapsNotIncluded();
}
@Test
- public void testCreateWithLocationInfoSanitizedWithoutLocationPermission()
+ public void testCreateWithLocationInfoSanitizedWithCoarseLocationAfterS()
throws Exception {
// Test that not having fine location permission leads to sanitization.
- setupLocationPermissions(Build.VERSION_CODES.Q, true, null /* op */, null /* perm */);
+ setupLocationPermissions(Build.VERSION_CODES.S, true, AppOpsManager.OPSTR_COARSE_LOCATION,
+ Manifest.permission.ACCESS_COARSE_LOCATION);
- verifyOwnerUidAndTransportInfoNetCapsPermission(
- false, /* shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag */
- false, /* shouldInclLocationSensitiveOwnerUidWithIncludeFlag */
- false, /* shouldInclLocationSensitiveTransportInfoWithoutIncludeFlag */
- false /* shouldInclLocationSensitiveTransportInfoWithIncludeFlag */
- );
+ verifyOwnerUidAndTransportInfoNetCapsNotIncluded();
}
@Test
@@ -9116,7 +9327,7 @@
@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())
@@ -10039,6 +10250,12 @@
.thenReturn(applicationInfo);
}
+ private void mockGetApplicationInfoThrowsNameNotFound(@NonNull final String packageName)
+ throws Exception {
+ when(mPackageManager.getApplicationInfo(eq(packageName), anyInt()))
+ .thenThrow(new PackageManager.NameNotFoundException(packageName));
+ }
+
private void mockHasSystemFeature(@NonNull final String featureName,
@NonNull final boolean hasFeature) {
when(mPackageManager.hasSystemFeature(eq(featureName)))
@@ -10435,8 +10652,7 @@
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 +10662,7 @@
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() {
@@ -10497,15 +10712,23 @@
@NonNull final UidRangeParcel[] uidRanges,
@NonNull final String testPackageName)
throws Exception {
- mockHasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, true);
-
// These tests work off a single UID therefore using 'start' is valid.
mockGetApplicationInfo(testPackageName, uidRanges[0].start);
+ setOemNetworkPreference(networkPrefToSetup, testPackageName);
+ }
+
+ private void setOemNetworkPreference(final int networkPrefToSetup,
+ @NonNull final String... testPackageNames)
+ throws Exception {
+ mockHasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, true);
+
// Build OemNetworkPreferences object
- final OemNetworkPreferences pref = new OemNetworkPreferences.Builder()
- .addNetworkPreference(testPackageName, networkPrefToSetup)
- .build();
+ final OemNetworkPreferences.Builder builder = new OemNetworkPreferences.Builder();
+ for (final String packageName : testPackageNames) {
+ builder.addNetworkPreference(packageName, networkPrefToSetup);
+ }
+ final OemNetworkPreferences pref = builder.build();
// Act on ConnectivityService.setOemNetworkPreference()
final TestOemListenerCallback oemPrefListener = new TestOemListenerCallback();
@@ -10602,7 +10825,7 @@
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 +10873,7 @@
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 +10915,7 @@
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())));
@@ -11104,8 +11327,7 @@
// Arrange PackageManager mocks
final int secondUserTestPackageUid = UserHandle.getUid(secondUser, TEST_PACKAGE_UID);
final UidRangeParcel[] uidRangesSingleUser =
- toUidRangeStableParcels(
- uidRangesForUids(TEST_PACKAGE_UID));
+ toUidRangeStableParcels(uidRangesForUids(TEST_PACKAGE_UID));
final UidRangeParcel[] uidRangesBothUsers =
toUidRangeStableParcels(
uidRangesForUids(TEST_PACKAGE_UID, secondUserTestPackageUid));
@@ -11152,6 +11374,84 @@
false /* shouldDestroyNetwork */);
}
+ @Test
+ public void testMultilayerForPackageChangesEvaluatesCorrectly()
+ throws Exception {
+ @OemNetworkPreferences.OemNetworkPreference final int networkPref =
+ OEM_NETWORK_PREFERENCE_OEM_PAID;
+ final String packageScheme = "package:";
+
+ // Arrange PackageManager mocks
+ final String packageToInstall = "package.to.install";
+ final int packageToInstallUid = 81387;
+ final UidRangeParcel[] uidRangesSinglePackage =
+ toUidRangeStableParcels(uidRangesForUids(TEST_PACKAGE_UID));
+ mockGetApplicationInfo(TEST_PACKAGE_NAME, TEST_PACKAGE_UID);
+ mockGetApplicationInfoThrowsNameNotFound(packageToInstall);
+ setOemNetworkPreference(networkPref, TEST_PACKAGE_NAME, packageToInstall);
+ grantUsingBackgroundNetworksPermissionForUid(Binder.getCallingUid(), packageToInstall);
+
+ // Verify the starting state. No networks should be connected.
+ verifySetOemNetworkPreferenceForPreference(uidRangesSinglePackage,
+ OEM_PREF_ANY_NET_ID, 0 /* times */,
+ OEM_PREF_ANY_NET_ID, 0 /* times */,
+ false /* shouldDestroyNetwork */);
+
+ // Test that we correctly add the expected values for installed packages.
+ setOemNetworkPreferenceAgentConnected(TRANSPORT_CELLULAR, true);
+ verifySetOemNetworkPreferenceForPreference(uidRangesSinglePackage,
+ mCellNetworkAgent.getNetwork().netId, 1 /* times */,
+ OEM_PREF_ANY_NET_ID, 0 /* times */,
+ false /* shouldDestroyNetwork */);
+
+ // Set the system to recognize the package to be installed
+ mockGetApplicationInfo(packageToInstall, packageToInstallUid);
+ final UidRangeParcel[] uidRangesAllPackages =
+ toUidRangeStableParcels(uidRangesForUids(TEST_PACKAGE_UID, packageToInstallUid));
+
+ // Send a broadcast indicating a package was installed.
+ final Intent addedIntent = new Intent(ACTION_PACKAGE_ADDED);
+ addedIntent.setData(Uri.parse(packageScheme + packageToInstall));
+ processBroadcast(addedIntent);
+
+ // Test the single package is removed and the combined packages are added.
+ verifySetOemNetworkPreferenceForPreference(uidRangesAllPackages, uidRangesSinglePackage,
+ mCellNetworkAgent.getNetwork().netId, 1 /* times */,
+ mCellNetworkAgent.getNetwork().netId, 1 /* times */,
+ false /* shouldDestroyNetwork */);
+
+ // Set the system to no longer recognize the package to be installed
+ mockGetApplicationInfoThrowsNameNotFound(packageToInstall);
+
+ // Send a broadcast indicating a package was removed.
+ final Intent removedIntent = new Intent(ACTION_PACKAGE_REMOVED);
+ removedIntent.setData(Uri.parse(packageScheme + packageToInstall));
+ processBroadcast(removedIntent);
+
+ // Test the combined packages are removed and the single package is added.
+ verifySetOemNetworkPreferenceForPreference(uidRangesSinglePackage, uidRangesAllPackages,
+ mCellNetworkAgent.getNetwork().netId, 1 /* times */,
+ mCellNetworkAgent.getNetwork().netId, 1 /* times */,
+ false /* shouldDestroyNetwork */);
+
+ // Set the system to change the installed package's uid
+ final int replacedTestPackageUid = TEST_PACKAGE_UID + 1;
+ mockGetApplicationInfo(TEST_PACKAGE_NAME, replacedTestPackageUid);
+ final UidRangeParcel[] uidRangesReplacedPackage =
+ toUidRangeStableParcels(uidRangesForUids(replacedTestPackageUid));
+
+ // Send a broadcast indicating a package was replaced.
+ final Intent replacedIntent = new Intent(ACTION_PACKAGE_REPLACED);
+ replacedIntent.setData(Uri.parse(packageScheme + TEST_PACKAGE_NAME));
+ processBroadcast(replacedIntent);
+
+ // Test the original uid is removed and is replaced with the new uid.
+ verifySetOemNetworkPreferenceForPreference(uidRangesReplacedPackage, uidRangesSinglePackage,
+ mCellNetworkAgent.getNetwork().netId, 1 /* times */,
+ mCellNetworkAgent.getNetwork().netId, 1 /* times */,
+ false /* shouldDestroyNetwork */);
+ }
+
/**
* Test network priority for preference OEM_NETWORK_PREFERENCE_OEM_PAID in the following order:
* NET_CAPABILITY_NOT_METERED -> NET_CAPABILITY_OEM_PAID -> fallback
@@ -11974,4 +12274,68 @@
mCm.setProfileNetworkPreference(testHandle,
PROFILE_NETWORK_PREFERENCE_ENTERPRISE, null, null));
}
+
+ @Test
+ public void testSubIdsClearedWithoutNetworkFactoryPermission() throws Exception {
+ mServiceContext.setPermission(NETWORK_FACTORY, PERMISSION_DENIED);
+ final NetworkCapabilities nc = new NetworkCapabilities();
+ nc.setSubIds(Collections.singleton(Process.myUid()));
+
+ final NetworkCapabilities result =
+ mService.networkCapabilitiesRestrictedForCallerPermissions(
+ nc, Process.myPid(), Process.myUid());
+ assertTrue(result.getSubIds().isEmpty());
+ }
+
+ @Test
+ public void testSubIdsExistWithNetworkFactoryPermission() throws Exception {
+ mServiceContext.setPermission(NETWORK_FACTORY, PERMISSION_GRANTED);
+
+ final Set<Integer> subIds = Collections.singleton(Process.myUid());
+ final NetworkCapabilities nc = new NetworkCapabilities();
+ nc.setSubIds(subIds);
+
+ final NetworkCapabilities result =
+ mService.networkCapabilitiesRestrictedForCallerPermissions(
+ nc, Process.myPid(), Process.myUid());
+ assertEquals(subIds, result.getSubIds());
+ }
+
+ private NetworkRequest getRequestWithSubIds() {
+ return new NetworkRequest.Builder()
+ .setSubIds(Collections.singleton(Process.myUid()))
+ .build();
+ }
+
+ @Test
+ public void testNetworkRequestWithSubIdsWithNetworkFactoryPermission() throws Exception {
+ mServiceContext.setPermission(NETWORK_FACTORY, PERMISSION_GRANTED);
+ final PendingIntent pendingIntent = PendingIntent.getBroadcast(
+ mContext, 0 /* requestCode */, new Intent("a"), FLAG_IMMUTABLE);
+ final NetworkCallback networkCallback1 = new NetworkCallback();
+ final NetworkCallback networkCallback2 = new NetworkCallback();
+
+ mCm.requestNetwork(getRequestWithSubIds(), networkCallback1);
+ mCm.requestNetwork(getRequestWithSubIds(), pendingIntent);
+ mCm.registerNetworkCallback(getRequestWithSubIds(), networkCallback2);
+
+ mCm.unregisterNetworkCallback(networkCallback1);
+ mCm.releaseNetworkRequest(pendingIntent);
+ mCm.unregisterNetworkCallback(networkCallback2);
+ }
+
+ @Test
+ public void testNetworkRequestWithSubIdsWithoutNetworkFactoryPermission() throws Exception {
+ mServiceContext.setPermission(NETWORK_FACTORY, PERMISSION_DENIED);
+ final PendingIntent pendingIntent = PendingIntent.getBroadcast(
+ mContext, 0 /* requestCode */, new Intent("a"), FLAG_IMMUTABLE);
+
+ final Class<SecurityException> expected = SecurityException.class;
+ assertThrows(
+ expected, () -> mCm.requestNetwork(getRequestWithSubIds(), new NetworkCallback()));
+ assertThrows(expected, () -> mCm.requestNetwork(getRequestWithSubIds(), pendingIntent));
+ assertThrows(
+ expected,
+ () -> mCm.registerNetworkCallback(getRequestWithSubIds(), new NetworkCallback()));
+ }
}
diff --git a/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java b/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
index 8c5d1d6..8b072c4 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 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 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 @@
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 @@
// 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 @@
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 8ccea1a..50aaaee 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 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 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 @@
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 @@
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 @@
}
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 9334e2c..eeeb4fb 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.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 @@
}
@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 @@
TYPE_MOBILE);
}
+ private static NetworkStateSnapshot buildImsState(
+ String subscriberId, int subId, String ifaceName) {
+ final LinkProperties prop = new LinkProperties();
+ prop.setInterfaceName(ifaceName);
+ final NetworkCapabilities capabilities = new NetworkCapabilities();
+ capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED, true);
+ capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING, true);
+ capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_IMS, true);
+ capabilities.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
+ capabilities.setNetworkSpecifier(new TelephonyNetworkSpecifier(subId));
+ return new NetworkStateSnapshot(
+ MOBILE_NETWORK, capabilities, prop, subscriberId, TYPE_MOBILE);
+ }
+
private long getElapsedRealtime() {
return mElapsedRealtime;
}
diff --git a/tests/vcn/java/android/net/vcn/VcnConfigTest.java b/tests/vcn/java/android/net/vcn/VcnConfigTest.java
index c1ef350..7ac51b7 100644
--- a/tests/vcn/java/android/net/vcn/VcnConfigTest.java
+++ b/tests/vcn/java/android/net/vcn/VcnConfigTest.java
@@ -79,6 +79,18 @@
}
@Test
+ public void testBuilderRequiresUniqueGatewayConnectionNames() {
+ final VcnGatewayConnectionConfig config = VcnGatewayConnectionConfigTest.buildTestConfig();
+ try {
+ new VcnConfig.Builder(mContext)
+ .addGatewayConnectionConfig(config)
+ .addGatewayConnectionConfig(config);
+ fail("Expected exception due to duplicate gateway connection name");
+ } catch (IllegalArgumentException e) {
+ }
+ }
+
+ @Test
public void testBuilderAndGetters() {
final VcnConfig config = buildTestConfig(mContext);
diff --git a/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java b/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java
index 8a0c923..4ee4d61 100644
--- a/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java
+++ b/tests/vcn/java/android/net/vcn/VcnGatewayConnectionConfigTest.java
@@ -19,6 +19,7 @@
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import android.net.NetworkCapabilities;
@@ -61,13 +62,20 @@
public static final VcnControlPlaneConfig CONTROL_PLANE_CONFIG =
VcnControlPlaneIkeConfigTest.buildTestConfig();
+ public static final String GATEWAY_CONNECTION_NAME_PREFIX = "gatewayConnectionName-";
+ private static int sGatewayConnectionConfigCount = 0;
+
// Public for use in VcnGatewayConnectionTest
public static VcnGatewayConnectionConfig buildTestConfig() {
return buildTestConfigWithExposedCaps(EXPOSED_CAPS);
}
private static VcnGatewayConnectionConfig.Builder newBuilder() {
- return new VcnGatewayConnectionConfig.Builder(CONTROL_PLANE_CONFIG);
+ // Append a unique identifier to the name prefix to guarantee that all created
+ // VcnGatewayConnectionConfigs have a unique name (required by VcnConfig).
+ return new VcnGatewayConnectionConfig.Builder(
+ GATEWAY_CONNECTION_NAME_PREFIX + sGatewayConnectionConfigCount++,
+ CONTROL_PLANE_CONFIG);
}
// Public for use in VcnGatewayConnectionTest
@@ -87,9 +95,23 @@
}
@Test
+ public void testBuilderRequiresNonNullGatewayConnectionName() {
+ try {
+ new VcnGatewayConnectionConfig.Builder(
+ null /* gatewayConnectionName */, CONTROL_PLANE_CONFIG)
+ .build();
+
+ fail("Expected exception due to invalid gateway connection name");
+ } catch (NullPointerException e) {
+ }
+ }
+
+ @Test
public void testBuilderRequiresNonNullControlPlaneConfig() {
try {
- new VcnGatewayConnectionConfig.Builder(null).build();
+ new VcnGatewayConnectionConfig.Builder(
+ GATEWAY_CONNECTION_NAME_PREFIX, null /* ctrlPlaneConfig */)
+ .build();
fail("Expected exception due to invalid control plane config");
} catch (NullPointerException e) {
@@ -139,6 +161,8 @@
public void testBuilderAndGetters() {
final VcnGatewayConnectionConfig config = buildTestConfig();
+ assertTrue(config.getGatewayConnectionName().startsWith(GATEWAY_CONNECTION_NAME_PREFIX));
+
int[] exposedCaps = config.getExposedCapabilities();
Arrays.sort(exposedCaps);
assertArrayEquals(EXPOSED_CAPS, exposedCaps);
diff --git a/tests/vcn/java/android/net/vcn/VcnManagerTest.java b/tests/vcn/java/android/net/vcn/VcnManagerTest.java
index 516c206..8461de6 100644
--- a/tests/vcn/java/android/net/vcn/VcnManagerTest.java
+++ b/tests/vcn/java/android/net/vcn/VcnManagerTest.java
@@ -50,9 +50,7 @@
public class VcnManagerTest {
private static final ParcelUuid SUB_GROUP = new ParcelUuid(new UUID(0, 0));
- private static final int[] UNDERLYING_NETWORK_CAPABILITIES = {
- NetworkCapabilities.NET_CAPABILITY_IMS, NetworkCapabilities.NET_CAPABILITY_INTERNET
- };
+ private static final String GATEWAY_CONNECTION_NAME = "gatewayConnectionName";
private static final Executor INLINE_EXECUTOR = Runnable::run;
private IVcnManagementService mMockVcnManagementService;
@@ -207,13 +205,13 @@
verify(mMockStatusCallback).onStatusChanged(VCN_STATUS_CODE_ACTIVE);
cbBinder.onGatewayConnectionError(
- UNDERLYING_NETWORK_CAPABILITIES,
+ GATEWAY_CONNECTION_NAME,
VcnManager.VCN_ERROR_CODE_NETWORK_ERROR,
UnknownHostException.class.getName(),
"exception_message");
verify(mMockStatusCallback)
.onGatewayConnectionError(
- eq(UNDERLYING_NETWORK_CAPABILITIES),
+ eq(GATEWAY_CONNECTION_NAME),
eq(VcnManager.VCN_ERROR_CODE_NETWORK_ERROR),
any(UnknownHostException.class));
}
diff --git a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
index f15d420..43e6676 100644
--- a/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
+++ b/tests/vcn/java/com/android/server/VcnManagementServiceTest.java
@@ -16,9 +16,13 @@
package com.android.server;
+import static android.net.ConnectivityManager.NetworkCallback;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE;
+import static android.net.vcn.VcnManager.VCN_STATUS_CODE_SAFE_MODE;
import static android.telephony.TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
import static android.telephony.TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS;
@@ -34,8 +38,8 @@
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 +49,6 @@
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;
@@ -54,8 +57,10 @@
import android.content.Intent;
import android.net.ConnectivityManager;
import android.net.LinkProperties;
+import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkCapabilities.Transport;
+import android.net.NetworkRequest;
import android.net.TelephonyNetworkSpecifier;
import android.net.vcn.IVcnStatusCallback;
import android.net.vcn.IVcnUnderlyingNetworkPolicyListener;
@@ -63,7 +68,6 @@
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;
@@ -258,6 +262,10 @@
verify(mConnMgr).registerNetworkProvider(any(VcnNetworkProvider.class));
verify(mSubscriptionTracker).register();
+ verify(mConnMgr)
+ .registerNetworkCallback(
+ eq(new NetworkRequest.Builder().clearCapabilities().build()),
+ any(NetworkCallback.class));
}
@Test
@@ -529,17 +537,6 @@
}
@Test
- public void testSetVcnConfigInSafeModeNotifiesStatusCallback() throws Exception {
- setupSubscriptionAndStartVcn(TEST_SUBSCRIPTION_ID, TEST_UUID_2, false /* isActive */);
- mVcnMgmtSvc.registerVcnStatusCallback(TEST_UUID_2, mMockStatusCallback, TEST_PACKAGE_NAME);
- verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_SAFE_MODE);
-
- mVcnMgmtSvc.setVcnConfig(TEST_UUID_2, TEST_VCN_CONFIG, TEST_PACKAGE_NAME);
-
- verify(mMockStatusCallback).onVcnStatusChanged(VcnManager.VCN_STATUS_CODE_ACTIVE);
- }
-
- @Test
public void testClearVcnConfigRequiresNonSystemServer() throws Exception {
doReturn(Process.SYSTEM_UID).when(mMockDeps).getBinderCallingUid();
@@ -697,36 +694,35 @@
hasCarrierPrivileges);
final Vcn vcn = startAndGetVcnInstance(subGrp);
- doReturn(isVcnActive).when(vcn).isActive();
+ doReturn(isVcnActive ? VCN_STATUS_CODE_ACTIVE : VCN_STATUS_CODE_SAFE_MODE)
+ .when(vcn)
+ .getStatus();
doReturn(true)
.when(mLocationPermissionChecker)
.checkLocationPermission(eq(TEST_PACKAGE_NAME), any(), eq(TEST_UID), any());
}
+ private NetworkCapabilities.Builder getNetworkCapabilitiesBuilderForTransport(
+ int subId, int 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 ncBuilder;
+ }
+
private VcnUnderlyingNetworkPolicy startVcnAndGetPolicyForTransport(
int subId, ParcelUuid subGrp, boolean isVcnActive, int transport) {
setupSubscriptionAndStartVcn(subId, subGrp, isVcnActive);
- final NetworkCapabilities.Builder ncBuilder = new NetworkCapabilities.Builder();
- ncBuilder.addCapability(NET_CAPABILITY_NOT_VCN_MANAGED);
- if (transport == TRANSPORT_CELLULAR) {
- ncBuilder
- .addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
- .setNetworkSpecifier(new TelephonyNetworkSpecifier(TEST_SUBSCRIPTION_ID));
- } else if (transport == TRANSPORT_WIFI) {
- WifiInfo wifiInfo = mock(WifiInfo.class);
- when(wifiInfo.makeCopy(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");
- }
-
- return mVcnMgmtSvc.getUnderlyingNetworkPolicy(ncBuilder.build(), new LinkProperties());
+ return mVcnMgmtSvc.getUnderlyingNetworkPolicy(
+ getNetworkCapabilitiesBuilderForTransport(subId, transport).build(),
+ new LinkProperties());
}
@Test
@@ -788,6 +784,53 @@
true /* isRestricted */);
}
+ private void setupTrackedCarrierWifiNetwork(NetworkCapabilities caps) {
+ mVcnMgmtSvc.systemReady();
+
+ final ArgumentCaptor<NetworkCallback> captor =
+ ArgumentCaptor.forClass(NetworkCallback.class);
+ verify(mConnMgr)
+ .registerNetworkCallback(
+ eq(new NetworkRequest.Builder().clearCapabilities().build()),
+ captor.capture());
+ captor.getValue().onCapabilitiesChanged(new Network(0), caps);
+ }
+
+ @Test
+ public void testGetUnderlyingNetworkPolicyVcnWifi_unrestrictingExistingNetworkRequiresRestart()
+ throws Exception {
+ final NetworkCapabilities existingNetworkCaps =
+ getNetworkCapabilitiesBuilderForTransport(TEST_SUBSCRIPTION_ID, TRANSPORT_WIFI)
+ .removeCapability(NET_CAPABILITY_NOT_RESTRICTED)
+ .build();
+ setupTrackedCarrierWifiNetwork(existingNetworkCaps);
+
+ // Trigger test without VCN instance alive; expect restart due to change of NOT_RESTRICTED
+ // immutable capability
+ final VcnUnderlyingNetworkPolicy policy =
+ mVcnMgmtSvc.getUnderlyingNetworkPolicy(
+ getNetworkCapabilitiesBuilderForTransport(
+ TEST_SUBSCRIPTION_ID, TRANSPORT_WIFI)
+ .build(),
+ new LinkProperties());
+ assertTrue(policy.isTeardownRequested());
+ }
+
+ @Test
+ public void testGetUnderlyingNetworkPolicyVcnWifi_restrictingExistingNetworkRequiresRestart()
+ throws Exception {
+ final NetworkCapabilities existingNetworkCaps =
+ getNetworkCapabilitiesBuilderForTransport(TEST_SUBSCRIPTION_ID, TRANSPORT_WIFI)
+ .build();
+ setupTrackedCarrierWifiNetwork(existingNetworkCaps);
+
+ final VcnUnderlyingNetworkPolicy policy =
+ startVcnAndGetPolicyForTransport(
+ TEST_SUBSCRIPTION_ID, TEST_UUID_2, false /* isActive */, TRANSPORT_WIFI);
+
+ assertTrue(policy.isTeardownRequested());
+ }
+
@Test
public void testGetUnderlyingNetworkPolicyNonVcnNetwork() throws Exception {
setupSubscriptionAndStartVcn(TEST_SUBSCRIPTION_ID, TEST_UUID_1, true /* isActive */);
@@ -848,7 +891,9 @@
}
private void triggerVcnSafeMode(
- @NonNull ParcelUuid subGroup, @NonNull TelephonySubscriptionSnapshot snapshot)
+ @NonNull ParcelUuid subGroup,
+ @NonNull TelephonySubscriptionSnapshot snapshot,
+ boolean isInSafeMode)
throws Exception {
verify(mMockDeps)
.newVcn(
@@ -859,22 +904,32 @@
mVcnCallbackCaptor.capture());
VcnCallback vcnCallback = mVcnCallbackCaptor.getValue();
- vcnCallback.onEnteredSafeMode();
+ vcnCallback.onSafeModeStatusChanged(isInSafeMode);
}
- @Test
- public void testVcnEnteringSafeModeNotifiesPolicyListeners() throws Exception {
+ private void verifyVcnSafeModeChangesNotifiesPolicyListeners(boolean enterSafeMode)
+ throws Exception {
TelephonySubscriptionSnapshot snapshot =
triggerSubscriptionTrackerCbAndGetSnapshot(Collections.singleton(TEST_UUID_1));
mVcnMgmtSvc.addVcnUnderlyingNetworkPolicyListener(mMockPolicyListener);
- triggerVcnSafeMode(TEST_UUID_1, snapshot);
+ triggerVcnSafeMode(TEST_UUID_1, snapshot, enterSafeMode);
verify(mMockPolicyListener).onPolicyChanged();
}
- private void triggerVcnStatusCallbackOnEnteredSafeMode(
+ @Test
+ public void testVcnEnteringSafeModeNotifiesPolicyListeners() throws Exception {
+ verifyVcnSafeModeChangesNotifiesPolicyListeners(true /* enterSafeMode */);
+ }
+
+ @Test
+ public void testVcnExitingSafeModeNotifiesPolicyListeners() throws Exception {
+ verifyVcnSafeModeChangesNotifiesPolicyListeners(false /* enterSafeMode */);
+ }
+
+ private void triggerVcnStatusCallbackOnSafeModeStatusChanged(
@NonNull ParcelUuid subGroup,
@NonNull String pkgName,
int uid,
@@ -897,12 +952,13 @@
mVcnMgmtSvc.registerVcnStatusCallback(subGroup, mMockStatusCallback, pkgName);
- triggerVcnSafeMode(subGroup, snapshot);
+ triggerVcnSafeMode(subGroup, snapshot, true /* enterSafeMode */);
}
@Test
- public void testVcnStatusCallbackOnEnteredSafeModeWithCarrierPrivileges() throws Exception {
- triggerVcnStatusCallbackOnEnteredSafeMode(
+ public void testVcnStatusCallbackOnSafeModeStatusChangedWithCarrierPrivileges()
+ throws Exception {
+ triggerVcnStatusCallbackOnSafeModeStatusChanged(
TEST_UUID_1,
TEST_PACKAGE_NAME,
TEST_UID,
@@ -913,8 +969,9 @@
}
@Test
- public void testVcnStatusCallbackOnEnteredSafeModeWithoutCarrierPrivileges() throws Exception {
- triggerVcnStatusCallbackOnEnteredSafeMode(
+ public void testVcnStatusCallbackOnSafeModeStatusChangedWithoutCarrierPrivileges()
+ throws Exception {
+ triggerVcnStatusCallbackOnSafeModeStatusChanged(
TEST_UUID_1,
TEST_PACKAGE_NAME,
TEST_UID,
@@ -926,8 +983,9 @@
}
@Test
- public void testVcnStatusCallbackOnEnteredSafeModeWithoutLocationPermission() throws Exception {
- triggerVcnStatusCallbackOnEnteredSafeMode(
+ public void testVcnStatusCallbackOnSafeModeStatusChangedWithoutLocationPermission()
+ throws Exception {
+ triggerVcnStatusCallbackOnSafeModeStatusChanged(
TEST_UUID_1,
TEST_PACKAGE_NAME,
TEST_UID,
diff --git a/tests/vcn/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java b/tests/vcn/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java
index 1ef1a61..b592000 100644
--- a/tests/vcn/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java
+++ b/tests/vcn/java/com/android/server/vcn/UnderlyingNetworkTrackerTest.java
@@ -146,27 +146,15 @@
@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);
-
- verify(mConnectivityManager)
- .requestBackgroundNetwork(
- eq(getRouteSelectionRequest()),
- any(),
- any(RouteSelectionCallback.class));
+ verifyNetworkRequestsRegistered(INITIAL_SUB_IDS);
}
- private void verifyBackgroundCellRequests(
- TelephonySubscriptionSnapshot snapshot,
- ParcelUuid subGroup,
- Set<Integer> expectedSubIds) {
- verify(snapshot).getAllSubIdsInGroup(eq(subGroup));
-
+ private void verifyNetworkRequestsRegistered(Set<Integer> expectedSubIds) {
+ verify(mConnectivityManager)
+ .requestBackgroundNetwork(
+ eq(getWifiRequest(expectedSubIds)),
+ any(),
+ any(NetworkBringupCallback.class));
for (final int subId : expectedSubIds) {
verify(mConnectivityManager)
.requestBackgroundNetwork(
@@ -174,12 +162,18 @@
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,30 +181,32 @@
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()
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
+ .setSubIds(netCapsSubIds)
.build();
}
private NetworkRequest getCellRequestForSubId(int subId) {
- return getExpectedRequestBase(false)
+ return getExpectedRequestBase()
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
.setNetworkSpecifier(new TelephonyNetworkSpecifier(subId))
.build();
}
- private NetworkRequest getRouteSelectionRequest() {
- return getExpectedRequestBase(true).build();
+ private NetworkRequest getRouteSelectionRequest(Set<Integer> netCapsSubIds) {
+ return getExpectedRequestBase().setSubIds(netCapsSubIds).build();
}
- private NetworkRequest.Builder getExpectedRequestBase(boolean requireVcnManaged) {
+ private NetworkRequest.Builder getExpectedRequestBase() {
final NetworkRequest.Builder builder =
new NetworkRequest.Builder()
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
@@ -218,10 +214,6 @@
.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED);
- if (requireVcnManaged) {
- builder.addUnwantedCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED);
- }
-
return builder;
}
@@ -274,7 +266,7 @@
NetworkCapabilities networkCapabilities) {
verify(mConnectivityManager)
.requestBackgroundNetwork(
- eq(getRouteSelectionRequest()),
+ eq(getRouteSelectionRequest(INITIAL_SUB_IDS)),
any(),
mRouteSelectionCallbackCaptor.capture());
@@ -328,7 +320,7 @@
public void testRecordTrackerCallbackNotifiedForNetworkSuspended() {
RouteSelectionCallback cb = verifyRegistrationOnAvailableAndGetCallback();
- cb.onNetworkSuspended(mNetwork);
+ cb.onCapabilitiesChanged(mNetwork, SUSPENDED_NETWORK_CAPABILITIES);
UnderlyingNetworkRecord expectedRecord =
new UnderlyingNetworkRecord(
@@ -336,7 +328,11 @@
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 @@
RouteSelectionCallback cb =
verifyRegistrationOnAvailableAndGetCallback(SUSPENDED_NETWORK_CAPABILITIES);
- cb.onNetworkResumed(mNetwork);
+ cb.onCapabilitiesChanged(mNetwork, INITIAL_NETWORK_CAPABILITIES);
UnderlyingNetworkRecord expectedRecord =
new UnderlyingNetworkRecord(
@@ -352,7 +348,11 @@
INITIAL_NETWORK_CAPABILITIES,
INITIAL_LINK_PROPERTIES,
false /* isBlocked */);
- verify(mNetworkTrackerCb).onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
+ verify(mNetworkTrackerCb, times(1)).onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
+ // onSelectedUnderlyingNetworkChanged() won't be fired twice if network capabilities doesn't
+ // change.
+ cb.onCapabilitiesChanged(mNetwork, INITIAL_NETWORK_CAPABILITIES);
+ verify(mNetworkTrackerCb, times(1)).onSelectedUnderlyingNetworkChanged(eq(expectedRecord));
}
@Test
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
index ca6448c..34c0018 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
@@ -32,6 +32,7 @@
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.argThat;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
@@ -40,6 +41,8 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
+import android.net.ConnectivityManager;
+import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.NetworkAgent;
import android.net.NetworkCapabilities;
@@ -58,19 +61,29 @@
import org.mockito.ArgumentCaptor;
import java.io.IOException;
+import java.net.InetAddress;
import java.net.UnknownHostException;
+import java.util.Arrays;
import java.util.Collections;
+import java.util.List;
+import java.util.function.Consumer;
/** Tests for VcnGatewayConnection.ConnectedState */
@RunWith(AndroidJUnit4.class)
@SmallTest
public class VcnGatewayConnectionConnectedStateTest extends VcnGatewayConnectionTestBase {
private VcnIkeSession mIkeSession;
+ private NetworkAgent mNetworkAgent;
@Before
public void setUp() throws Exception {
super.setUp();
+ mNetworkAgent = mock(NetworkAgent.class);
+ doReturn(mNetworkAgent)
+ .when(mDeps)
+ .newNetworkAgent(any(), any(), any(), any(), anyInt(), any(), any(), any(), any());
+
mGatewayConnection.setUnderlyingNetwork(TEST_UNDERLYING_NETWORK_RECORD_1);
mIkeSession = mGatewayConnection.buildIkeSession(TEST_UNDERLYING_NETWORK_RECORD_1.network);
@@ -159,21 +172,44 @@
assertEquals(mGatewayConnection.mConnectedState, mGatewayConnection.getCurrentState());
}
- @Test
- public void testChildOpenedRegistersNetwork() throws Exception {
- // Verify scheduled but not canceled when entering ConnectedState
- verifySafeModeTimeoutAlarmAndGetCallback(false /* expectCanceled */);
+ private void triggerChildOpened() {
+ triggerChildOpened(Collections.singletonList(TEST_INTERNAL_ADDR), TEST_DNS_ADDR);
+ }
+ private void triggerChildOpened(List<LinkAddress> internalAddresses, InetAddress dnsAddress) {
final VcnChildSessionConfiguration mMockChildSessionConfig =
mock(VcnChildSessionConfiguration.class);
- doReturn(Collections.singletonList(TEST_INTERNAL_ADDR))
- .when(mMockChildSessionConfig)
- .getInternalAddresses();
- doReturn(Collections.singletonList(TEST_DNS_ADDR))
+ doReturn(internalAddresses).when(mMockChildSessionConfig).getInternalAddresses();
+ doReturn(Collections.singletonList(dnsAddress))
.when(mMockChildSessionConfig)
.getInternalDnsServers();
getChildSessionCallback().onOpened(mMockChildSessionConfig);
+ }
+
+ private void triggerValidation(int status) {
+ final ArgumentCaptor<Consumer<Integer>> validationCallbackCaptor =
+ ArgumentCaptor.forClass(Consumer.class);
+ verify(mDeps)
+ .newNetworkAgent(
+ any(),
+ any(),
+ any(),
+ any(),
+ anyInt(),
+ any(),
+ any(),
+ any(),
+ validationCallbackCaptor.capture());
+
+ validationCallbackCaptor.getValue().accept(status);
+ }
+
+ @Test
+ public void testChildOpenedRegistersNetwork() throws Exception {
+ // Verify scheduled but not canceled when entering ConnectedState
+ verifySafeModeTimeoutAlarmAndGetCallback(false /* expectCanceled */);
+ triggerChildOpened();
mTestLooper.dispatchAll();
assertEquals(mGatewayConnection.mConnectedState, mGatewayConnection.getCurrentState());
@@ -182,15 +218,20 @@
ArgumentCaptor.forClass(LinkProperties.class);
final ArgumentCaptor<NetworkCapabilities> ncCaptor =
ArgumentCaptor.forClass(NetworkCapabilities.class);
- verify(mConnMgr)
- .registerNetworkAgent(
- any(),
- any(),
- lpCaptor.capture(),
+ verify(mDeps)
+ .newNetworkAgent(
+ eq(mVcnContext),
+ any(String.class),
ncCaptor.capture(),
+ lpCaptor.capture(),
+ anyInt(),
+ argThat(nac -> nac.getLegacyType() == ConnectivityManager.TYPE_MOBILE),
any(),
any(),
- anyInt());
+ any());
+ verify(mNetworkAgent).register();
+ verify(mNetworkAgent).markConnected();
+
verify(mIpSecSvc)
.addAddressToTunnelInterface(
eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), eq(TEST_INTERNAL_ADDR), any());
@@ -208,9 +249,78 @@
// Now that Vcn Network is up, notify it as validated and verify the SafeMode alarm is
// canceled
- mGatewayConnection.mNetworkAgent.onValidationStatus(
- NetworkAgent.VALIDATION_STATUS_VALID, null /* redirectUri */);
+ triggerValidation(NetworkAgent.VALIDATION_STATUS_VALID);
verify(mSafeModeTimeoutAlarm).cancel();
+ assertFalse(mGatewayConnection.isInSafeMode());
+ }
+
+ @Test
+ public void testInternalAndDnsAddressesChanged() throws Exception {
+ final List<LinkAddress> startingInternalAddrs =
+ Arrays.asList(new LinkAddress[] {TEST_INTERNAL_ADDR, TEST_INTERNAL_ADDR_2});
+ triggerChildOpened(startingInternalAddrs, TEST_DNS_ADDR);
+ mTestLooper.dispatchAll();
+
+ for (LinkAddress addr : startingInternalAddrs) {
+ verify(mIpSecSvc)
+ .addAddressToTunnelInterface(
+ eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), eq(addr), any());
+ }
+
+ verify(mDeps)
+ .newNetworkAgent(
+ any(),
+ any(),
+ any(),
+ argThat(
+ lp ->
+ startingInternalAddrs.equals(lp.getLinkAddresses())
+ && Collections.singletonList(TEST_DNS_ADDR)
+ .equals(lp.getDnsServers())),
+ anyInt(),
+ any(),
+ any(),
+ any(),
+ any());
+
+ // Trigger another connection event, and verify that the addresses change
+ final List<LinkAddress> newInternalAddrs =
+ Arrays.asList(new LinkAddress[] {TEST_INTERNAL_ADDR_2, TEST_INTERNAL_ADDR_3});
+ triggerChildOpened(newInternalAddrs, TEST_DNS_ADDR_2);
+ mTestLooper.dispatchAll();
+
+ // Verify addresses on tunnel network added/removed
+ for (LinkAddress addr : newInternalAddrs) {
+ verify(mIpSecSvc)
+ .addAddressToTunnelInterface(
+ eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), eq(addr), any());
+ }
+ verify(mIpSecSvc)
+ .removeAddressFromTunnelInterface(
+ eq(TEST_IPSEC_TUNNEL_RESOURCE_ID), eq(TEST_INTERNAL_ADDR), any());
+
+ // TODO(b/184579891): Also verify link properties updated and sent when sendLinkProperties
+ // is mockable
+
+ // Verify that IpSecTunnelInterface only created once
+ verify(mIpSecSvc).createTunnelInterface(any(), any(), any(), any(), any());
+ verifyNoMoreInteractions(mIpSecSvc);
+ }
+
+ @Test
+ public void testSuccessfulConnectionExitsSafeMode() throws Exception {
+ verifySafeModeTimeoutNotifiesCallbackAndUnregistersNetworkAgent(
+ mGatewayConnection.mConnectedState);
+
+ assertTrue(mGatewayConnection.isInSafeMode());
+ assertFalse(mGatewayConnection.isQuitting());
+
+ triggerChildOpened();
+ mTestLooper.dispatchAll();
+
+ triggerValidation(NetworkAgent.VALIDATION_STATUS_VALID);
+
+ assertFalse(mGatewayConnection.isInSafeMode());
}
@Test
@@ -241,7 +351,7 @@
verify(mGatewayStatusCallback)
.onGatewayConnectionError(
- eq(mConfig.getExposedCapabilities()),
+ eq(mConfig.getGatewayConnectionName()),
eq(VCN_ERROR_CODE_INTERNAL_ERROR),
any(),
any());
@@ -275,7 +385,10 @@
verify(mGatewayStatusCallback)
.onGatewayConnectionError(
- eq(mConfig.getExposedCapabilities()), eq(expectedErrorType), any(), any());
+ eq(mConfig.getGatewayConnectionName()),
+ eq(expectedErrorType),
+ any(),
+ any());
}
@Test
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java
index 7afa449..bfe8c73 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectingStateTest.java
@@ -118,8 +118,9 @@
}
@Test
- public void testSafeModeTimeoutNotifiesCallback() {
- verifySafeModeTimeoutNotifiesCallback(mGatewayConnection.mConnectingState);
+ public void testSafeModeTimeoutNotifiesCallbackAndUnregistersNetworkAgent() {
+ verifySafeModeTimeoutNotifiesCallbackAndUnregistersNetworkAgent(
+ mGatewayConnection.mConnectingState);
}
@Test
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java
index 99feffd..9da8b45 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionDisconnectingStateTest.java
@@ -86,8 +86,9 @@
}
@Test
- public void testSafeModeTimeoutNotifiesCallback() {
- verifySafeModeTimeoutNotifiesCallback(mGatewayConnection.mDisconnectingState);
+ public void testSafeModeTimeoutNotifiesCallbackAndUnregistersNetworkAgent() {
+ verifySafeModeTimeoutNotifiesCallbackAndUnregistersNetworkAgent(
+ mGatewayConnection.mDisconnectingState);
}
@Test
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java
index 85a0277..6dbf7d5 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionRetryTimeoutStateTest.java
@@ -96,8 +96,9 @@
}
@Test
- public void testSafeModeTimeoutNotifiesCallback() {
- verifySafeModeTimeoutNotifiesCallback(mGatewayConnection.mRetryTimeoutState);
+ public void testSafeModeTimeoutNotifiesCallbackAndUnregistersNetworkAgent() {
+ verifySafeModeTimeoutNotifiesCallbackAndUnregistersNetworkAgent(
+ mGatewayConnection.mRetryTimeoutState);
}
@Test
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
index a660735..c5ed8f6 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
@@ -21,6 +21,8 @@
import static com.android.server.vcn.VcnTestUtils.setupIpSecManager;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.atLeastOnce;
@@ -42,6 +44,7 @@
import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.Network;
+import android.net.NetworkAgent;
import android.net.NetworkCapabilities;
import android.net.ipsec.ike.ChildSessionCallback;
import android.net.ipsec.ike.IkeSessionCallback;
@@ -71,8 +74,14 @@
protected static final ParcelUuid TEST_SUB_GRP = new ParcelUuid(UUID.randomUUID());
protected static final InetAddress TEST_DNS_ADDR =
InetAddresses.parseNumericAddress("2001:DB8:0:1::");
+ protected static final InetAddress TEST_DNS_ADDR_2 =
+ InetAddresses.parseNumericAddress("2001:DB8:0:2::");
protected static final LinkAddress TEST_INTERNAL_ADDR =
- new LinkAddress(InetAddresses.parseNumericAddress("2001:DB8:0:2::"), 64);
+ new LinkAddress(InetAddresses.parseNumericAddress("2001:DB8:1:1::"), 64);
+ protected static final LinkAddress TEST_INTERNAL_ADDR_2 =
+ new LinkAddress(InetAddresses.parseNumericAddress("2001:DB8:1:2::"), 64);
+ protected static final LinkAddress TEST_INTERNAL_ADDR_3 =
+ new LinkAddress(InetAddresses.parseNumericAddress("2001:DB8:1:3::"), 64);
protected static final int TEST_IPSEC_SPI_VALUE = 0x1234;
protected static final int TEST_IPSEC_SPI_RESOURCE_ID = 1;
@@ -267,7 +276,12 @@
expectCanceled);
}
- protected void verifySafeModeTimeoutNotifiesCallback(@NonNull State expectedState) {
+ protected void verifySafeModeTimeoutNotifiesCallbackAndUnregistersNetworkAgent(
+ @NonNull State expectedState) {
+ // Set a NetworkAgent, and expect it to be unregistered and cleared
+ final NetworkAgent mockNetworkAgent = mock(NetworkAgent.class);
+ mGatewayConnection.setNetworkAgent(mockNetworkAgent);
+
// SafeMode timer starts when VcnGatewayConnection exits DisconnectedState (the initial
// state)
final Runnable delayedEvent =
@@ -275,7 +289,11 @@
delayedEvent.run();
mTestLooper.dispatchAll();
- verify(mGatewayStatusCallback).onEnteredSafeMode();
+ verify(mGatewayStatusCallback).onSafeModeStatusChanged();
assertEquals(expectedState, mGatewayConnection.getCurrentState());
+ assertTrue(mGatewayConnection.isInSafeMode());
+
+ verify(mockNetworkAgent).unregister();
+ assertNull(mGatewayConnection.getNetworkAgent());
}
}
diff --git a/tests/vcn/java/com/android/server/vcn/VcnTest.java b/tests/vcn/java/com/android/server/vcn/VcnTest.java
index c853fc5..90eb75e 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnTest.java
@@ -19,12 +19,13 @@
import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS;
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+import static android.net.vcn.VcnManager.VCN_STATUS_CODE_ACTIVE;
+import static android.net.vcn.VcnManager.VCN_STATUS_CODE_SAFE_MODE;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.argThat;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
@@ -51,7 +52,8 @@
import org.junit.Test;
import org.mockito.ArgumentCaptor;
-import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Set;
import java.util.UUID;
@@ -132,6 +134,7 @@
private void startVcnGatewayWithCapabilities(
NetworkRequestListener requestListener, int... netCapabilities) {
final NetworkRequest.Builder requestBuilder = new NetworkRequest.Builder();
+ requestBuilder.addTransportType(TRANSPORT_CELLULAR);
for (final int netCapability : netCapabilities) {
requestBuilder.addCapability(netCapability);
}
@@ -140,7 +143,7 @@
mTestLooper.dispatchAll();
}
- private void verifyUpdateSubscriptionSnapshotNotifiesConnectionGateways(boolean isActive) {
+ private void verifyUpdateSubscriptionSnapshotNotifiesGatewayConnections(int status) {
final NetworkRequestListener requestListener = verifyAndGetRequestListener();
startVcnGatewayWithCapabilities(requestListener, TEST_CAPS[0]);
@@ -150,25 +153,24 @@
final TelephonySubscriptionSnapshot updatedSnapshot =
mock(TelephonySubscriptionSnapshot.class);
- mVcn.setIsActive(isActive);
+ mVcn.setStatus(status);
mVcn.updateSubscriptionSnapshot(updatedSnapshot);
mTestLooper.dispatchAll();
for (final VcnGatewayConnection gateway : gatewayConnections) {
- verify(gateway, isActive ? times(1) : never())
- .updateSubscriptionSnapshot(eq(updatedSnapshot));
+ verify(gateway).updateSubscriptionSnapshot(eq(updatedSnapshot));
}
}
@Test
public void testSubscriptionSnapshotUpdatesVcnGatewayConnections() {
- verifyUpdateSubscriptionSnapshotNotifiesConnectionGateways(true /* isActive */);
+ verifyUpdateSubscriptionSnapshotNotifiesGatewayConnections(VCN_STATUS_CODE_ACTIVE);
}
@Test
- public void testSubscriptionSnapshotUpdatesVcnGatewayConnectionsWhileInactive() {
- verifyUpdateSubscriptionSnapshotNotifiesConnectionGateways(false /* isActive */);
+ public void testSubscriptionSnapshotUpdatesVcnGatewayConnectionsInSafeMode() {
+ verifyUpdateSubscriptionSnapshotNotifiesGatewayConnections(VCN_STATUS_CODE_SAFE_MODE);
}
private void triggerVcnRequestListeners(NetworkRequestListener requestListener) {
@@ -198,32 +200,53 @@
private void verifySafeMode(
NetworkRequestListener requestListener,
- Set<VcnGatewayConnection> expectedGatewaysTornDown) {
- assertFalse(mVcn.isActive());
- for (final VcnGatewayConnection gatewayConnection : expectedGatewaysTornDown) {
- verify(gatewayConnection).teardownAsynchronously();
+ Set<VcnGatewayConnection> activeGateways,
+ boolean expectInSafeMode) {
+ for (VcnGatewayConnection gatewayConnection : activeGateways) {
+ verify(gatewayConnection, never()).teardownAsynchronously();
}
- verify(mVcnNetworkProvider).unregisterListener(requestListener);
- verify(mVcnCallback).onEnteredSafeMode();
+
+ assertEquals(
+ expectInSafeMode ? VCN_STATUS_CODE_SAFE_MODE : VCN_STATUS_CODE_ACTIVE,
+ mVcn.getStatus());
+ verify(mVcnCallback).onSafeModeStatusChanged(expectInSafeMode);
}
@Test
- public void testGatewayEnteringSafeModeNotifiesVcn() {
+ public void testGatewayEnteringAndExitingSafeModeNotifiesVcn() {
final NetworkRequestListener requestListener = verifyAndGetRequestListener();
final Set<VcnGatewayConnection> gatewayConnections =
startGatewaysAndGetGatewayConnections(requestListener);
- // Doesn't matter which callback this gets - any Gateway entering Safemode should shut down
- // all Gateways
+ // Doesn't matter which callback this gets, or which VCN is in safe mode - any Gateway
+ // entering Safemode should trigger safe mode
final VcnGatewayStatusCallback statusCallback = mGatewayStatusCallbackCaptor.getValue();
- statusCallback.onEnteredSafeMode();
+ final VcnGatewayConnection gatewayConnection = gatewayConnections.iterator().next();
+
+ doReturn(true).when(gatewayConnection).isInSafeMode();
+ statusCallback.onSafeModeStatusChanged();
mTestLooper.dispatchAll();
- verifySafeMode(requestListener, gatewayConnections);
+ verifySafeMode(requestListener, gatewayConnections, true /* expectInSafeMode */);
+
+ // Verify that when all GatewayConnections exit safe mode, the VCN also exits safe mode
+ doReturn(false).when(gatewayConnection).isInSafeMode();
+ statusCallback.onSafeModeStatusChanged();
+ mTestLooper.dispatchAll();
+
+ verifySafeMode(requestListener, gatewayConnections, false /* expectInSafeMode */);
+
+ // Re-trigger, verify safe mode callback does not get fired again for identical state
+ statusCallback.onSafeModeStatusChanged();
+ mTestLooper.dispatchAll();
+
+ // Expect only once still; from above.
+ verify(mVcnCallback).onSafeModeStatusChanged(false);
}
- @Test
- public void testGatewayQuit() {
+ private void verifyGatewayQuit(int status) {
+ mVcn.setStatus(status);
+
final NetworkRequestListener requestListener = verifyAndGetRequestListener();
final Set<VcnGatewayConnection> gatewayConnections =
new ArraySet<>(startGatewaysAndGetGatewayConnections(requestListener));
@@ -236,7 +259,7 @@
assertEquals(1, mVcn.getVcnGatewayConnections().size());
verify(mVcnNetworkProvider).resendAllRequests(requestListener);
- // Verify that the VcnGatewayConnection is restarted
+ // Verify that the VcnGatewayConnection is restarted if a request exists for it
triggerVcnRequestListeners(requestListener);
mTestLooper.dispatchAll();
assertEquals(2, mVcn.getVcnGatewayConnections().size());
@@ -250,21 +273,13 @@
}
@Test
- public void testGatewayQuitWhileInactive() {
- final NetworkRequestListener requestListener = verifyAndGetRequestListener();
- final Set<VcnGatewayConnection> gatewayConnections =
- new ArraySet<>(startGatewaysAndGetGatewayConnections(requestListener));
+ public void testGatewayQuitReevaluatesRequests() {
+ verifyGatewayQuit(VCN_STATUS_CODE_ACTIVE);
+ }
- mVcn.teardownAsynchronously();
- mTestLooper.dispatchAll();
-
- final VcnGatewayStatusCallback statusCallback = mGatewayStatusCallbackCaptor.getValue();
- statusCallback.onQuit();
- mTestLooper.dispatchAll();
-
- // Verify that the VCN requests the networkRequests be resent
- assertEquals(1, mVcn.getVcnGatewayConnections().size());
- verify(mVcnNetworkProvider, never()).resendAllRequests(requestListener);
+ @Test
+ public void testGatewayQuitReevaluatesRequestsInSafeMode() {
+ verifyGatewayQuit(VCN_STATUS_CODE_SAFE_MODE);
}
@Test
@@ -274,11 +289,12 @@
assertEquals(2, mVcn.getVcnGatewayConnectionConfigMap().size());
// Create VcnConfig with only one VcnGatewayConnectionConfig so a gateway connection is torn
- // down
- final VcnGatewayConnectionConfig activeConfig =
- VcnGatewayConnectionConfigTest.buildTestConfigWithExposedCaps(TEST_CAPS[0]);
- final VcnGatewayConnectionConfig removedConfig =
- VcnGatewayConnectionConfigTest.buildTestConfigWithExposedCaps(TEST_CAPS[1]);
+ // down. Reuse existing VcnGatewayConnectionConfig so that the gateway connection name
+ // matches.
+ final List<VcnGatewayConnectionConfig> currentConfigs =
+ new ArrayList<>(mVcn.getVcnGatewayConnectionConfigMap().keySet());
+ final VcnGatewayConnectionConfig activeConfig = currentConfigs.get(0);
+ final VcnGatewayConnectionConfig removedConfig = currentConfigs.get(1);
final VcnConfig updatedConfig =
new VcnConfig.Builder(mContext).addGatewayConnectionConfig(activeConfig).build();
@@ -293,49 +309,4 @@
verify(removedGatewayConnection).teardownAsynchronously();
verify(mVcnNetworkProvider).resendAllRequests(requestListener);
}
-
- @Test
- public void testUpdateConfigExitsSafeMode() {
- final NetworkRequestListener requestListener = verifyAndGetRequestListener();
- final Set<VcnGatewayConnection> gatewayConnections =
- new ArraySet<>(startGatewaysAndGetGatewayConnections(requestListener));
-
- final VcnGatewayStatusCallback statusCallback = mGatewayStatusCallbackCaptor.getValue();
- statusCallback.onEnteredSafeMode();
- mTestLooper.dispatchAll();
- verifySafeMode(requestListener, gatewayConnections);
-
- doAnswer(invocation -> {
- final NetworkRequestListener listener = invocation.getArgument(0);
- triggerVcnRequestListeners(listener);
- return null;
- }).when(mVcnNetworkProvider).registerListener(eq(requestListener));
-
- mVcn.updateConfig(mConfig);
- mTestLooper.dispatchAll();
-
- // Registered on start, then re-registered with new configs
- verify(mVcnNetworkProvider, times(2)).registerListener(eq(requestListener));
- assertTrue(mVcn.isActive());
- for (final int[] caps : TEST_CAPS) {
- // Expect each gateway connection created only on initial startup
- verify(mDeps)
- .newVcnGatewayConnection(
- eq(mVcnContext),
- eq(TEST_SUB_GROUP),
- eq(mSubscriptionSnapshot),
- argThat(config -> Arrays.equals(caps, config.getExposedCapabilities())),
- any());
- }
- }
-
- @Test
- public void testIgnoreNetworkRequestWhileInactive() {
- mVcn.setIsActive(false /* isActive */);
-
- final NetworkRequestListener requestListener = verifyAndGetRequestListener();
- triggerVcnRequestListeners(requestListener);
-
- verify(mDeps, never()).newVcnGatewayConnection(any(), any(), any(), any(), any());
- }
}
diff --git a/tools/fonts/fontchain_linter.py b/tools/fonts/fontchain_linter.py
index 7de7065..a4a315b 100755
--- a/tools/fonts/fontchain_linter.py
+++ b/tools/fonts/fontchain_linter.py
@@ -11,12 +11,6 @@
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 @@
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 @@
check_cjk_punctuation()
- check_canonical_name()
-
check_emoji = sys.argv[2]
if check_emoji == 'true':
ucd_path = sys.argv[3]
diff --git a/tools/hiddenapi/OWNERS b/tools/hiddenapi/OWNERS
new file mode 100644
index 0000000..afbeef5
--- /dev/null
+++ b/tools/hiddenapi/OWNERS
@@ -0,0 +1,7 @@
+# compat-team@ for changes to hiddenapi files
+andreionea@google.com
+mathewi@google.com
+satayev@google.com
+
+# soong-team@ as the files these tools protect are tightly coupled with Soong
+file:platform/build/soong:/OWNERS
diff --git a/tools/hiddenapi/exclude.sh b/tools/hiddenapi/exclude.sh
index 18c4054..2924e01 100755
--- a/tools/hiddenapi/exclude.sh
+++ b/tools/hiddenapi/exclude.sh
@@ -7,11 +7,9 @@
# the team email to use in the event of this detecting an entry in a <team> package. Also
# add <team> to the TEAMS list.
LIBCORE_PACKAGES="\
- android.icu \
android.system \
android.test \
com.android.bouncycastle \
- com.android.conscrypt \
com.android.i18n.phonenumbers \
com.android.okhttp \
com.sun \
@@ -24,37 +22,54 @@
org.json \
org.w3c.dom \
org.xml.sax \
+ org.xmlpull.v1 \
sun \
"
LIBCORE_EMAIL=libcore-team@android.com
+I18N_PACKAGES="\
+ android.icu \
+ "
+
+I18N_EMAIL=$LIBCORE_EMAIL
+
+CONSCRYPT_PACKAGES="\
+ com.android.org.conscrypt \
+ "
+
+CONSCRYPT_EMAIL=$LIBCORE_EMAIL
+
# List of teams.
-TEAMS=LIBCORE
+TEAMS="LIBCORE I18N CONSCRYPT"
+
+SHA=$1
# Generate the list of packages and convert to a regular expression.
PACKAGES=$(for t in $TEAMS; do echo $(eval echo \${${t}_PACKAGES}); done)
RE=$(echo ${PACKAGES} | sed "s/ /|/g")
-git show --name-only --pretty=format: $1 | grep "config/hiddenapi-.*txt" | while read file; do
- ENTRIES=$(grep -E "^L(${RE})/" <(git show $1:$file))
+EXIT_CODE=0
+for file in $(git show --name-only --pretty=format: $SHA | grep "config/hiddenapi-.*txt"); do
+ ENTRIES=$(grep -E "^\+L(${RE})/" <(git diff ${SHA}~1 ${SHA} $file) | sed "s|^\+||" || echo)
if [[ -n "${ENTRIES}" ]]; then
- echo -e "\e[1m\e[31m$file $1 contains the following entries\e[0m"
+ echo -e "\e[1m\e[31m$file $SHA contains the following entries\e[0m"
echo -e "\e[1m\e[31mfor packages that are handled using UnsupportedAppUsage. Please remove\e[0m"
echo -e "\e[1m\e[31mthese entries and add annotations instead.\e[0m"
# Partition the entries by team and provide contact details to aid in fixing the issue.
for t in ${TEAMS}
do
PACKAGES=$(eval echo \${${t}_PACKAGES})
- RE=$(echo ${PACKAGES} | sed "s/ /|/g")
- TEAM_ENTRIES=$(grep -E "^L(${RE})/" <(echo "${ENTRIES}"))
+ TEAM_RE=$(echo ${PACKAGES} | sed "s/ /|/g")
+ TEAM_ENTRIES=$(grep -E "^L(${TEAM_RE})/" <(echo "${ENTRIES}") || echo)
if [[ -n "${TEAM_ENTRIES}" ]]; then
EMAIL=$(eval echo \${${t}_EMAIL})
- echo -e "\e[33mContact ${EMAIL} or compat- for help with the following:\e[0m"
- for i in ${ENTRIES}
+ echo -e "\e[33mContact ${EMAIL} for help with the following:\e[0m"
+ for i in ${TEAM_ENTRIES}
do
echo -e "\e[33m ${i}\e[0m"
done
fi
done
- exit 1
+ EXIT_CODE=1
fi
done
+exit $EXIT_CODE