Merge "Add more OWNERS coverage"
diff --git a/Android.bp b/Android.bp
index 8385d6e..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,7 +112,6 @@
":gsiservice_aidl",
":incidentcompanion_aidl",
":installd_aidl",
- ":keystore_aidl",
":libaudioclient_aidl",
":libbinder_aidl",
":libbluetooth-binder-aidl",
@@ -399,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: [
@@ -578,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,
},
@@ -660,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"],
@@ -755,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",
@@ -770,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",
],
}
@@ -787,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",
@@ -813,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",
],
@@ -839,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",
],
}
@@ -1061,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,
@@ -1140,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: {
@@ -1198,28 +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",
- ],
-}
-
// 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).
diff --git a/ApiDocs.bp b/ApiDocs.bp
index ff3dc8d..d3bef7f 100644
--- a/ApiDocs.bp
+++ b/ApiDocs.bp
@@ -59,11 +59,23 @@
name: "framework-doc-stubs-default",
srcs: [
":framework-non-updatable-stub-sources",
- ":framework-updatable-sources",
- "test-base/src/**/*.java",
+
+ // 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/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/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-unsupported.txt b/config/hiddenapi-unsupported.txt
index 8a377ac..48a9782 100644
--- a/config/hiddenapi-unsupported.txt
+++ b/config/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 ef06785..b944ac9 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -25703,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);
@@ -25732,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);
}
@@ -40412,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();
@@ -41367,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
@@ -41378,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 3b7a617..fe8b9d6 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -23,6 +23,7 @@
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";
}
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index e0de978..eebf283 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -9795,7 +9795,6 @@
method @Deprecated public int getDataConnectionApnTypeBitMask();
method @Deprecated public int getDataConnectionFailCause();
method @Deprecated public int getDataConnectionState();
- method public int getId();
}
public final class PreciseDisconnectCause {
@@ -10552,6 +10551,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";
@@ -10563,6 +10563,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";
}
@@ -11984,10 +11985,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;
}
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 2f160e9..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";
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/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/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/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 68606ec..da3febd 100644
--- a/core/java/android/net/NetworkPolicyManager.java
+++ b/core/java/android/net/NetworkPolicyManager.java
@@ -564,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.
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..75db3820 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/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/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/view/OWNERS b/core/java/android/view/OWNERS
index 4a1d685..cdf1e46 100644
--- a/core/java/android/view/OWNERS
+++ b/core/java/android/view/OWNERS
@@ -59,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/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/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/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 4a22272..1f7695e 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2551,10 +2551,6 @@
<permission android:name="android.permission.CREATE_USERS"
android:protectionLevel="signature" />
- <!-- @TestApi @hide Allows an application to query user info for all users on the device. -->
- <permission android:name="android.permission.QUERY_USERS"
- android:protectionLevel="signature" />
-
<!-- @hide Allows an application to set the profile owners and the device owner.
This permission is not available to third party applications.-->
<permission android:name="android.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS"
@@ -2562,6 +2558,16 @@
android:label="@string/permlab_manageProfileAndDeviceOwners"
android:description="@string/permdesc_manageProfileAndDeviceOwners" />
+ <!-- @TestApi @hide Allows an application to reset the record of previous system update freeze
+ periods. -->
+ <permission android:name="android.permission.CLEAR_FREEZE_PERIOD"
+ android:protectionLevel="signature" />
+
+ <!-- @TestApi @hide Allows an application to force available DevicePolicyManager logs to
+ DPC. -->
+ <permission android:name="android.permission.FORCE_DEVICE_POLICY_MANAGER_LOGS"
+ android:protectionLevel="signature" />
+
<!-- Allows an application to get full detailed information about
recently running tasks, with full fidelity to the real state.
@hide -->
@@ -4107,6 +4113,11 @@
<permission android:name="android.permission.MODIFY_AUDIO_ROUTING"
android:protectionLevel="signature|privileged" />
+ <!-- @TestApi Allows an application to query audio related state.
+ @hide -->
+ <permission android:name="android.permission.QUERY_AUDIO_STATE"
+ android:protectionLevel="signature" />
+
<!-- Allows an application to modify what effects are applied to all audio
(matching certain criteria) from any application.
<p>Not for use by third-party applications.</p>
@@ -4584,6 +4595,11 @@
<permission android:name="android.permission.SET_INITIAL_LOCK"
android:protectionLevel="signature|setup"/>
+ <!-- @TestApi Allows applications to set and verify lockscreen credentials.
+ @hide -->
+ <permission android:name="android.permission.SET_AND_VERIFY_LOCKSCREEN_CREDENTIALS"
+ android:protectionLevel="signature"/>
+
<!-- Allows managing (adding, removing) fingerprint templates. Reserved for the system. @hide -->
<permission android:name="android.permission.MANAGE_FINGERPRINT"
android:protectionLevel="signature|privileged" />
diff --git a/core/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/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 009421b..43fdedc 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -454,6 +454,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 ae9f8664..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/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 c82b6e6b..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..268b15bf 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..c26d9f583 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/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 0a9560a..ab290f9 100644
--- a/packages/Connectivity/framework/api/current.txt
+++ b/packages/Connectivity/framework/api/current.txt
@@ -298,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);
@@ -408,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 cd96a1b..f95d377 100644
--- a/packages/Connectivity/framework/api/module-lib-current.txt
+++ b/packages/Connectivity/framework/api/module-lib-current.txt
@@ -104,7 +104,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
@@ -176,10 +175,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 95ad694..0a82cb7 100644
--- a/packages/Connectivity/framework/api/system-current.txt
+++ b/packages/Connectivity/framework/api/system-current.txt
@@ -273,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 {
@@ -325,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 {
diff --git a/packages/Connectivity/framework/src/android/net/ConnectivityManager.java b/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
index c6f4e0b..df222e6 100644
--- a/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
+++ b/packages/Connectivity/framework/src/android/net/ConnectivityManager.java
@@ -3140,18 +3140,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) {
@@ -3409,6 +3418,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 */
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/NetworkCapabilities.java b/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java
index 881fa8c..9a75f0b 100644
--- a/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java
@@ -163,7 +163,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 +273,8 @@
NET_CAPABILITY_VEHICLE_INTERNAL,
NET_CAPABILITY_NOT_VCN_MANAGED,
NET_CAPABILITY_ENTERPRISE,
+ NET_CAPABILITY_VSIM,
+ NET_CAPABILITY_BIP,
})
public @interface NetCapability { }
@@ -493,8 +494,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 +553,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 +592,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 +613,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 +627,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 +642,7 @@
*/
public @NonNull NetworkCapabilities removeUnwantedCapability(@NetCapability int capability) {
checkValidCapability(capability);
- mUnwantedNetworkCapabilities &= ~(1 << capability);
+ mUnwantedNetworkCapabilities &= ~(1L << capability);
return this;
}
@@ -731,14 +710,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 +728,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 +807,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 +1112,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() {
@@ -2163,6 +2136,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 +2365,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 +2738,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 38691ef..5d40417 100644
--- a/packages/Connectivity/framework/src/android/net/NetworkRequest.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkRequest.java
@@ -501,9 +501,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;
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 b7ce2a3..d0dc987 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" />
@@ -354,6 +359,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" />
@@ -369,6 +377,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/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/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 e3ce7a31..5aa3e5b 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -1281,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);
@@ -1895,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;
}
@@ -3761,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);
@@ -4034,7 +4050,7 @@
}
}
}
- decrementRequestCount(nri);
+ nri.decrementRequestCount();
mNetworkRequestInfoLogs.log("RELEASE " + nri);
if (null != nri.getActiveRequest()) {
@@ -4151,14 +4167,6 @@
? mSystemNetworkRequestCounter : mNetworkRequestCounter;
}
- private void incrementRequestCountOrThrow(NetworkRequestInfo nri) {
- getRequestCounter(nri).incrementCountOrThrow(nri.mUid);
- }
-
- private void decrementRequestCount(NetworkRequestInfo nri) {
- getRequestCounter(nri).decrementCount(nri.mUid);
- }
-
@Override
public void setAcceptUnvalidated(Network network, boolean accept, boolean always) {
enforceNetworkStackSettingsOrSetup();
@@ -4962,7 +4970,7 @@
}
@Override
- public void setGlobalProxy(final ProxyInfo proxyProperties) {
+ public void setGlobalProxy(@Nullable final ProxyInfo proxyProperties) {
PermissionUtils.enforceNetworkStackPermission(mContext);
mProxyTracker.setGlobalProxy(proxyProperties);
}
@@ -5307,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),
@@ -5324,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();
@@ -5347,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<>();
@@ -5457,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
@@ -5507,7 +5545,8 @@
mPid = getCallingPid();
mUid = mDeps.getCallingUid();
mAsUid = asUid;
- incrementRequestCountOrThrow(this);
+ mPerUidCounter = getRequestCounter(this);
+ mPerUidCounter.incrementCountOrThrow(mUid);
/**
* Location sensitive data not included in pending intent. Only included in
* {@link NetworkCallback}.
@@ -5539,15 +5578,11 @@
mUid = mDeps.getCallingUid();
mAsUid = asUid;
mPendingIntent = null;
- incrementRequestCountOrThrow(this);
+ 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,
@@ -5582,9 +5617,11 @@
mUid = nri.mUid;
mAsUid = nri.mAsUid;
mPendingIntent = nri.mPendingIntent;
- incrementRequestCountOrThrow(this);
+ mPerUidCounter = getRequestCounter(this);
+ mPerUidCounter.incrementCountOrThrow(mUid);
mCallbackFlags = nri.mCallbackFlags;
mCallingAttributionTag = nri.mCallingAttributionTag;
+ linkDeathRecipient();
}
NetworkRequestInfo(int asUid, @NonNull final NetworkRequest r) {
@@ -5613,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);
}
}
@@ -5635,7 +5686,7 @@
+ mNetworkRequestForCallback.requestId
+ " " + mRequests
+ (mPendingIntent == null ? "" : " to trigger " + mPendingIntent)
- + "callback flags: " + mCallbackFlags;
+ + " callback flags: " + mCallbackFlags;
}
}
@@ -5660,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) {
@@ -6150,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
@@ -6170,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;
@@ -6617,7 +6681,7 @@
mDeps.reportNetworkInterfaceForTransports(mContext, iface,
caps.getTransportTypes());
} catch (Exception e) {
- loge("Exception adding interface: " + e);
+ logw("Exception adding interface: " + e);
}
}
}
@@ -8767,7 +8831,7 @@
// Decrement the reference count for this NetworkRequestInfo. The reference count is
// incremented when the NetworkRequestInfo is created as part of
// enforceRequestCountLimit().
- decrementRequestCount(nri);
+ nri.decrementRequestCount();
return;
}
@@ -8833,7 +8897,7 @@
// Decrement the reference count for this NetworkRequestInfo. The reference count is
// incremented when the NetworkRequestInfo is created as part of
// enforceRequestCountLimit().
- decrementRequestCount(nri);
+ nri.decrementRequestCount();
iCb.unlinkToDeath(cbInfo, 0);
}
@@ -9409,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
@@ -9583,7 +9641,6 @@
new OemNetworkRequestFactory().createNrisFromOemNetworkPreferences(preference);
replaceDefaultNetworkRequestsForPreference(nris);
mOemNetworkPreferences = preference;
- // TODO http://b/176496396 persist data to shared preferences.
if (null != listener) {
try {
@@ -9740,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/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/clipboard/ClipboardService.java b/services/core/java/com/android/server/clipboard/ClipboardService.java
index 6aec9fc..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,40 +100,57 @@
private boolean openPipe() {
try {
- final RandomAccessFile pipe = new RandomAccessFile(PIPE_DEVICE, "rw");
+ final FileDescriptor fd = Os.socket(OsConstants.AF_VSOCK, OsConstants.SOCK_STREAM, 0);
+
try {
- pipe.write(createOpenHandshake());
- mPipe = pipe;
+ Os.connect(fd, new VmSocketAddress(HOST_PORT, OsConstants.VMADDR_CID_HOST));
+
+ final byte[] handshake = createOpenHandshake();
+ Os.write(fd, handshake, 0, handshake.length);
+ mPipe = fd;
return true;
- } catch (IOException ignore) {
- pipe.close();
+ } catch (ErrnoException | SocketException | InterruptedIOException e) {
+ Os.close(fd);
}
- } catch (IOException ignore) {
+ } catch (ErrnoException e) {
}
+
return false;
}
private void closePipe() {
try {
- final RandomAccessFile pipe = mPipe;
+ final FileDescriptor fd = mPipe;
mPipe = null;
- if (pipe != null) {
- pipe.close();
+ if (fd != null) {
+ Os.close(fd);
}
- } catch (IOException ignore) {
+ } catch (ErrnoException ignore) {
}
}
- private byte[] receiveMessage() throws IOException {
- final int size = Integer.reverseBytes(mPipe.readInt());
- final byte[] receivedData = new byte[size];
- mPipe.readFully(receivedData);
- return receivedData;
+ private byte[] receiveMessage() throws ErrnoException, InterruptedIOException {
+ final byte[] lengthBits = new byte[4];
+ Os.read(mPipe, lengthBits, 0, lengthBits.length);
+
+ final ByteBuffer bb = ByteBuffer.wrap(lengthBits);
+ bb.order(ByteOrder.LITTLE_ENDIAN);
+ final int msgLen = bb.getInt();
+
+ final byte[] msg = new byte[msgLen];
+ Os.read(mPipe, msg, 0, msg.length);
+
+ return msg;
}
- private void sendMessage(byte[] message) throws IOException {
- mPipe.writeInt(Integer.reverseBytes(message.length));
- mPipe.write(message);
+ private void sendMessage(byte[] msg) throws ErrnoException, InterruptedIOException {
+ final byte[] lengthBits = new byte[4];
+ final ByteBuffer bb = ByteBuffer.wrap(lengthBits);
+ bb.order(ByteOrder.LITTLE_ENDIAN);
+ bb.putInt(msg.length);
+
+ Os.write(mPipe, lengthBits, 0, lengthBits.length);
+ Os.write(mPipe, msg, 0, msg.length);
}
public HostClipboardMonitor(HostClipboardCallback cb) {
@@ -135,7 +159,7 @@
@Override
public void run() {
- while(!Thread.interrupted()) {
+ while (!Thread.interrupted()) {
try {
// There's no guarantee that QEMU pipes will be ready at the moment
// this method is invoked. We simply try to get the pipe open and
@@ -147,9 +171,10 @@
final byte[] receivedData = receiveMessage();
mHostClipboardCallback.onHostClipboardUpdated(
new String(receivedData));
- } catch (IOException e) {
+ } catch (ErrnoException | InterruptedIOException e) {
closePipe();
- } catch (InterruptedException e) {}
+ } catch (InterruptedException e) {
+ }
}
}
@@ -158,7 +183,7 @@
if (mPipe != null) {
sendMessage(content.getBytes());
}
- } catch(IOException e) {
+ } catch (ErrnoException | InterruptedIOException e) {
Slog.e("HostClipboardMonitor",
"Failed to set host clipboard " + e.getMessage());
}
diff --git a/services/core/java/com/android/server/connectivity/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/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/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/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index c127858..290307b 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -5581,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;
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 37b9d564..0e4a2ee 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -273,7 +273,8 @@
options.getCompilationReason(),
newResult,
ArtStatsLogUtils.getApkType(path),
- dexCodeIsa);
+ dexCodeIsa,
+ path);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_PACKAGE_MANAGER);
}
@@ -488,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 f99a3c3..13798ba 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. */
@@ -150,7 +152,8 @@
int compilationReason,
int result,
int apkType,
- String isa) {
+ String isa,
+ String apkPath) {
int dexMetadataType = getDexMetadataType(dexMetadataPath);
logger.write(
sessionId,
@@ -167,6 +170,16 @@
uid,
compilationReason,
compilerFilter,
+ ArtStatsLog.ART_DATUM_REPORTED__KIND__ART_DATUM_DEX2OAT_DEX_CODE_BYTES,
+ getDexBytes(apkPath),
+ dexMetadataType,
+ apkType,
+ isa);
+ logger.write(
+ sessionId,
+ uid,
+ compilationReason,
+ compilerFilter,
ArtStatsLog.ART_DATUM_REPORTED__KIND__ART_DATUM_DEX2OAT_TOTAL_TIME,
compileTime,
dexMetadataType,
@@ -181,6 +194,37 @@
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) {
if (dexMetadataPath == null) {
return ArtStatsLog.ART_DATUM_REPORTED__DEX_METADATA_TYPE__ART_DEX_METADATA_TYPE_NONE;
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/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 6ff8d6f..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. */
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..24bb1b1 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -110,7 +110,6 @@
"libhardware",
"libhardware_legacy",
"libhidlbase",
- "libkeystore_binder",
"libmtp",
"libnativehelper",
"libprocessgroup",
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 46ec65d..80f43d7 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;
@@ -2330,6 +2331,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/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
index 100d3ea..f5876fa 100644
--- a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java
@@ -33,12 +33,6 @@
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.uidPoliciesToString;
import static android.net.NetworkPolicyManager.uidRulesToString;
import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
@@ -49,7 +43,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;
@@ -141,7 +134,6 @@
import android.util.ArrayMap;
import android.util.DataUnit;
import android.util.Log;
-import android.util.Pair;
import android.util.Range;
import android.util.RecurrenceRule;
@@ -1844,68 +1836,6 @@
reset(mStatsService);
}
- /**
- * 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));
- }
- }
-
private void enableRestrictedMode(boolean enable) throws Exception {
mService.mRestrictedNetworkingMode = enable;
mService.updateRestrictedModeAllowlistUL();
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 f014119..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
@@ -108,7 +108,8 @@
COMPILATION_REASON,
RESULT_CODE,
ArtStatsLog.ART_DATUM_REPORTED__APK_TYPE__ART_APK_TYPE_BASE,
- INSTRUCTION_SET);
+ INSTRUCTION_SET,
+ apk.toString());
// Assert
verifyWrites(ArtStatsLog.
@@ -139,7 +140,8 @@
COMPILATION_REASON,
RESULT_CODE,
ArtStatsLog.ART_DATUM_REPORTED__APK_TYPE__ART_APK_TYPE_BASE,
- INSTRUCTION_SET);
+ INSTRUCTION_SET,
+ apk.toString());
// Assert
verifyWrites(ArtStatsLog.
@@ -170,7 +172,8 @@
COMPILATION_REASON,
RESULT_CODE,
ArtStatsLog.ART_DATUM_REPORTED__APK_TYPE__ART_APK_TYPE_BASE,
- INSTRUCTION_SET);
+ INSTRUCTION_SET,
+ apk.toString());
// Assert
verifyWrites(ArtStatsLog.
@@ -199,7 +202,8 @@
COMPILATION_REASON,
RESULT_CODE,
ArtStatsLog.ART_DATUM_REPORTED__APK_TYPE__ART_APK_TYPE_BASE,
- INSTRUCTION_SET);
+ INSTRUCTION_SET,
+ apk.toString());
// Assert
verifyWrites(ArtStatsLog.
@@ -229,7 +233,8 @@
COMPILATION_REASON,
RESULT_CODE,
ArtStatsLog.ART_DATUM_REPORTED__APK_TYPE__ART_APK_TYPE_BASE,
- INSTRUCTION_SET);
+ INSTRUCTION_SET,
+ apk.toString());
// Assert
verifyWrites(ArtStatsLog.
@@ -267,6 +272,16 @@
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,
+ COMPILATION_REASON,
+ COMPILER_FILTER,
ArtStatsLog.ART_DATUM_REPORTED__KIND__ART_DATUM_DEX2OAT_TOTAL_TIME,
COMPILE_TIME,
dexMetadataType,
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 7c234fc..f027cd1 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -4351,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;
@@ -4916,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/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/stub/RcsCapabilityExchangeImplBase.java b/telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java
index a117adc..57616d35 100644
--- a/telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/RcsCapabilityExchangeImplBase.java
@@ -441,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/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/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 14c72f1..e050495 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -18,8 +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;
@@ -59,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;
@@ -85,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;
@@ -577,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
@@ -1228,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);
@@ -2791,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
@@ -3031,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 {
@@ -3144,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.
}
@@ -8133,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();
@@ -9141,7 +9157,7 @@
final int expectedOwnerUidWithoutIncludeFlag =
shouldInclLocationSensitiveOwnerUidWithoutIncludeFlag
- ? Process.myUid() : INVALID_UID;
+ ? myUid : INVALID_UID;
assertEquals(expectedOwnerUidWithoutIncludeFlag, getOwnerUidNetCapsPermission(
myUid, myUid, false /* includeLocationSensitiveInfo */));
@@ -9160,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
@@ -9184,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
@@ -9204,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 */
);
}
@@ -9221,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 */
);
}
@@ -9239,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
@@ -9266,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
@@ -10253,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)))
@@ -10709,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();
@@ -11316,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));
@@ -11364,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
@@ -12186,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/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 631c862..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());
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/exclude.sh b/tools/hiddenapi/exclude.sh
index 18c4054..73eacc0 100755
--- a/tools/hiddenapi/exclude.sh
+++ b/tools/hiddenapi/exclude.sh
@@ -35,7 +35,7 @@
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))
+ ENTRIES=$(grep -E "^L(${RE})/" || true <(git show $1:$file))
if [[ -n "${ENTRIES}" ]]; then
echo -e "\e[1m\e[31m$file $1 contains the following entries\e[0m"
echo -e "\e[1m\e[31mfor packages that are handled using UnsupportedAppUsage. Please remove\e[0m"