summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--api/current.txt7
-rw-r--r--api/system-current.txt7
-rw-r--r--core/java/android/app/ActivityThread.java90
-rw-r--r--core/java/android/app/ApplicationErrorReport.java8
-rw-r--r--core/java/android/content/pm/ApplicationInfo.java5
-rw-r--r--core/java/android/content/pm/PackageParser.java21
-rw-r--r--core/java/android/inputmethodservice/ExtractEditLayout.java2
-rw-r--r--core/java/android/net/IpPrefix.java15
-rw-r--r--core/java/android/net/RouteInfo.java8
-rw-r--r--core/java/android/os/Debug.java90
-rw-r--r--core/java/android/security/keymaster/KeyCharacteristics.java53
-rw-r--r--core/java/android/security/keymaster/KeymasterArguments.java9
-rw-r--r--core/java/android/security/keymaster/KeymasterDefs.java54
-rw-r--r--core/java/android/text/SpanSet.java13
-rw-r--r--core/java/android/widget/ProgressBar.java4
-rw-r--r--core/java/com/android/internal/content/NativeLibraryHelper.java31
-rw-r--r--core/java/com/android/internal/os/InstallerConnection.java30
-rw-r--r--core/java/com/android/internal/os/PowerProfile.java2
-rw-r--r--core/java/com/android/internal/os/ZygoteInit.java11
-rw-r--r--core/jni/AndroidRuntime.cpp13
-rw-r--r--core/jni/com_android_internal_content_NativeLibraryHelper.cpp46
-rw-r--r--core/res/res/values/attrs_manifest.xml6
-rw-r--r--core/res/res/values/public.xml1
-rw-r--r--core/tests/coretests/apks/install_jni_lib/Android.mk8
-rw-r--r--core/tests/coretests/apks/install_jni_lib/com_android_frameworks_coretests_JNITest.cpp6
-rw-r--r--core/tests/coretests/apks/install_jni_lib_open_from_apk/Android.mk11
-rw-r--r--core/tests/coretests/apks/install_jni_lib_open_from_apk/AndroidManifest.xml28
-rw-r--r--core/tests/coretests/apks/install_jni_lib_open_from_apk/res/values/strings.xml19
-rw-r--r--core/tests/coretests/apks/install_jni_lib_open_from_apk/src/com/android/frameworks/coretests/JNITests.java26
-rw-r--r--core/tests/coretests/apks/install_jni_lib_open_from_apk/src/com/android/frameworks/coretests/OpenFromApkActivity.java38
-rw-r--r--core/tests/coretests/src/android/net/IpPrefixTest.java32
-rw-r--r--core/tests/coretests/src/android/net/RouteInfoTest.java1
-rw-r--r--include/androidfw/ResourceTypes.h2
-rw-r--r--keystore/java/android/security/AndroidKeyStore.java157
-rw-r--r--keystore/java/android/security/AndroidKeyStoreProvider.java20
-rw-r--r--keystore/java/android/security/ArrayUtils.java62
-rw-r--r--keystore/java/android/security/EcIesParameterSpec.java264
-rw-r--r--keystore/java/android/security/KeyGeneratorSpec.java268
-rw-r--r--keystore/java/android/security/KeyPairGeneratorSpec.java318
-rw-r--r--keystore/java/android/security/KeyStoreCipherSpi.java113
-rw-r--r--keystore/java/android/security/KeyStoreCryptoOperationChunkedStreamer.java57
-rw-r--r--keystore/java/android/security/KeyStoreHmacSpi.java38
-rw-r--r--keystore/java/android/security/KeyStoreKeyCharacteristics.java68
-rw-r--r--keystore/java/android/security/KeyStoreKeyConstraints.java609
-rw-r--r--keystore/java/android/security/KeyStoreKeyGeneratorSpi.java137
-rw-r--r--keystore/java/android/security/KeyStoreKeyProperties.java274
-rw-r--r--keystore/java/android/security/KeyStoreKeySpec.java157
-rw-r--r--keystore/java/android/security/KeyStoreParameter.java305
-rw-r--r--keystore/java/android/security/KeyStoreSecretKeyFactorySpi.java128
-rw-r--r--keystore/java/android/security/KeymasterUtils.java323
-rw-r--r--keystore/tests/src/android/security/KeyPairGeneratorSpecTest.java56
-rw-r--r--keystore/tests/src/android/security/KeyStoreTest.java18
-rw-r--r--libs/hwui/FontRenderer.cpp2
-rw-r--r--libs/hwui/RenderBufferCache.cpp5
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java5
-rw-r--r--rs/java/android/renderscript/FieldPacker.java225
-rw-r--r--rs/java/android/renderscript/RenderScript.java40
-rw-r--r--rs/java/android/renderscript/RenderScriptCacheDir.java40
-rw-r--r--rs/java/android/renderscript/ScriptC.java4
-rw-r--r--rs/java/android/renderscript/ScriptGroup2.java16
-rw-r--r--rs/java/android/renderscript/ScriptIntrinsicBlur.java2
-rw-r--r--rs/jni/android_renderscript_RenderScript.cpp20
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java2
-rwxr-xr-xservices/core/java/com/android/server/am/ActiveServices.java2
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java28
-rw-r--r--services/core/java/com/android/server/am/ActivityStack.java21
-rw-r--r--services/core/java/com/android/server/pm/Installer.java135
-rw-r--r--services/core/java/com/android/server/pm/PackageDexOptimizer.java91
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java30
-rw-r--r--services/core/java/com/android/server/pm/SELinuxMMAC.java217
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java31
-rw-r--r--tools/aapt/Android.mk2
-rw-r--r--tools/aapt/Images.cpp1
-rw-r--r--tools/aapt/Resource.cpp1
-rw-r--r--tools/aapt/ResourceTable.cpp3
75 files changed, 2902 insertions, 2090 deletions
diff --git a/api/current.txt b/api/current.txt
index 144f292..c21fa0a 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -547,6 +547,7 @@ package android {
field public static final int expandableListViewWhiteStyle = 16843446; // 0x10102b6
field public static final int exported = 16842768; // 0x1010010
field public static final int extraTension = 16843371; // 0x101026b
+ field public static final int extractNativeLibs = 16843990; // 0x10104d6
field public static final int factor = 16843219; // 0x10101d3
field public static final int fadeDuration = 16843384; // 0x1010278
field public static final int fadeEnabled = 16843390; // 0x101027e
@@ -8368,6 +8369,7 @@ package android.content.pm {
field public static final int FLAG_ALLOW_TASK_REPARENTING = 32; // 0x20
field public static final int FLAG_DEBUGGABLE = 2; // 0x2
field public static final int FLAG_EXTERNAL_STORAGE = 262144; // 0x40000
+ field public static final int FLAG_EXTRACT_NATIVE_LIBS = 268435456; // 0x10000000
field public static final int FLAG_FACTORY_TEST = 16; // 0x10
field public static final int FLAG_FULL_BACKUP_ONLY = 67108864; // 0x4000000
field public static final int FLAG_HAS_CODE = 4; // 0x4
@@ -16996,6 +16998,7 @@ package android.net {
}
public final class IpPrefix implements android.os.Parcelable {
+ method public boolean contains(java.net.InetAddress);
method public int describeContents();
method public java.net.InetAddress getAddress();
method public int getPrefixLength();
@@ -17515,7 +17518,7 @@ package android.net.http {
method public static android.net.http.HttpResponseCache getInstalled();
method public int getNetworkCount();
method public int getRequestCount();
- method public static android.net.http.HttpResponseCache install(java.io.File, long) throws java.io.IOException;
+ method public static synchronized android.net.http.HttpResponseCache install(java.io.File, long) throws java.io.IOException;
method public long maxSize();
method public java.net.CacheRequest put(java.net.URI, java.net.URLConnection) throws java.io.IOException;
method public long size();
@@ -41519,7 +41522,7 @@ package java.lang {
method public static double nextUp(double);
method public static float nextUp(float);
method public static double pow(double, double);
- method public static synchronized double random();
+ method public static double random();
method public static double rint(double);
method public static long round(double);
method public static int round(float);
diff --git a/api/system-current.txt b/api/system-current.txt
index 7ab0e48..6732a09 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -617,6 +617,7 @@ package android {
field public static final int expandableListViewWhiteStyle = 16843446; // 0x10102b6
field public static final int exported = 16842768; // 0x1010010
field public static final int extraTension = 16843371; // 0x101026b
+ field public static final int extractNativeLibs = 16843990; // 0x10104d6
field public static final int factor = 16843219; // 0x10101d3
field public static final int fadeDuration = 16843384; // 0x1010278
field public static final int fadeEnabled = 16843390; // 0x101027e
@@ -8616,6 +8617,7 @@ package android.content.pm {
field public static final int FLAG_ALLOW_TASK_REPARENTING = 32; // 0x20
field public static final int FLAG_DEBUGGABLE = 2; // 0x2
field public static final int FLAG_EXTERNAL_STORAGE = 262144; // 0x40000
+ field public static final int FLAG_EXTRACT_NATIVE_LIBS = 268435456; // 0x10000000
field public static final int FLAG_FACTORY_TEST = 16; // 0x10
field public static final int FLAG_FULL_BACKUP_ONLY = 67108864; // 0x4000000
field public static final int FLAG_HAS_CODE = 4; // 0x4
@@ -18259,6 +18261,7 @@ package android.net {
}
public final class IpPrefix implements android.os.Parcelable {
+ method public boolean contains(java.net.InetAddress);
method public int describeContents();
method public java.net.InetAddress getAddress();
method public int getPrefixLength();
@@ -18843,7 +18846,7 @@ package android.net.http {
method public static android.net.http.HttpResponseCache getInstalled();
method public int getNetworkCount();
method public int getRequestCount();
- method public static android.net.http.HttpResponseCache install(java.io.File, long) throws java.io.IOException;
+ method public static synchronized android.net.http.HttpResponseCache install(java.io.File, long) throws java.io.IOException;
method public long maxSize();
method public java.net.CacheRequest put(java.net.URI, java.net.URLConnection) throws java.io.IOException;
method public long size();
@@ -44055,7 +44058,7 @@ package java.lang {
method public static double nextUp(double);
method public static float nextUp(float);
method public static double pow(double, double);
- method public static synchronized double random();
+ method public static double random();
method public static double rint(double);
method public static long round(double);
method public static int round(float);
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index beb244b..b063209 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -97,7 +97,7 @@ import android.view.ViewRootImpl;
import android.view.Window;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
-import android.renderscript.RenderScript;
+import android.renderscript.RenderScriptCacheDir;
import android.security.AndroidKeyStoreProvider;
import com.android.internal.app.IVoiceInteractor;
@@ -261,6 +261,8 @@ public final class ActivityThread {
IActivityManager.ContentProviderHolder holder;
boolean acquiring = true;
int requests = 1;
+ // Set if there was a runtime exception when trying to acquire the provider.
+ RuntimeException runtimeException = null;
}
// The lock of mProviderMap protects the following variables.
@@ -3187,7 +3189,7 @@ public final class ActivityThread {
if (cv == null) {
mThumbnailCanvas = cv = new Canvas();
}
-
+
cv.setBitmap(thumbnail);
if (!r.activity.onCreateThumbnail(thumbnail, cv)) {
mAvailThumbnailBitmap = thumbnail;
@@ -3485,12 +3487,12 @@ public final class ActivityThread {
private void handleWindowVisibility(IBinder token, boolean show) {
ActivityClientRecord r = mActivities.get(token);
-
+
if (r == null) {
Log.w(TAG, "handleWindowVisibility: no activity for token " + token);
return;
}
-
+
if (!show && !r.stopped) {
performStopActivityInner(r, null, show, false);
} else if (show && r.stopped) {
@@ -3918,10 +3920,10 @@ public final class ActivityThread {
}
}
}
-
+
if (DEBUG_CONFIGURATION) Slog.v(TAG, "Relaunching activity "
+ tmp.token + ": changedConfig=" + changedConfig);
-
+
// If there was a pending configuration change, execute it first.
if (changedConfig != null) {
mCurDefaultDisplayDpi = changedConfig.densityDpi;
@@ -4118,7 +4120,7 @@ public final class ActivityThread {
if (config == null) {
return;
}
-
+
if (DEBUG_CONFIGURATION) Slog.v(TAG, "Handle configuration changed: "
+ config);
@@ -4166,7 +4168,7 @@ public final class ActivityThread {
if (DEBUG_CONFIGURATION) Slog.v(TAG, "Handle activity config changed: "
+ r.activityInfo.name);
-
+
performConfigurationChanged(r.activity, mCompatConfiguration);
freeTextLayoutCachesIfNeeded(r.activity.mCurrentConfig.diff(mCompatConfiguration));
@@ -4247,7 +4249,7 @@ public final class ActivityThread {
ApplicationPackageManager.handlePackageBroadcast(cmd, packages,
hasPkgInfo);
}
-
+
final void handleLowMemory() {
ArrayList<ComponentCallbacks2> callbacks = collectComponentCallbacks(true, null);
@@ -4294,10 +4296,10 @@ public final class ActivityThread {
String[] packages = getPackageManager().getPackagesForUid(uid);
// If there are several packages in this application we won't
- // initialize the graphics disk caches
+ // initialize the graphics disk caches
if (packages != null && packages.length == 1) {
HardwareRenderer.setupDiskCache(cacheDir);
- RenderScript.setupDiskCache(cacheDir);
+ RenderScriptCacheDir.setupDiskCache(cacheDir);
}
} catch (RemoteException e) {
// Ignore
@@ -4670,39 +4672,55 @@ public final class ActivityThread {
}
IActivityManager.ContentProviderHolder holder = null;
- if (first) {
- // Multiple threads may try to acquire the same provider at the same time.
- // When this happens, we only let the first one really gets provider.
- // Other threads just wait for its result.
- // Note that we cannot hold the lock while acquiring and installing the
- // provider since it might take a long time to run and it could also potentially
- // be re-entrant in the case where the provider is in the same process.
- try {
+ try {
+ if (first) {
+ // Multiple threads may try to acquire the same provider at the same time.
+ // When this happens, we only let the first one really gets provider.
+ // Other threads just wait for its result.
+ // Note that we cannot hold the lock while acquiring and installing the
+ // provider since it might take a long time to run and it could also potentially
+ // be re-entrant in the case where the provider is in the same process.
holder = ActivityManagerNative.getDefault().getContentProvider(
getApplicationThread(), auth, userId, stable);
- } catch (RemoteException ex) {
+ } else {
+ synchronized (r) {
+ while (r.acquiring) {
+ try {
+ r.wait();
+ } catch (InterruptedException e) {
+ }
+ }
+ holder = r.holder;
+ }
}
+ } catch (RemoteException ex) {
+ } catch (RuntimeException e) {
synchronized (r) {
- r.holder = holder;
- r.acquiring = false;
- r.notifyAll();
+ r.runtimeException = e;
}
- } else {
- synchronized (r) {
- while (r.acquiring) {
- try {
- r.wait();
- } catch (InterruptedException e) {
- }
+ } finally {
+ if (first) {
+ synchronized (r) {
+ r.holder = holder;
+ r.acquiring = false;
+ r.notifyAll();
}
- holder = r.holder;
}
- }
- synchronized (mAcquiringProviderMap) {
- if (--r.requests == 0) {
- mAcquiringProviderMap.remove(key);
+
+ synchronized (mAcquiringProviderMap) {
+ if (--r.requests == 0) {
+ mAcquiringProviderMap.remove(key);
+ }
+ }
+
+ if (r.runtimeException != null) {
+ // Was set when the first thread tried to acquire the provider,
+ // but we should make sure it is thrown for all threads trying to
+ // acquire the provider.
+ throw r.runtimeException;
}
}
+
if (holder == null) {
Slog.e(TAG, "Failed to find provider info for " + auth);
return null;
@@ -5222,7 +5240,7 @@ public final class ActivityThread {
if (mPendingConfiguration == null ||
mPendingConfiguration.isOtherSeqNewer(newConfig)) {
mPendingConfiguration = newConfig;
-
+
sendMessage(H.CONFIGURATION_CHANGED, newConfig);
}
}
diff --git a/core/java/android/app/ApplicationErrorReport.java b/core/java/android/app/ApplicationErrorReport.java
index 6c2511e..8692336 100644
--- a/core/java/android/app/ApplicationErrorReport.java
+++ b/core/java/android/app/ApplicationErrorReport.java
@@ -235,10 +235,13 @@ public class ApplicationErrorReport implements Parcelable {
dest.writeString(processName);
dest.writeLong(time);
dest.writeInt(systemApp ? 1 : 0);
+ dest.writeInt(crashInfo != null ? 1 : 0);
switch (type) {
case TYPE_CRASH:
- crashInfo.writeToParcel(dest, flags);
+ if (crashInfo != null) {
+ crashInfo.writeToParcel(dest, flags);
+ }
break;
case TYPE_ANR:
anrInfo.writeToParcel(dest, flags);
@@ -259,10 +262,11 @@ public class ApplicationErrorReport implements Parcelable {
processName = in.readString();
time = in.readLong();
systemApp = in.readInt() == 1;
+ boolean hasCrashInfo = in.readInt() == 1;
switch (type) {
case TYPE_CRASH:
- crashInfo = new CrashInfo(in);
+ crashInfo = hasCrashInfo ? new CrashInfo(in) : null;
anrInfo = null;
batteryInfo = null;
runningServiceInfo = null;
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index b3c558b..4a087da 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -346,6 +346,11 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
public static final int FLAG_USES_CLEARTEXT_TRAFFIC = 1<<27;
/**
+ * When set installer extracts native libs from .apk files.
+ */
+ public static final int FLAG_EXTRACT_NATIVE_LIBS = 1<<28;
+
+ /**
* Value for {@link #flags}: true if code from this application will need to be
* loaded into other applications' processes. On devices that support multiple
* instruction sets, this implies the code might be loaded into a process that's
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 5320929..53aa6ff 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -268,6 +268,7 @@ public class PackageParser {
public final boolean coreApp;
public final boolean multiArch;
+ public final boolean extractNativeLibs;
public PackageLite(String codePath, ApkLite baseApk, String[] splitNames,
String[] splitCodePaths, int[] splitRevisionCodes) {
@@ -283,6 +284,7 @@ public class PackageParser {
this.splitRevisionCodes = splitRevisionCodes;
this.coreApp = baseApk.coreApp;
this.multiArch = baseApk.multiArch;
+ this.extractNativeLibs = baseApk.extractNativeLibs;
}
public List<String> getAllCodePaths() {
@@ -309,10 +311,12 @@ public class PackageParser {
public final Signature[] signatures;
public final boolean coreApp;
public final boolean multiArch;
+ public final boolean extractNativeLibs;
public ApkLite(String codePath, String packageName, String splitName, int versionCode,
int revisionCode, int installLocation, List<VerifierInfo> verifiers,
- Signature[] signatures, boolean coreApp, boolean multiArch) {
+ Signature[] signatures, boolean coreApp, boolean multiArch,
+ boolean extractNativeLibs) {
this.codePath = codePath;
this.packageName = packageName;
this.splitName = splitName;
@@ -323,6 +327,7 @@ public class PackageParser {
this.signatures = signatures;
this.coreApp = coreApp;
this.multiArch = multiArch;
+ this.extractNativeLibs = extractNativeLibs;
}
}
@@ -1269,6 +1274,7 @@ public class PackageParser {
int revisionCode = 0;
boolean coreApp = false;
boolean multiArch = false;
+ boolean extractNativeLibs = true;
for (int i = 0; i < attrs.getAttributeCount(); i++) {
final String attr = attrs.getAttributeName(i);
@@ -1307,14 +1313,17 @@ public class PackageParser {
final String attr = attrs.getAttributeName(i);
if ("multiArch".equals(attr)) {
multiArch = attrs.getAttributeBooleanValue(i, false);
- break;
+ }
+ if ("extractNativeLibs".equals(attr)) {
+ extractNativeLibs = attrs.getAttributeBooleanValue(i, true);
}
}
}
}
return new ApkLite(codePath, packageSplit.first, packageSplit.second, versionCode,
- revisionCode, installLocation, verifiers, signatures, coreApp, multiArch);
+ revisionCode, installLocation, verifiers, signatures, coreApp, multiArch,
+ extractNativeLibs);
}
/**
@@ -2567,6 +2576,12 @@ public class PackageParser {
ai.flags |= ApplicationInfo.FLAG_MULTIARCH;
}
+ if (sa.getBoolean(
+ com.android.internal.R.styleable.AndroidManifestApplication_extractNativeLibs,
+ true)) {
+ ai.flags |= ApplicationInfo.FLAG_EXTRACT_NATIVE_LIBS;
+ }
+
String str;
str = sa.getNonConfigurationString(
com.android.internal.R.styleable.AndroidManifestApplication_permission, 0);
diff --git a/core/java/android/inputmethodservice/ExtractEditLayout.java b/core/java/android/inputmethodservice/ExtractEditLayout.java
index 5696839..e902443 100644
--- a/core/java/android/inputmethodservice/ExtractEditLayout.java
+++ b/core/java/android/inputmethodservice/ExtractEditLayout.java
@@ -163,6 +163,8 @@ public class ExtractEditLayout extends LinearLayout {
mCallback.onDestroyActionMode(this);
mCallback = null;
+ mMenu.close();
+
mExtractActionButton.setVisibility(VISIBLE);
mEditButton.setVisibility(INVISIBLE);
diff --git a/core/java/android/net/IpPrefix.java b/core/java/android/net/IpPrefix.java
index b268986..6b4f2d5 100644
--- a/core/java/android/net/IpPrefix.java
+++ b/core/java/android/net/IpPrefix.java
@@ -170,6 +170,21 @@ public final class IpPrefix implements Parcelable {
}
/**
+ * Determines whether the prefix contains the specified address.
+ *
+ * @param address An {@link InetAddress} to test.
+ * @return {@code true} if the prefix covers the given address.
+ */
+ public boolean contains(InetAddress address) {
+ byte[] addrBytes = (address == null) ? null : address.getAddress();
+ if (addrBytes == null || addrBytes.length != this.address.length) {
+ return false;
+ }
+ NetworkUtils.maskRawAddress(addrBytes, prefixLength);
+ return Arrays.equals(this.address, addrBytes);
+ }
+
+ /**
* Returns a string representation of this {@code IpPrefix}.
*
* @return a string such as {@code "192.0.2.0/24"} or {@code "2001:db8:1:2::/64"}.
diff --git a/core/java/android/net/RouteInfo.java b/core/java/android/net/RouteInfo.java
index cfd20a0..90a2460 100644
--- a/core/java/android/net/RouteInfo.java
+++ b/core/java/android/net/RouteInfo.java
@@ -367,13 +367,7 @@ public final class RouteInfo implements Parcelable {
* @return {@code true} if the destination and prefix length cover the given address.
*/
public boolean matches(InetAddress destination) {
- if (destination == null) return false;
-
- // match the route destination and destination with prefix length
- InetAddress dstNet = NetworkUtils.getNetworkPart(destination,
- mDestination.getPrefixLength());
-
- return mDestination.getAddress().equals(dstNet);
+ return mDestination.contains(destination);
}
/**
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index 2d92c7b..1c85db4 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -34,6 +34,7 @@ import java.lang.annotation.Target;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.Map;
import org.apache.harmony.dalvik.ddmc.Chunk;
import org.apache.harmony.dalvik.ddmc.ChunkHandler;
@@ -1035,6 +1036,95 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo
}
/**
+ * Returns the value of a particular runtime statistic or {@code null} if no
+ * such runtime statistic exists.
+ *
+ * <p>The following table lists the runtime statistics that the runtime supports.
+ * Note runtime statistics may be added or removed in a future API level.</p>
+ *
+ * <table>
+ * <thead>
+ * <tr>
+ * <th>Runtime statistic name</th>
+ * <th>Meaning</th>
+ * <th>Example</th>
+ * <th>Supported (API Levels)</th>
+ * </tr>
+ * </thead>
+ * <tbody>
+ * <tr>
+ * <td>art.gc.gc-count</td>
+ * <td>The number of garbage collection runs.</td>
+ * <td>{@code 164}</td>
+ * <td>23</td>
+ * </tr>
+ * <tr>
+ * <td>art.gc.gc-time</td>
+ * <td>The total duration of garbage collection runs in ms.</td>
+ * <td>{@code 62364}</td>
+ * <td>23</td>
+ * </tr>
+ * <tr>
+ * <td>art.gc.bytes-allocated</td>
+ * <td>The total number of bytes that the application allocated.</td>
+ * <td>{@code 1463948408}</td>
+ * <td>23</td>
+ * </tr>
+ * <tr>
+ * <td>art.gc.bytes-freed</td>
+ * <td>The total number of bytes that garbage collection reclaimed.</td>
+ * <td>{@code 1313493084}</td>
+ * <td>23</td>
+ * </tr>
+ * <tr>
+ * <td>art.gc.blocking-gc-count</td>
+ * <td>The number of blocking garbage collection runs.</td>
+ * <td>{@code 2}</td>
+ * <td>23</td>
+ * </tr>
+ * <tr>
+ * <td>art.gc.blocking-gc-time</td>
+ * <td>The total duration of blocking garbage collection runs in ms.</td>
+ * <td>{@code 804}</td>
+ * <td>23</td>
+ * </tr>
+ * <tr>
+ * <td>art.gc.gc-count-rate-histogram</td>
+ * <td>The histogram of the number of garbage collection runs per 10 seconds.</td>
+ * <td>{@code 0:34503,1:45350,2:11281,3:8088,4:43,5:8}</td>
+ * <td>23</td>
+ * </tr>
+ * <tr>
+ * <td>art.gc.blocking-gc-count-rate-histogram</td>
+ * <td>The histogram of the number of garbage collection runs per 10 seconds.</td>
+ * <td>{@code 0:99269,1:1,2:1}</td>
+ * <td>23</td>
+ * </tr>
+ * </tbody>
+ * </table>
+ *
+ * @param statName
+ * the name of the runtime statistic to look up.
+ * @return the value of the specified runtime statistic or {@code null} if the
+ * runtime statistic doesn't exist.
+ * @hide
+ */
+ public static String getRuntimeStat(String statName) {
+ return VMDebug.getRuntimeStat(statName);
+ }
+
+ /**
+ * Returns a map of the names/values of the runtime statistics
+ * that {@link #getRuntimeStat()} supports.
+ *
+ * @return a map of the names/values of the supported runtime statistics.
+ * @hide
+ */
+ public static Map<String, String> getRuntimeStats() {
+ return VMDebug.getRuntimeStats();
+ }
+
+ /**
* Returns the size of the native heap.
* @return The size of the native heap in bytes.
*/
diff --git a/core/java/android/security/keymaster/KeyCharacteristics.java b/core/java/android/security/keymaster/KeyCharacteristics.java
index b803a1b..b3a3aad 100644
--- a/core/java/android/security/keymaster/KeyCharacteristics.java
+++ b/core/java/android/security/keymaster/KeyCharacteristics.java
@@ -19,6 +19,8 @@ package android.security.keymaster;
import android.os.Parcel;
import android.os.Parcelable;
+import java.util.ArrayList;
+import java.util.Date;
import java.util.List;
/**
@@ -30,10 +32,12 @@ public class KeyCharacteristics implements Parcelable {
public static final Parcelable.Creator<KeyCharacteristics> CREATOR = new
Parcelable.Creator<KeyCharacteristics>() {
+ @Override
public KeyCharacteristics createFromParcel(Parcel in) {
return new KeyCharacteristics(in);
}
+ @Override
public KeyCharacteristics[] newArray(int length) {
return new KeyCharacteristics[length];
}
@@ -50,6 +54,7 @@ public class KeyCharacteristics implements Parcelable {
return 0;
}
+ @Override
public void writeToParcel(Parcel out, int flags) {
swEnforced.writeToParcel(out, flags);
hwEnforced.writeToParcel(out, flags);
@@ -59,5 +64,53 @@ public class KeyCharacteristics implements Parcelable {
swEnforced = KeymasterArguments.CREATOR.createFromParcel(in);
hwEnforced = KeymasterArguments.CREATOR.createFromParcel(in);
}
+
+ public Integer getInteger(int tag) {
+ if (hwEnforced.containsTag(tag)) {
+ return hwEnforced.getInt(tag, -1);
+ } else if (swEnforced.containsTag(tag)) {
+ return swEnforced.getInt(tag, -1);
+ } else {
+ return null;
+ }
+ }
+
+ public int getInt(int tag, int defaultValue) {
+ Integer result = getInteger(tag);
+ return (result != null) ? result : defaultValue;
+ }
+
+ public List<Integer> getInts(int tag) {
+ List<Integer> result = new ArrayList<Integer>();
+ result.addAll(hwEnforced.getInts(tag));
+ result.addAll(swEnforced.getInts(tag));
+ return result;
+ }
+
+ public Date getDate(int tag) {
+ Date result = hwEnforced.getDate(tag, null);
+ if (result == null) {
+ result = swEnforced.getDate(tag, null);
+ }
+ return result;
+ }
+
+ public Date getDate(int tag, Date defaultValue) {
+ if (hwEnforced.containsTag(tag)) {
+ return hwEnforced.getDate(tag, null);
+ } else if (hwEnforced.containsTag(tag)) {
+ return swEnforced.getDate(tag, null);
+ } else {
+ return defaultValue;
+ }
+ }
+
+ public boolean getBoolean(KeyCharacteristics keyCharacteristics, int tag) {
+ if (keyCharacteristics.hwEnforced.containsTag(tag)) {
+ return keyCharacteristics.hwEnforced.getBoolean(tag, false);
+ } else {
+ return keyCharacteristics.swEnforced.getBoolean(tag, false);
+ }
+ }
}
diff --git a/core/java/android/security/keymaster/KeymasterArguments.java b/core/java/android/security/keymaster/KeymasterArguments.java
index b5fd4bd..8ed288c 100644
--- a/core/java/android/security/keymaster/KeymasterArguments.java
+++ b/core/java/android/security/keymaster/KeymasterArguments.java
@@ -34,9 +34,12 @@ public class KeymasterArguments implements Parcelable {
public static final Parcelable.Creator<KeymasterArguments> CREATOR = new
Parcelable.Creator<KeymasterArguments>() {
+ @Override
public KeymasterArguments createFromParcel(Parcel in) {
return new KeymasterArguments(in);
}
+
+ @Override
public KeymasterArguments[] newArray(int size) {
return new KeymasterArguments[size];
}
@@ -54,6 +57,12 @@ public class KeymasterArguments implements Parcelable {
mArguments.add(new KeymasterIntArgument(tag, value));
}
+ public void addInts(int tag, int... values) {
+ for (int value : values) {
+ addInt(tag, value);
+ }
+ }
+
public void addBoolean(int tag) {
mArguments.add(new KeymasterBooleanArgument(tag));
}
diff --git a/core/java/android/security/keymaster/KeymasterDefs.java b/core/java/android/security/keymaster/KeymasterDefs.java
index e94a312..d3953b3 100644
--- a/core/java/android/security/keymaster/KeymasterDefs.java
+++ b/core/java/android/security/keymaster/KeymasterDefs.java
@@ -47,21 +47,17 @@ public final class KeymasterDefs {
public static final int KM_TAG_PURPOSE = KM_ENUM_REP | 1;
public static final int KM_TAG_ALGORITHM = KM_ENUM | 2;
public static final int KM_TAG_KEY_SIZE = KM_INT | 3;
- public static final int KM_TAG_BLOCK_MODE = KM_ENUM | 4;
- public static final int KM_TAG_DIGEST = KM_ENUM | 5;
- public static final int KM_TAG_MAC_LENGTH = KM_INT | 6;
- public static final int KM_TAG_PADDING = KM_ENUM | 7;
- public static final int KM_TAG_RETURN_UNAUTHED = KM_BOOL | 8;
- public static final int KM_TAG_CALLER_NONCE = KM_BOOL | 9;
+ public static final int KM_TAG_BLOCK_MODE = KM_ENUM_REP | 4;
+ public static final int KM_TAG_DIGEST = KM_ENUM_REP | 5;
+ public static final int KM_TAG_PADDING = KM_ENUM_REP | 6;
+ public static final int KM_TAG_RETURN_UNAUTHED = KM_BOOL | 7;
+ public static final int KM_TAG_CALLER_NONCE = KM_BOOL | 8;
public static final int KM_TAG_RESCOPING_ADD = KM_ENUM_REP | 101;
public static final int KM_TAG_RESCOPING_DEL = KM_ENUM_REP | 102;
public static final int KM_TAG_BLOB_USAGE_REQUIREMENTS = KM_ENUM | 705;
public static final int KM_TAG_RSA_PUBLIC_EXPONENT = KM_LONG | 200;
- public static final int KM_TAG_DSA_GENERATOR = KM_BIGNUM | 201;
- public static final int KM_TAG_DSA_P = KM_BIGNUM | 202;
- public static final int KM_TAG_DSA_Q = KM_BIGNUM | 203;
public static final int KM_TAG_ACTIVE_DATETIME = KM_DATE | 400;
public static final int KM_TAG_ORIGINATION_EXPIRE_DATETIME = KM_DATE | 401;
public static final int KM_TAG_USAGE_EXPIRE_DATETIME = KM_DATE | 402;
@@ -88,43 +84,21 @@ public final class KeymasterDefs {
public static final int KM_TAG_NONCE = KM_BYTES | 1001;
public static final int KM_TAG_CHUNK_LENGTH = KM_INT | 1002;
public static final int KM_TAG_AUTH_TOKEN = KM_BYTES | 1003;
+ public static final int KM_TAG_MAC_LENGTH = KM_INT | 1004;
// Algorithm values.
public static final int KM_ALGORITHM_RSA = 1;
- public static final int KM_ALGORITHM_DSA = 2;
- public static final int KM_ALGORITHM_ECDSA = 3;
- public static final int KM_ALGORITHM_ECIES = 4;
+ public static final int KM_ALGORITHM_EC = 3;
public static final int KM_ALGORITHM_AES = 32;
- public static final int KM_ALGORITHM_3DES = 33;
- public static final int KM_ALGORITHM_SKIPJACK = 34;
- public static final int KM_ALGORITHM_MARS = 48;
- public static final int KM_ALGORITHM_RC6 = 49;
- public static final int KM_ALGORITHM_SERPENT = 50;
- public static final int KM_ALGORITHM_TWOFISH = 51;
- public static final int KM_ALGORITHM_IDEA = 52;
- public static final int KM_ALGORITHM_RC5 = 53;
- public static final int KM_ALGORITHM_CAST5 = 54;
- public static final int KM_ALGORITHM_BLOWFISH = 55;
- public static final int KM_ALGORITHM_RC4 = 64;
- public static final int KM_ALGORITHM_CHACHA20 = 65;
public static final int KM_ALGORITHM_HMAC = 128;
// Block modes.
public static final int KM_MODE_FIRST_UNAUTHENTICATED = 1;
public static final int KM_MODE_ECB = KM_MODE_FIRST_UNAUTHENTICATED;
public static final int KM_MODE_CBC = 2;
- public static final int KM_MODE_CBC_CTS = 3;
public static final int KM_MODE_CTR = 4;
- public static final int KM_MODE_OFB = 5;
- public static final int KM_MODE_CFB = 6;
- public static final int KM_MODE_XTS = 7;
public static final int KM_MODE_FIRST_AUTHENTICATED = 32;
public static final int KM_MODE_GCM = KM_MODE_FIRST_AUTHENTICATED;
- public static final int KM_MODE_OCB = 33;
- public static final int KM_MODE_CCM = 34;
- public static final int KM_MODE_FIRST_MAC = 128;
- public static final int KM_MODE_CMAC = KM_MODE_FIRST_MAC;
- public static final int KM_MODE_POLY1305 = 129;
// Padding modes.
public static final int KM_PAD_NONE = 1;
@@ -132,11 +106,7 @@ public final class KeymasterDefs {
public static final int KM_PAD_RSA_PSS = 3;
public static final int KM_PAD_RSA_PKCS1_1_5_ENCRYPT = 4;
public static final int KM_PAD_RSA_PKCS1_1_5_SIGN = 5;
- public static final int KM_PAD_ANSI_X923 = 32;
- public static final int KM_PAD_ISO_10126 = 33;
- public static final int KM_PAD_ZERO = 64;
- public static final int KM_PAD_PKCS7 = 65;
- public static final int KM_PAD_ISO_7816_4 = 66;
+ public static final int KM_PAD_PKCS7 = 64;
// Digest modes.
public static final int KM_DIGEST_NONE = 0;
@@ -146,9 +116,6 @@ public final class KeymasterDefs {
public static final int KM_DIGEST_SHA_2_256 = 4;
public static final int KM_DIGEST_SHA_2_384 = 5;
public static final int KM_DIGEST_SHA_2_512 = 6;
- public static final int KM_DIGEST_SHA_3_256 = 7;
- public static final int KM_DIGEST_SHA_3_384 = 8;
- public static final int KM_DIGEST_SHA_3_512 = 9;
// Key origins.
public static final int KM_ORIGIN_HARDWARE = 0;
@@ -168,9 +135,11 @@ public final class KeymasterDefs {
// Key formats.
public static final int KM_KEY_FORMAT_X509 = 0;
public static final int KM_KEY_FORMAT_PKCS8 = 1;
- public static final int KM_KEY_FORMAT_PKCS12 = 2;
public static final int KM_KEY_FORMAT_RAW = 3;
+ // User authenticators.
+ public static final int HW_AUTH_PASSWORD = 1 << 0;
+
// Error codes.
public static final int KM_ERROR_OK = 0;
public static final int KM_ERROR_ROOT_OF_TRUST_ALREADY_SET = -1;
@@ -215,7 +184,6 @@ public final class KeymasterDefs {
public static final int KM_ERROR_INVALID_TAG = -40;
public static final int KM_ERROR_MEMORY_ALLOCATION_FAILED = -41;
public static final int KM_ERROR_INVALID_RESCOPING = -42;
- public static final int KM_ERROR_INVALID_DSA_PARAMS = -43;
public static final int KM_ERROR_IMPORT_PARAMETER_MISMATCH = -44;
public static final int KM_ERROR_SECURE_HW_ACCESS_DENIED = -45;
public static final int KM_ERROR_OPERATION_CANCELLED = -46;
diff --git a/core/java/android/text/SpanSet.java b/core/java/android/text/SpanSet.java
index 3ca6033..00f1493 100644
--- a/core/java/android/text/SpanSet.java
+++ b/core/java/android/text/SpanSet.java
@@ -17,6 +17,7 @@
package android.text;
import java.lang.reflect.Array;
+import java.util.Arrays;
/**
* A cached set of spans. Caches the result of {@link Spanned#getSpans(int, int, Class)} and then
@@ -54,6 +55,7 @@ public class SpanSet<E> {
spanFlags = new int[length];
}
+ int prevNumberOfSpans = numberOfSpans;
numberOfSpans = 0;
for (int i = 0; i < length; i++) {
final E span = allSpans[i];
@@ -71,6 +73,12 @@ public class SpanSet<E> {
numberOfSpans++;
}
+
+ // cleanup extra spans left over from previous init() call
+ if (numberOfSpans < prevNumberOfSpans) {
+ // prevNumberofSpans was > 0, therefore spans != null
+ Arrays.fill(spans, numberOfSpans, prevNumberOfSpans, null);
+ }
}
/**
@@ -103,9 +111,8 @@ public class SpanSet<E> {
* Removes all internal references to the spans to avoid memory leaks.
*/
public void recycle() {
- // The spans array is guaranteed to be not null when numberOfSpans is > 0
- for (int i = 0; i < numberOfSpans; i++) {
- spans[i] = null; // prevent a leak: no reference kept when TextLine is recycled
+ if (spans != null) {
+ Arrays.fill(spans, 0, numberOfSpans, null);
}
}
}
diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java
index de1bbc7..358dbde 100644
--- a/core/java/android/widget/ProgressBar.java
+++ b/core/java/android/widget/ProgressBar.java
@@ -1812,9 +1812,7 @@ public class ProgressBar extends View {
}
if (mRefreshProgressRunnable != null) {
removeCallbacks(mRefreshProgressRunnable);
- }
- if (mRefreshProgressRunnable != null && mRefreshIsPosted) {
- removeCallbacks(mRefreshProgressRunnable);
+ mRefreshIsPosted = false;
}
if (mAccessibilityEventSender != null) {
removeCallbacks(mAccessibilityEventSender);
diff --git a/core/java/com/android/internal/content/NativeLibraryHelper.java b/core/java/com/android/internal/content/NativeLibraryHelper.java
index 02f675c..f479f4f 100644
--- a/core/java/com/android/internal/content/NativeLibraryHelper.java
+++ b/core/java/com/android/internal/content/NativeLibraryHelper.java
@@ -33,6 +33,7 @@ import android.content.pm.PackageParser.PackageLite;
import android.content.pm.PackageParser.PackageParserException;
import android.os.Build;
import android.os.SELinux;
+import android.os.SystemProperties;
import android.system.ErrnoException;
import android.system.Os;
import android.util.Slog;
@@ -74,6 +75,7 @@ public class NativeLibraryHelper {
final long[] apkHandles;
final boolean multiArch;
+ final boolean extractNativeLibs;
public static Handle create(File packageFile) throws IOException {
try {
@@ -86,14 +88,16 @@ public class NativeLibraryHelper {
public static Handle create(Package pkg) throws IOException {
return create(pkg.getAllCodePaths(),
- (pkg.applicationInfo.flags & ApplicationInfo.FLAG_MULTIARCH) != 0);
+ (pkg.applicationInfo.flags & ApplicationInfo.FLAG_MULTIARCH) != 0,
+ (pkg.applicationInfo.flags & ApplicationInfo.FLAG_EXTRACT_NATIVE_LIBS) != 0);
}
public static Handle create(PackageLite lite) throws IOException {
- return create(lite.getAllCodePaths(), lite.multiArch);
+ return create(lite.getAllCodePaths(), lite.multiArch, lite.extractNativeLibs);
}
- private static Handle create(List<String> codePaths, boolean multiArch) throws IOException {
+ private static Handle create(List<String> codePaths, boolean multiArch,
+ boolean extractNativeLibs) throws IOException {
final int size = codePaths.size();
final long[] apkHandles = new long[size];
for (int i = 0; i < size; i++) {
@@ -108,12 +112,13 @@ public class NativeLibraryHelper {
}
}
- return new Handle(apkHandles, multiArch);
+ return new Handle(apkHandles, multiArch, extractNativeLibs);
}
- Handle(long[] apkHandles, boolean multiArch) {
+ Handle(long[] apkHandles, boolean multiArch, boolean extractNativeLibs) {
this.apkHandles = apkHandles;
this.multiArch = multiArch;
+ this.extractNativeLibs = extractNativeLibs;
mGuard.open("close");
}
@@ -146,8 +151,8 @@ public class NativeLibraryHelper {
private static native long nativeSumNativeBinaries(long handle, String cpuAbi);
- private native static int nativeCopyNativeBinaries(long handle,
- String sharedLibraryPath, String abiToCopy);
+ private native static int nativeCopyNativeBinaries(long handle, String sharedLibraryPath,
+ String abiToCopy, boolean extractNativeLibs, boolean hasNativeBridge);
private static long sumNativeBinaries(Handle handle, String abi) {
long sum = 0;
@@ -167,7 +172,8 @@ public class NativeLibraryHelper {
*/
public static int copyNativeBinaries(Handle handle, File sharedLibraryDir, String abi) {
for (long apkHandle : handle.apkHandles) {
- int res = nativeCopyNativeBinaries(apkHandle, sharedLibraryDir.getPath(), abi);
+ int res = nativeCopyNativeBinaries(apkHandle, sharedLibraryDir.getPath(), abi,
+ handle.extractNativeLibs, HAS_NATIVE_BRIDGE);
if (res != INSTALL_SUCCEEDED) {
return res;
}
@@ -218,7 +224,8 @@ public class NativeLibraryHelper {
/**
* Remove the native binaries of a given package. This deletes the files
*/
- public static void removeNativeBinariesFromDirLI(File nativeLibraryRoot, boolean deleteRootDir) {
+ public static void removeNativeBinariesFromDirLI(File nativeLibraryRoot,
+ boolean deleteRootDir) {
if (DEBUG_NATIVE) {
Slog.w(TAG, "Deleting native binaries from: " + nativeLibraryRoot.getPath());
}
@@ -247,7 +254,8 @@ public class NativeLibraryHelper {
// asked to or this will prevent installation of future updates.
if (deleteRootDir) {
if (!nativeLibraryRoot.delete()) {
- Slog.w(TAG, "Could not delete native binary directory: " + nativeLibraryRoot.getPath());
+ Slog.w(TAG, "Could not delete native binary directory: " +
+ nativeLibraryRoot.getPath());
}
}
}
@@ -416,6 +424,9 @@ public class NativeLibraryHelper {
// We don't care about the other return values for now.
private static final int BITCODE_PRESENT = 1;
+ private static final boolean HAS_NATIVE_BRIDGE =
+ !"0".equals(SystemProperties.get("ro.dalvik.vm.native.bridge", "0"));
+
private static native int hasRenderscriptBitcode(long apkHandle);
public static boolean hasRenderscriptBitcode(Handle handle) throws IOException {
diff --git a/core/java/com/android/internal/os/InstallerConnection.java b/core/java/com/android/internal/os/InstallerConnection.java
index a4cdf19..671bf24 100644
--- a/core/java/com/android/internal/os/InstallerConnection.java
+++ b/core/java/com/android/internal/os/InstallerConnection.java
@@ -90,12 +90,15 @@ public class InstallerConnection {
}
}
- public int dexopt(String apkPath, int uid, boolean isPublic, String instructionSet) {
- return dexopt(apkPath, uid, isPublic, "*", instructionSet, false, false, null);
+ public int dexopt(String apkPath, int uid, boolean isPublic,
+ String instructionSet, int dexoptNeeded) {
+ return dexopt(apkPath, uid, isPublic, "*", instructionSet, dexoptNeeded,
+ false, false, null);
}
public int dexopt(String apkPath, int uid, boolean isPublic, String pkgName,
- String instructionSet, boolean vmSafeMode, boolean debuggable, String outputPath) {
+ String instructionSet, int dexoptNeeded, boolean vmSafeMode,
+ boolean debuggable, String outputPath) {
StringBuilder builder = new StringBuilder("dexopt");
builder.append(' ');
builder.append(apkPath);
@@ -106,6 +109,8 @@ public class InstallerConnection {
builder.append(pkgName);
builder.append(' ');
builder.append(instructionSet);
+ builder.append(' ');
+ builder.append(dexoptNeeded);
builder.append(vmSafeMode ? " 1" : " 0");
builder.append(debuggable ? " 1" : " 0");
builder.append(' ');
@@ -113,25 +118,6 @@ public class InstallerConnection {
return execute(builder.toString());
}
- public int patchoat(String apkPath, int uid, boolean isPublic, String instructionSet) {
- return patchoat(apkPath, uid, isPublic, "*", instructionSet);
- }
-
- public int patchoat(String apkPath, int uid, boolean isPublic, String pkgName,
- String instructionSet) {
- StringBuilder builder = new StringBuilder("patchoat");
- builder.append(' ');
- builder.append(apkPath);
- builder.append(' ');
- builder.append(uid);
- builder.append(isPublic ? " 1" : " 0");
- builder.append(' ');
- builder.append(pkgName);
- builder.append(' ');
- builder.append(instructionSet);
- return execute(builder.toString());
- }
-
private boolean connect() {
if (mSocket != null) {
return true;
diff --git a/core/java/com/android/internal/os/PowerProfile.java b/core/java/com/android/internal/os/PowerProfile.java
index b3bafa1..1038acf 100644
--- a/core/java/com/android/internal/os/PowerProfile.java
+++ b/core/java/com/android/internal/os/PowerProfile.java
@@ -256,7 +256,7 @@ public class PowerProfile {
final Double[] values = (Double[]) data;
if (values.length > level && level >= 0) {
return values[level];
- } else if (level < 0) {
+ } else if (level < 0 || values.length == 0) {
return 0;
} else {
return values[values.length - 1];
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 98638ed..50ddbd1 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -465,12 +465,11 @@ public class ZygoteInit {
try {
for (String classPathElement : classPathElements) {
- final byte dexopt = DexFile.isDexOptNeededInternal(classPathElement, "*", instructionSet,
- false /* defer */);
- if (dexopt == DexFile.DEXOPT_NEEDED) {
- installer.dexopt(classPathElement, Process.SYSTEM_UID, false, instructionSet);
- } else if (dexopt == DexFile.PATCHOAT_NEEDED) {
- installer.patchoat(classPathElement, Process.SYSTEM_UID, false, instructionSet);
+ final int dexoptNeeded = DexFile.getDexOptNeeded(
+ classPathElement, "*", instructionSet, false /* defer */);
+ if (dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) {
+ installer.dexopt(classPathElement, Process.SYSTEM_UID, false,
+ instructionSet, dexoptNeeded);
}
}
} catch (IOException ioe) {
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index d826303..0bfc0c9 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -586,6 +586,7 @@ int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv)
char localeOption[sizeof("-Duser.locale=") + PROPERTY_VALUE_MAX];
char lockProfThresholdBuf[sizeof("-Xlockprofthreshold:")-1 + PROPERTY_VALUE_MAX];
char nativeBridgeLibrary[sizeof("-XX:NativeBridge=") + PROPERTY_VALUE_MAX];
+ char cpuAbiListBuf[sizeof("--cpu-abilist=") + PROPERTY_VALUE_MAX];
bool checkJni = false;
property_get("dalvik.vm.checkjni", propBuf, "");
@@ -859,6 +860,18 @@ int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv)
// Dalvik-cache pruning counter.
parseRuntimeOption("dalvik.vm.zygote.max-boot-retry", cachePruneBuf,
"-Xzygote-max-boot-retry=");
+#if defined(__LP64__)
+ const char* cpu_abilist_property_name = "ro.product.cpu.abilist64";
+#else
+ const char* cpu_abilist_property_name = "ro.product.cpu.abilist32";
+#endif // defined(__LP64__)
+ property_get(cpu_abilist_property_name, propBuf, "");
+ if (propBuf[0] == '\0') {
+ ALOGE("%s is not expected to be empty", cpu_abilist_property_name);
+ return -1;
+ }
+ snprintf(cpuAbiListBuf, sizeof(cpuAbiListBuf), "--cpu-abilist=%s", propBuf);
+ addOption(cpuAbiListBuf);
initArgs.version = JNI_VERSION_1_4;
initArgs.options = mOptions.editArray();
diff --git a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
index 3c1993e..9307ff9 100644
--- a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
+++ b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
@@ -33,6 +33,7 @@
#include <string.h>
#include <time.h>
#include <unistd.h>
+#include <inttypes.h>
#include <sys/stat.h>
#include <sys/types.h>
@@ -173,7 +174,11 @@ sumFiles(JNIEnv*, void* arg, ZipFileRO* zipFile, ZipEntryRO zipEntry, const char
static install_status_t
copyFileIfChanged(JNIEnv *env, void* arg, ZipFileRO* zipFile, ZipEntryRO zipEntry, const char* fileName)
{
- jstring* javaNativeLibPath = (jstring*) arg;
+ void** args = reinterpret_cast<void**>(arg);
+ jstring* javaNativeLibPath = (jstring*) args[0];
+ jboolean extractNativeLibs = *(jboolean*) args[1];
+ jboolean hasNativeBridge = *(jboolean*) args[2];
+
ScopedUtfChars nativeLibPath(env, *javaNativeLibPath);
size_t uncompLen;
@@ -181,13 +186,31 @@ copyFileIfChanged(JNIEnv *env, void* arg, ZipFileRO* zipFile, ZipEntryRO zipEntr
long crc;
time_t modTime;
- if (!zipFile->getEntryInfo(zipEntry, NULL, &uncompLen, NULL, NULL, &when, &crc)) {
+ int method;
+ off64_t offset;
+
+ if (!zipFile->getEntryInfo(zipEntry, &method, &uncompLen, NULL, &offset, &when, &crc)) {
ALOGD("Couldn't read zip entry info\n");
return INSTALL_FAILED_INVALID_APK;
- } else {
- struct tm t;
- ZipUtils::zipTimeToTimespec(when, &t);
- modTime = mktime(&t);
+ }
+
+ if (!extractNativeLibs) {
+ // check if library is uncompressed and page-aligned
+ if (method != ZipFileRO::kCompressStored) {
+ ALOGD("Library '%s' is compressed - will not be able to open it directly from apk.\n",
+ fileName);
+ return INSTALL_FAILED_INVALID_APK;
+ }
+
+ if (offset % PAGE_SIZE != 0) {
+ ALOGD("Library '%s' is not page-aligned - will not be able to open it directly from"
+ " apk.\n", fileName);
+ return INSTALL_FAILED_INVALID_APK;
+ }
+
+ if (!hasNativeBridge) {
+ return INSTALL_SUCCEEDED;
+ }
}
// Build local file path
@@ -208,6 +231,9 @@ copyFileIfChanged(JNIEnv *env, void* arg, ZipFileRO* zipFile, ZipEntryRO zipEntr
}
// Only copy out the native file if it's different.
+ struct tm t;
+ ZipUtils::zipTimeToTimespec(when, &t);
+ modTime = mktime(&t);
struct stat64 st;
if (!isFileDifferent(localFileName, uncompLen, modTime, crc, &st)) {
return INSTALL_SUCCEEDED;
@@ -465,10 +491,12 @@ static int findSupportedAbi(JNIEnv *env, jlong apkHandle, jobjectArray supported
static jint
com_android_internal_content_NativeLibraryHelper_copyNativeBinaries(JNIEnv *env, jclass clazz,
- jlong apkHandle, jstring javaNativeLibPath, jstring javaCpuAbi)
+ jlong apkHandle, jstring javaNativeLibPath, jstring javaCpuAbi,
+ jboolean extractNativeLibs, jboolean hasNativeBridge)
{
+ void* args[] = { &javaNativeLibPath, &extractNativeLibs, &hasNativeBridge };
return (jint) iterateOverNativeFiles(env, apkHandle, javaCpuAbi,
- copyFileIfChanged, &javaNativeLibPath);
+ copyFileIfChanged, reinterpret_cast<void*>(args));
}
static jlong
@@ -548,7 +576,7 @@ static JNINativeMethod gMethods[] = {
"(J)V",
(void *)com_android_internal_content_NativeLibraryHelper_close},
{"nativeCopyNativeBinaries",
- "(JLjava/lang/String;Ljava/lang/String;)I",
+ "(JLjava/lang/String;Ljava/lang/String;ZZ)I",
(void *)com_android_internal_content_NativeLibraryHelper_copyNativeBinaries},
{"nativeSumNativeBinaries",
"(JLjava/lang/String;)J",
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index ea592cf..f69772a 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1021,6 +1021,10 @@
<p>The default value of this attribute is <code>false</code>. -->
<attr name="resumeWhilePausing" format="boolean" />
+ <!-- When set installer will extract native libraries. If set to false
+ libraries in the apk must be stored and page-aligned. -->
+ <attr name="extractNativeLibs" format="boolean"/>
+
<!-- The <code>manifest</code> tag is the root of an
<code>AndroidManifest.xml</code> file,
describing the contents of an Android package (.apk) file. One
@@ -1151,8 +1155,8 @@
@hide -->
<attr name="usesCleartextTraffic" />
<attr name="multiArch" />
+ <attr name="extractNativeLibs" />
</declare-styleable>
-
<!-- The <code>permission</code> tag declares a security permission that can be
used to control access from other packages to specific components or
features in your package (or other packages). See the
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 2bb9aa8..bfd0d26 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2598,4 +2598,5 @@
<public type="style" name="Theme.DeviceDefault.Dialog.Alert" />
<public type="style" name="Theme.DeviceDefault.Light.Dialog.Alert" />
+ <public type="attr" name="extractNativeLibs" />
</resources>
diff --git a/core/tests/coretests/apks/install_jni_lib/Android.mk b/core/tests/coretests/apks/install_jni_lib/Android.mk
index b61ea8e..7322e8d 100644
--- a/core/tests/coretests/apks/install_jni_lib/Android.mk
+++ b/core/tests/coretests/apks/install_jni_lib/Android.mk
@@ -23,6 +23,14 @@ LOCAL_SHARED_LIBRARIES := \
libnativehelper
LOCAL_MODULE := libframeworks_coretests_jni
+
+# this does not prevent build system
+# from installing library to /system/lib
LOCAL_MODULE_TAGS := tests
+# .. we want to avoid that... so we put it somewhere
+# bionic linker cant find it without outside help (nativetests):
+LOCAL_MODULE_PATH_32 := $($(TARGET_2ND_ARCH_VAR_PREFIX)TARGET_OUT_DATA_NATIVE_TESTS)/$(LOCAL_MODULE)
+LOCAL_MODULE_PATH_64 := $(TARGET_OUT_DATA_NATIVE_TESTS)/$(LOCAL_MODULE)
+
include $(BUILD_SHARED_LIBRARY)
diff --git a/core/tests/coretests/apks/install_jni_lib/com_android_frameworks_coretests_JNITest.cpp b/core/tests/coretests/apks/install_jni_lib/com_android_frameworks_coretests_JNITest.cpp
index 957fc4a..e0b616c 100644
--- a/core/tests/coretests/apks/install_jni_lib/com_android_frameworks_coretests_JNITest.cpp
+++ b/core/tests/coretests/apks/install_jni_lib/com_android_frameworks_coretests_JNITest.cpp
@@ -27,8 +27,8 @@ static JNINativeMethod sMethods[] = {
{ "checkFunction", "()I", (void*) checkFunction },
};
-int register_com_android_framework_coretests_JNITests(JNIEnv* env) {
- return jniRegisterNativeMethods(env, "com/android/framework/coretests/JNITests", sMethods,
+int register_com_android_frameworks_coretests_JNITests(JNIEnv* env) {
+ return jniRegisterNativeMethods(env, "com/android/frameworks/coretests/JNITests", sMethods,
NELEM(sMethods));
}
@@ -46,7 +46,7 @@ jint JNI_OnLoad(JavaVM *jvm, void *reserved) {
return JNI_ERR;
}
- if ((status = android::register_com_android_framework_coretests_JNITests(e)) < 0) {
+ if ((status = android::register_com_android_frameworks_coretests_JNITests(e)) < 0) {
return JNI_ERR;
}
diff --git a/core/tests/coretests/apks/install_jni_lib_open_from_apk/Android.mk b/core/tests/coretests/apks/install_jni_lib_open_from_apk/Android.mk
new file mode 100644
index 0000000..5fa2405
--- /dev/null
+++ b/core/tests/coretests/apks/install_jni_lib_open_from_apk/Android.mk
@@ -0,0 +1,11 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := install_jni_lib_open_from_apk
+
+LOCAL_JNI_SHARED_LIBRARIES_ZIP_OPTIONS := -0
+LOCAL_PAGE_ALIGN_JNI_SHARED_LIBRARIES := true
+
+include $(FrameworkCoreTests_BUILD_PACKAGE)
diff --git a/core/tests/coretests/apks/install_jni_lib_open_from_apk/AndroidManifest.xml b/core/tests/coretests/apks/install_jni_lib_open_from_apk/AndroidManifest.xml
new file mode 100644
index 0000000..190f894
--- /dev/null
+++ b/core/tests/coretests/apks/install_jni_lib_open_from_apk/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.frameworks.coretests.install_jni_lib_open_from_apk">
+
+ <application android:hasCode="true" android:label="@string/app_name" android:extractNativeLibs="false">
+ <activity android:name="com.android.frameworks.coretests.OpenFromApkActivity"
+ android:label="@string/app_name">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/core/tests/coretests/apks/install_jni_lib_open_from_apk/res/values/strings.xml b/core/tests/coretests/apks/install_jni_lib_open_from_apk/res/values/strings.xml
new file mode 100644
index 0000000..8c2a0bf
--- /dev/null
+++ b/core/tests/coretests/apks/install_jni_lib_open_from_apk/res/values/strings.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="app_name">Load From Apk Test</string>
+</resources>
diff --git a/core/tests/coretests/apks/install_jni_lib_open_from_apk/src/com/android/frameworks/coretests/JNITests.java b/core/tests/coretests/apks/install_jni_lib_open_from_apk/src/com/android/frameworks/coretests/JNITests.java
new file mode 100644
index 0000000..4f9176c
--- /dev/null
+++ b/core/tests/coretests/apks/install_jni_lib_open_from_apk/src/com/android/frameworks/coretests/JNITests.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.frameworks.coretests;
+
+public class JNITests {
+ static {
+ System.loadLibrary("frameworks_coretests_jni");
+ }
+
+ public static native int checkFunction();
+}
diff --git a/core/tests/coretests/apks/install_jni_lib_open_from_apk/src/com/android/frameworks/coretests/OpenFromApkActivity.java b/core/tests/coretests/apks/install_jni_lib_open_from_apk/src/com/android/frameworks/coretests/OpenFromApkActivity.java
new file mode 100644
index 0000000..524cad7
--- /dev/null
+++ b/core/tests/coretests/apks/install_jni_lib_open_from_apk/src/com/android/frameworks/coretests/OpenFromApkActivity.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.frameworks.coretests;
+
+import android.app.Activity;
+import android.widget.TextView;
+import android.os.Bundle;
+
+public class OpenFromApkActivity extends Activity {
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ TextView tv = new TextView(this);
+
+ int i = JNITests.checkFunction();
+
+ tv.setText("All is well: i=" + i);
+
+ setContentView(tv);
+ }
+
+}
diff --git a/core/tests/coretests/src/android/net/IpPrefixTest.java b/core/tests/coretests/src/android/net/IpPrefixTest.java
index cf278fb..fcc6389 100644
--- a/core/tests/coretests/src/android/net/IpPrefixTest.java
+++ b/core/tests/coretests/src/android/net/IpPrefixTest.java
@@ -29,6 +29,10 @@ import junit.framework.TestCase;
public class IpPrefixTest extends TestCase {
+ private static InetAddress Address(String addr) {
+ return InetAddress.parseNumericAddress(addr);
+ }
+
// Explicitly cast everything to byte because "error: possible loss of precision".
private static final byte[] IPV4_BYTES = { (byte) 192, (byte) 0, (byte) 2, (byte) 4};
private static final byte[] IPV6_BYTES = {
@@ -209,6 +213,34 @@ public class IpPrefixTest extends TestCase {
}
@SmallTest
+ public void testContains() {
+ IpPrefix p = new IpPrefix("2001:db8:f00::ace:d00d/127");
+ assertTrue(p.contains(Address("2001:db8:f00::ace:d00c")));
+ assertTrue(p.contains(Address("2001:db8:f00::ace:d00d")));
+ assertFalse(p.contains(Address("2001:db8:f00::ace:d00e")));
+ assertFalse(p.contains(Address("2001:db8:f00::bad:d00d")));
+ assertFalse(p.contains(Address("2001:4868:4860::8888")));
+ assertFalse(p.contains(null));
+ assertFalse(p.contains(Address("8.8.8.8")));
+
+ p = new IpPrefix("192.0.2.0/23");
+ assertTrue(p.contains(Address("192.0.2.43")));
+ assertTrue(p.contains(Address("192.0.3.21")));
+ assertFalse(p.contains(Address("192.0.0.21")));
+ assertFalse(p.contains(Address("8.8.8.8")));
+ assertFalse(p.contains(Address("2001:4868:4860::8888")));
+
+ IpPrefix ipv6Default = new IpPrefix("::/0");
+ assertTrue(ipv6Default.contains(Address("2001:db8::f00")));
+ assertFalse(ipv6Default.contains(Address("192.0.2.1")));
+
+ IpPrefix ipv4Default = new IpPrefix("0.0.0.0/0");
+ assertTrue(ipv4Default.contains(Address("255.255.255.255")));
+ assertTrue(ipv4Default.contains(Address("192.0.2.1")));
+ assertFalse(ipv4Default.contains(Address("2001:db8::f00")));
+ }
+
+ @SmallTest
public void testHashCode() {
IpPrefix p;
int oldCode = -1;
diff --git a/core/tests/coretests/src/android/net/RouteInfoTest.java b/core/tests/coretests/src/android/net/RouteInfoTest.java
index 0b88bc7..831fefd 100644
--- a/core/tests/coretests/src/android/net/RouteInfoTest.java
+++ b/core/tests/coretests/src/android/net/RouteInfoTest.java
@@ -90,6 +90,7 @@ public class RouteInfoTest extends TestCase {
assertFalse(r.matches(Address("2001:db8:f00::ace:d00e")));
assertFalse(r.matches(Address("2001:db8:f00::bad:d00d")));
assertFalse(r.matches(Address("2001:4868:4860::8888")));
+ assertFalse(r.matches(Address("8.8.8.8")));
r = new PatchedRouteInfo(Prefix("192.0.2.0/23"), null, "wlan0");
assertTrue(r.matches(Address("192.0.2.43")));
diff --git a/include/androidfw/ResourceTypes.h b/include/androidfw/ResourceTypes.h
index ff2c6d1..8de0138 100644
--- a/include/androidfw/ResourceTypes.h
+++ b/include/androidfw/ResourceTypes.h
@@ -112,7 +112,7 @@ struct __assertChar16Size {
*
* The PNG chunk type is "npTc".
*/
-struct Res_png_9patch
+struct alignas(uintptr_t) Res_png_9patch
{
Res_png_9patch() : wasDeserialized(false), xDivsOffset(0),
yDivsOffset(0), colorsOffset(0) { }
diff --git a/keystore/java/android/security/AndroidKeyStore.java b/keystore/java/android/security/AndroidKeyStore.java
index dcc79be..fcee9fc 100644
--- a/keystore/java/android/security/AndroidKeyStore.java
+++ b/keystore/java/android/security/AndroidKeyStore.java
@@ -19,6 +19,8 @@ package android.security;
import com.android.org.conscrypt.OpenSSLEngine;
import com.android.org.conscrypt.OpenSSLKeyHolder;
+import libcore.util.EmptyArray;
+
import android.security.keymaster.KeyCharacteristics;
import android.security.keymaster.KeymasterArguments;
import android.security.keymaster.KeymasterDefs;
@@ -46,6 +48,7 @@ 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;
@@ -112,13 +115,6 @@ public class AndroidKeyStore extends KeyStoreSpi {
if (keymasterAlgorithm == -1) {
throw new UnrecoverableKeyException("Key algorithm unknown");
}
- @KeyStoreKeyConstraints.AlgorithmEnum int keyAlgorithm;
- try {
- keyAlgorithm = KeyStoreKeyConstraints.Algorithm.fromKeymaster(keymasterAlgorithm);
- } catch (IllegalArgumentException e) {
- throw (UnrecoverableKeyException)
- new UnrecoverableKeyException("Unsupported key algorithm").initCause(e);
- }
int keymasterDigest =
keyCharacteristics.hwEnforced.getInt(KeymasterDefs.KM_TAG_DIGEST, -1);
@@ -126,20 +122,11 @@ public class AndroidKeyStore extends KeyStoreSpi {
keymasterDigest =
keyCharacteristics.swEnforced.getInt(KeymasterDefs.KM_TAG_DIGEST, -1);
}
- @KeyStoreKeyConstraints.DigestEnum Integer digest = null;
- if (keymasterDigest != -1) {
- try {
- digest = KeyStoreKeyConstraints.Digest.fromKeymaster(keymasterDigest);
- } catch (IllegalArgumentException e) {
- throw (UnrecoverableKeyException)
- new UnrecoverableKeyException("Unsupported digest").initCause(e);
- }
- }
String keyAlgorithmString;
try {
- keyAlgorithmString = KeyStoreKeyConstraints.Algorithm.toJCASecretKeyAlgorithm(
- keyAlgorithm, digest);
+ keyAlgorithmString = KeymasterUtils.getJcaSecretKeyAlgorithm(
+ keymasterAlgorithm, keymasterDigest);
} catch (IllegalArgumentException e) {
throw (UnrecoverableKeyException)
new UnrecoverableKeyException("Unsupported secret key type").initCause(e);
@@ -456,91 +443,95 @@ public class AndroidKeyStore extends KeyStoreSpi {
}
String keyAlgorithmString = key.getAlgorithm();
- @KeyStoreKeyConstraints.AlgorithmEnum int keyAlgorithm;
- @KeyStoreKeyConstraints.DigestEnum Integer digest;
+ int keymasterAlgorithm;
+ int keymasterDigest;
try {
- keyAlgorithm =
- KeyStoreKeyConstraints.Algorithm.fromJCASecretKeyAlgorithm(keyAlgorithmString);
- digest = KeyStoreKeyConstraints.Digest.fromJCASecretKeyAlgorithm(keyAlgorithmString);
+ keymasterAlgorithm = KeymasterUtils.getKeymasterAlgorithmFromJcaSecretKeyAlgorithm(
+ keyAlgorithmString);
+ keymasterDigest =
+ KeymasterUtils.getKeymasterDigestfromJcaSecretKeyAlgorithm(keyAlgorithmString);
} catch (IllegalArgumentException e) {
throw new KeyStoreException("Unsupported secret key algorithm: " + keyAlgorithmString);
}
- if ((params.getAlgorithm() != null) && (params.getAlgorithm() != keyAlgorithm)) {
- throw new KeyStoreException("Key algorithm mismatch. Key: " + keyAlgorithmString
- + ", parameter spec: "
- + KeyStoreKeyConstraints.Algorithm.toString(params.getAlgorithm()));
- }
-
KeymasterArguments args = new KeymasterArguments();
- args.addInt(KeymasterDefs.KM_TAG_ALGORITHM,
- KeyStoreKeyConstraints.Algorithm.toKeymaster(keyAlgorithm));
-
- if (digest != null) {
- // Digest available from JCA key algorithm
- if (params.getDigest() != null) {
- // Digest also specified in parameters -- check that these two match
- if (digest != params.getDigest()) {
- throw new KeyStoreException("Key digest mismatch. Key: " + keyAlgorithmString
- + ", parameter spec: "
- + KeyStoreKeyConstraints.Digest.toString(params.getDigest()));
+ args.addInt(KeymasterDefs.KM_TAG_ALGORITHM, keymasterAlgorithm);
+
+ int[] keymasterDigests;
+ if (params.isDigestsSpecified()) {
+ // Digest(s) specified in parameters
+ keymasterDigests =
+ KeymasterUtils.getKeymasterDigestsFromJcaDigestAlgorithms(params.getDigests());
+ if (keymasterDigest != -1) {
+ // Digest also specified in the JCA key algorithm name.
+ if (!com.android.internal.util.ArrayUtils.contains(
+ keymasterDigests, keymasterDigest)) {
+ throw new KeyStoreException("Key digest mismatch"
+ + ". Key: " + keyAlgorithmString
+ + ", parameter spec: " + Arrays.asList(params.getDigests()));
}
}
} else {
- // Digest not available from JCA key algorithm
- digest = params.getDigest();
- }
- if (digest != null) {
- args.addInt(KeymasterDefs.KM_TAG_DIGEST,
- KeyStoreKeyConstraints.Digest.toKeymaster(digest));
- Integer digestOutputSizeBytes =
- KeyStoreKeyConstraints.Digest.getOutputSizeBytes(digest);
- if (digestOutputSizeBytes != null) {
- // TODO: Remove MAC length constraint once Keymaster API no longer requires it.
+ // No digest specified in parameters
+ if (keymasterDigest != -1) {
+ // Digest specified in the JCA key algorithm name.
+ keymasterDigests = new int[] {keymasterDigest};
+ } else {
+ keymasterDigests = EmptyArray.INT;
+ }
+ }
+ args.addInts(KeymasterDefs.KM_TAG_DIGEST, keymasterDigests);
+ if (keymasterDigests.length > 0) {
+ // TODO: Remove MAC length constraint once Keymaster API no longer requires it.
+ // This code will blow up if mode than one digest is specified.
+ int digestOutputSizeBytes =
+ KeymasterUtils.getDigestOutputSizeBytes(keymasterDigests[0]);
+ if (digestOutputSizeBytes != -1) {
// TODO: Switch to bits instead of bytes, once this is fixed in Keymaster
args.addInt(KeymasterDefs.KM_TAG_MAC_LENGTH, digestOutputSizeBytes);
}
}
- if (keyAlgorithm == KeyStoreKeyConstraints.Algorithm.HMAC) {
- if (digest == null) {
- throw new IllegalStateException("Digest algorithm must be specified for key"
- + " algorithm " + keyAlgorithmString);
+ if (keymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_HMAC) {
+ if (keymasterDigests.length == 0) {
+ throw new KeyStoreException("At least one digest algorithm must be specified"
+ + " for key algorithm " + keyAlgorithmString);
}
}
- @KeyStoreKeyConstraints.PurposeEnum int purposes = (params.getPurposes() != null)
- ? params.getPurposes()
- : (KeyStoreKeyConstraints.Purpose.ENCRYPT
- | KeyStoreKeyConstraints.Purpose.DECRYPT
- | KeyStoreKeyConstraints.Purpose.SIGN
- | KeyStoreKeyConstraints.Purpose.VERIFY);
- for (int keymasterPurpose :
- KeyStoreKeyConstraints.Purpose.allToKeymaster(purposes)) {
- args.addInt(KeymasterDefs.KM_TAG_PURPOSE, keymasterPurpose);
- }
- if (params.getBlockMode() != null) {
- args.addInt(KeymasterDefs.KM_TAG_BLOCK_MODE,
- KeyStoreKeyConstraints.BlockMode.toKeymaster(params.getBlockMode()));
- }
- if (params.getPadding() != null) {
- args.addInt(KeymasterDefs.KM_TAG_PADDING,
- KeyStoreKeyConstraints.Padding.toKeymaster(params.getPadding()));
- }
- if (params.getMaxUsesPerBoot() != null) {
- args.addInt(KeymasterDefs.KM_TAG_MAX_USES_PER_BOOT, params.getMaxUsesPerBoot());
+ @KeyStoreKeyProperties.PurposeEnum int purposes = params.getPurposes();
+ int[] keymasterBlockModes = KeymasterUtils.getKeymasterBlockModesFromJcaBlockModes(
+ params.getBlockModes());
+ if (((purposes & KeyStoreKeyProperties.Purpose.ENCRYPT) != 0)
+ && (params.isRandomizedEncryptionRequired())) {
+ for (int keymasterBlockMode : keymasterBlockModes) {
+ if (!KeymasterUtils.isKeymasterBlockModeIndCpaCompatible(keymasterBlockMode)) {
+ throw new KeyStoreException(
+ "Randomized encryption (IND-CPA) required but may be violated by block"
+ + " mode: "
+ + KeymasterUtils.getJcaBlockModeFromKeymasterBlockMode(
+ keymasterBlockMode)
+ + ". See KeyStoreParameter documentation.");
+ }
+ }
}
- if (params.getMinSecondsBetweenOperations() != null) {
- args.addInt(KeymasterDefs.KM_TAG_MIN_SECONDS_BETWEEN_OPS,
- params.getMinSecondsBetweenOperations());
+ for (int keymasterPurpose : KeyStoreKeyProperties.Purpose.allToKeymaster(purposes)) {
+ args.addInt(KeymasterDefs.KM_TAG_PURPOSE, keymasterPurpose);
}
- if (params.getUserAuthenticators().isEmpty()) {
+ args.addInts(KeymasterDefs.KM_TAG_BLOCK_MODE, keymasterBlockModes);
+ int[] keymasterPaddings = ArrayUtils.concat(
+ KeymasterUtils.getKeymasterPaddingsFromJcaEncryptionPaddings(
+ params.getEncryptionPaddings()),
+ KeymasterUtils.getKeymasterPaddingsFromJcaSignaturePaddings(
+ params.getSignaturePaddings()));
+ args.addInts(KeymasterDefs.KM_TAG_PADDING, keymasterPaddings);
+ if (params.getUserAuthenticators() == 0) {
args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
} else {
args.addInt(KeymasterDefs.KM_TAG_USER_AUTH_TYPE,
- KeyStoreKeyConstraints.UserAuthenticator.allToKeymaster(
+ KeyStoreKeyProperties.UserAuthenticator.allToKeymaster(
params.getUserAuthenticators()));
}
- if (params.getUserAuthenticationValidityDurationSeconds() != null) {
+ if (params.getUserAuthenticationValidityDurationSeconds() != -1) {
args.addInt(KeymasterDefs.KM_TAG_AUTH_TIMEOUT,
params.getUserAuthenticationValidityDurationSeconds());
}
@@ -557,9 +548,9 @@ public class AndroidKeyStore extends KeyStoreSpi {
// TODO: Remove this once keymaster does not require us to specify the size of imported key.
args.addInt(KeymasterDefs.KM_TAG_KEY_SIZE, keyMaterial.length * 8);
- if (((purposes & KeyStoreKeyConstraints.Purpose.ENCRYPT) != 0)
- || ((purposes & KeyStoreKeyConstraints.Purpose.DECRYPT) != 0)) {
- // Permit caller-specified IV. This is needed for the Cipher abstraction.
+ if (((purposes & KeyStoreKeyProperties.Purpose.ENCRYPT) != 0)
+ && (!params.isRandomizedEncryptionRequired())) {
+ // Permit caller-provided IV when encrypting with this key
args.addBoolean(KeymasterDefs.KM_TAG_CALLER_NONCE);
}
diff --git a/keystore/java/android/security/AndroidKeyStoreProvider.java b/keystore/java/android/security/AndroidKeyStoreProvider.java
index a59927d..43f3b30 100644
--- a/keystore/java/android/security/AndroidKeyStoreProvider.java
+++ b/keystore/java/android/security/AndroidKeyStoreProvider.java
@@ -49,14 +49,26 @@ public class AndroidKeyStoreProvider extends Provider {
// javax.crypto.KeyGenerator
put("KeyGenerator.AES", PACKAGE_NAME + ".KeyStoreKeyGeneratorSpi$AES");
+ put("KeyGenerator.HmacSHA1", PACKAGE_NAME + ".KeyStoreKeyGeneratorSpi$HmacSHA1");
+ put("KeyGenerator.HmacSHA224", PACKAGE_NAME + ".KeyStoreKeyGeneratorSpi$HmacSHA224");
put("KeyGenerator.HmacSHA256", PACKAGE_NAME + ".KeyStoreKeyGeneratorSpi$HmacSHA256");
+ put("KeyGenerator.HmacSHA384", PACKAGE_NAME + ".KeyStoreKeyGeneratorSpi$HmacSHA384");
+ put("KeyGenerator.HmacSHA512", PACKAGE_NAME + ".KeyStoreKeyGeneratorSpi$HmacSHA512");
// java.security.SecretKeyFactory
- put("SecretKeyFactory.AES", PACKAGE_NAME + ".KeyStoreSecretKeyFactorySpi");
- put("SecretKeyFactory.HmacSHA256", PACKAGE_NAME + ".KeyStoreSecretKeyFactorySpi");
+ putSecretKeyFactoryImpl("AES");
+ putSecretKeyFactoryImpl("HmacSHA1");
+ putSecretKeyFactoryImpl("HmacSHA224");
+ putSecretKeyFactoryImpl("HmacSHA256");
+ putSecretKeyFactoryImpl("HmacSHA384");
+ putSecretKeyFactoryImpl("HmacSHA512");
// javax.crypto.Mac
+ putMacImpl("HmacSHA1", PACKAGE_NAME + ".KeyStoreHmacSpi$HmacSHA1");
+ putMacImpl("HmacSHA224", PACKAGE_NAME + ".KeyStoreHmacSpi$HmacSHA224");
putMacImpl("HmacSHA256", PACKAGE_NAME + ".KeyStoreHmacSpi$HmacSHA256");
+ putMacImpl("HmacSHA384", PACKAGE_NAME + ".KeyStoreHmacSpi$HmacSHA384");
+ putMacImpl("HmacSHA512", PACKAGE_NAME + ".KeyStoreHmacSpi$HmacSHA512");
// javax.crypto.Cipher
putSymmetricCipherImpl("AES/ECB/NoPadding",
@@ -73,6 +85,10 @@ public class AndroidKeyStoreProvider extends Provider {
PACKAGE_NAME + ".KeyStoreCipherSpi$AES$CTR$NoPadding");
}
+ private void putSecretKeyFactoryImpl(String algorithm) {
+ put("SecretKeyFactory." + algorithm, PACKAGE_NAME + ".KeyStoreSecretKeyFactorySpi");
+ }
+
private void putMacImpl(String algorithm, String implClass) {
put("Mac." + algorithm, implClass);
put("Mac." + algorithm + " SupportedKeyClasses", KEYSTORE_SECRET_KEY_CLASS_NAME);
diff --git a/keystore/java/android/security/ArrayUtils.java b/keystore/java/android/security/ArrayUtils.java
new file mode 100644
index 0000000..2047d3f
--- /dev/null
+++ b/keystore/java/android/security/ArrayUtils.java
@@ -0,0 +1,62 @@
+package android.security;
+
+import libcore.util.EmptyArray;
+
+/**
+ * @hide
+ */
+abstract class ArrayUtils {
+ private ArrayUtils() {}
+
+ public static String[] nullToEmpty(String[] array) {
+ return (array != null) ? array : EmptyArray.STRING;
+ }
+
+ public static String[] cloneIfNotEmpty(String[] array) {
+ return ((array != null) && (array.length > 0)) ? array.clone() : array;
+ }
+
+ public static byte[] concat(byte[] arr1, byte[] arr2) {
+ return concat(arr1, 0, (arr1 != null) ? arr1.length : 0,
+ arr2, 0, (arr2 != null) ? arr2.length : 0);
+ }
+
+ public static byte[] concat(byte[] arr1, int offset1, int len1, byte[] arr2, int offset2,
+ int len2) {
+ if (len1 == 0) {
+ return subarray(arr2, offset2, len2);
+ } else if (len2 == 0) {
+ return subarray(arr1, offset1, len1);
+ } else {
+ byte[] result = new byte[len1 + len2];
+ System.arraycopy(arr1, offset1, result, 0, len1);
+ System.arraycopy(arr2, offset2, result, len1, len2);
+ return result;
+ }
+ }
+
+ public static byte[] subarray(byte[] arr, int offset, int len) {
+ if (len == 0) {
+ return EmptyArray.BYTE;
+ }
+ if ((offset == 0) && (len == arr.length)) {
+ return arr;
+ }
+ byte[] result = new byte[len];
+ System.arraycopy(arr, offset, result, 0, len);
+ return result;
+ }
+
+ public static int[] concat(int[] arr1, int[] arr2) {
+ if ((arr1 == null) || (arr1.length == 0)) {
+ return arr2;
+ } else if ((arr2 == null) || (arr2.length == 0)) {
+ return arr1;
+ } else {
+ int[] result = new int[arr1.length + arr2.length];
+ System.arraycopy(arr1, 0, result, 0, arr1.length);
+ System.arraycopy(arr2, 0, result, arr1.length, arr2.length);
+ return result;
+ }
+ }
+}
diff --git a/keystore/java/android/security/EcIesParameterSpec.java b/keystore/java/android/security/EcIesParameterSpec.java
new file mode 100644
index 0000000..3372da9
--- /dev/null
+++ b/keystore/java/android/security/EcIesParameterSpec.java
@@ -0,0 +1,264 @@
+package android.security;
+
+import android.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.security.spec.AlgorithmParameterSpec;
+
+import javax.crypto.Cipher;
+import javax.crypto.Mac;
+
+/**
+ * {@link AlgorithmParameterSpec} for ECIES (Integrated Encryption Scheme using Elliptic Curve
+ * cryptography) based on {@code ISO/IEC 18033-2}.
+ *
+ * <p>ECIES is a hybrid authenticated encryption scheme. Encryption is performed using an Elliptic
+ * Curve (EC) public key. The resulting ciphertext can be decrypted only using the corresponding EC
+ * private key. The scheme is called hybrid because the EC key is only used to securely encapsulate
+ * symmetric key material. Encryption of plaintext and authentication of the corresponding
+ * ciphertext is performed using symmetric cryptography.
+ *
+ * <p>Encryption using ECIES consists of two stages:
+ * <ol>
+ * <li>Key Encapsulation Mechanism (KEM) randomly generates symmetric key material and securely
+ * encapsulates it in the output so that it can be extracted by the KEM when decrypting.
+ * Encapsulated key material is represented in the output as an EC point.</li>
+ * <li>The above symmetric key material is used by Data Encapsulation Mechanism (DEM) to encrypt the
+ * provided plaintext and authenticate the ciphertext. The resulting authenticated ciphertext is
+ * then output. When decrypting, the DEM first authenticates the ciphertext and, only if it
+ * authenticates, decrypts the ciphertext and outputs the plaintext.</li>
+ * </ol>
+ *
+ * <p>Details of KEM:
+ * <ul>
+ * <li>Only curves with cofactor of {@code 1} are supported.</li>
+ * <li>{@code CheckMode}, {@code OldCofactorMode}, {@code CofactorMode}, and {@code SingleHashMode}
+ * are {@code 0}.
+ * <li>Point format is specified by {@link #getKemPointFormat()}.</li>
+ * <li>KDF algorithm is specified by {@link #getKemKdfAlgorithm()}.</li>
+ * </ul>
+ *
+ * <p>Details of DEM:
+ * <ul>
+ * <li>Only DEM1-like mechanism is supported, with its symmetric cipher (SC) specified by
+ * {@link #getDemCipherTransformation()} (e.g., {@code AES/CBC/NoPadding} for standard DEM1) and
+ * MAC algorithm specified by {@link #getDemMacAlgorithm()} (e.g., {@code HmacSHA1} for standard
+ * DEM1).</li>
+ * </ul>
+ *
+ * @hide
+ */
+public class EcIesParameterSpec implements AlgorithmParameterSpec {
+
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(value = {PointFormat.UNCOMPRESSED, PointFormat.COMPRESSED})
+ public @interface PointFormatEnum {}
+
+ /**
+ * Wire format of the EC point.
+ */
+ public static abstract class PointFormat {
+
+ private PointFormat() {}
+
+ /** Unspecified point format. */
+ public static final int UNSPECIFIED = -1;
+
+ /**
+ * Uncompressed point format: both coordinates are stored separately.
+ *
+ * <p>The wire format is byte {@code 0x04} followed by binary representation of the
+ * {@code x} coordinate followed by binary representation of the {@code y} coordinate. See
+ * {@code ISO 18033-2} section {@code 5.4.3}.
+ */
+ public static final int UNCOMPRESSED = 0;
+
+ /**
+ * Compressed point format: only one coordinate is stored.
+ *
+ * <p>The wire format is byte {@code 0x02} or {@code 0x03} (depending on the value of the
+ * stored coordinate) followed by the binary representation of the {@code x} coordinate.
+ * See {@code ISO 18033-2} section {@code 5.4.3}.
+ */
+ public static final int COMPRESSED = 1;
+ }
+
+ /**
+ * Default parameter spec: compressed point format, {@code HKDFwithSHA256}, DEM uses 128-bit AES
+ * GCM.
+ */
+ public static final EcIesParameterSpec DEFAULT = new EcIesParameterSpec(
+ PointFormat.COMPRESSED,
+ "HKDFwithSHA256",
+ "AES/GCM/NoPadding",
+ 128,
+ null,
+ 0);
+
+ private final @PointFormatEnum int mKemPointFormat;
+ private final String mKemKdfAlgorithm;
+ private final String mDemCipherTransformation;
+ private final int mDemCipherKeySize;
+ private final String mDemMacAlgorithm;
+ private final int mDemMacKeySize;
+
+ private EcIesParameterSpec(
+ @PointFormatEnum int kemPointFormat,
+ String kemKdfAlgorithm,
+ String demCipherTransformation,
+ int demCipherKeySize,
+ String demMacAlgorithm,
+ int demMacKeySize) {
+ mKemPointFormat = kemPointFormat;
+ mKemKdfAlgorithm = kemKdfAlgorithm;
+ mDemCipherTransformation = demCipherTransformation;
+ mDemCipherKeySize = demCipherKeySize;
+ mDemMacAlgorithm = demMacAlgorithm;
+ mDemMacKeySize = demMacKeySize;
+ }
+
+ /**
+ * Returns KEM EC point wire format or {@link PointFormat#UNSPECIFIED} if not specified.
+ */
+ public @PointFormatEnum int getKemPointFormat() {
+ return mKemPointFormat;
+ }
+
+ /**
+ * Returns KEM KDF algorithm (e.g., {@code HKDFwithSHA256} or {@code KDF1withSHA1}) or
+ * {@code null} if not specified.
+ */
+ public String getKemKdfAlgorithm() {
+ return mKemKdfAlgorithm;
+ }
+
+ /**
+ * Returns DEM {@link Cipher} transformation (e.g., {@code AES/GCM/NoPadding} or
+ * {@code AES/CBC/PKCS7Padding}) or {@code null} if not specified.
+ *
+ * @see Cipher#getInstance(String)
+ * @see #getDemCipherKeySize()
+ */
+ public String getDemCipherTransformation() {
+ return mDemCipherTransformation;
+ }
+
+ /**
+ * Returns DEM {@link Cipher} key size in bits.
+ *
+ * @see #getDemCipherTransformation()
+ */
+ public int getDemCipherKeySize() {
+ return mDemCipherKeySize;
+ }
+
+ /**
+ * Returns DEM {@link Mac} algorithm (e.g., {@code HmacSHA256} or {@code HmacSHA1}) or
+ * {@code null} if not specified.
+ *
+ * @see Mac#getInstance(String)
+ * @see #getDemMacKeySize()
+ */
+ public String getDemMacAlgorithm() {
+ return mDemMacAlgorithm;
+ }
+
+ /**
+ * Returns DEM {@link Mac} key size in bits.
+ *
+ * @see #getDemCipherTransformation()
+ */
+ public int getDemMacKeySize() {
+ return mDemMacKeySize;
+ }
+
+ /**
+ * Builder of {@link EcIesParameterSpec}.
+ */
+ public static class Builder {
+ private @PointFormatEnum int mKemPointFormat = PointFormat.UNSPECIFIED;
+ private String mKemKdfAlgorithm;
+ private String mDemCipherTransformation;
+ private int mDemCipherKeySize = 128;
+ private String mDemMacAlgorithm;
+ private int mDemMacKeySize = -1;
+
+ /**
+ * Sets KEM EC point wire format.
+ */
+ public Builder setKemPointFormat(@PointFormatEnum int pointFormat) {
+ mKemPointFormat = pointFormat;
+ return this;
+ }
+
+ /**
+ * Sets KEM KDF algorithm. For example, {@code HKDFwithSHA256}, {@code KDF2withSHA256}, or
+ * {@code KDF1withSHA1}.
+ */
+ public Builder setKemKdfAlgorithm(String algorithm) {
+ mKemKdfAlgorithm = algorithm;
+ return this;
+ }
+
+ /**
+ * Sets DEM {@link Cipher} transformation. For example, {@code AES/GCM/NoPadding},
+ * {@code AES/CBC/PKCS7Padding} or {@code AES/CTR/NoPadding}.
+ *
+ * @see Cipher#getInstance(String)
+ */
+ public Builder setDemCipherTransformation(String transformation) {
+ mDemCipherTransformation = transformation;
+ return this;
+ }
+
+ /**
+ * Returns DEM {@link Cipher} key size in bits.
+ *
+ * <p>The default value is {@code 128} bits.
+ *
+ * @see #setDemCipherTransformation(String)
+ */
+ public Builder setDemCipherKeySize(int sizeBits) {
+ mDemCipherKeySize = sizeBits;
+ return this;
+ }
+
+ /**
+ * Sets DEM {@link Mac} algorithm. For example, {@code HmacSHA256} or {@code HmacSHA1}.
+ *
+ * @see Mac#getInstance(String)
+ */
+ public Builder setDemMacAlgorithm(String algorithm) {
+ mDemMacAlgorithm = algorithm;
+ return this;
+ }
+
+ /**
+ * Sets DEM {@link Mac} key size in bits.
+ *
+ * <p>By default, {@code Mac} key size is the same as the {@code Cipher} key size.
+ *
+ * @see #setDemCipherKeySize(int)
+ */
+ public Builder setDemMacKeySize(int sizeBits) {
+ mDemMacKeySize = sizeBits;
+ return this;
+ }
+
+ /**
+ * Returns a new {@link EcIesParameterSpec} based on the current state of this builder.
+ */
+ public EcIesParameterSpec build() {
+ int demMacKeySize = (mDemMacKeySize != -1) ? mDemMacKeySize : mDemCipherKeySize;
+ return new EcIesParameterSpec(
+ mKemPointFormat,
+ mKemKdfAlgorithm,
+ mDemCipherTransformation,
+ mDemCipherKeySize,
+ mDemMacAlgorithm,
+ demMacKeySize
+ );
+ }
+ }
+}
diff --git a/keystore/java/android/security/KeyGeneratorSpec.java b/keystore/java/android/security/KeyGeneratorSpec.java
index 1311368..a22c31c 100644
--- a/keystore/java/android/security/KeyGeneratorSpec.java
+++ b/keystore/java/android/security/KeyGeneratorSpec.java
@@ -19,13 +19,10 @@ package android.security;
import android.content.Context;
import android.text.TextUtils;
-import java.security.cert.Certificate;
import java.security.spec.AlgorithmParameterSpec;
-import java.util.Collections;
import java.util.Date;
-import java.util.HashSet;
-import java.util.Set;
+import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
@@ -33,13 +30,13 @@ import javax.crypto.SecretKey;
* {@link AlgorithmParameterSpec} for initializing a {@code KeyGenerator} that works with
* <a href="{@docRoot}training/articles/keystore.html">Android KeyStore facility</a>.
*
- * <p>The Android KeyStore facility is accessed through a {@link KeyGenerator} API
- * using the {@code AndroidKeyStore} provider. The {@code context} passed in may be used to pop up
- * some UI to ask the user to unlock or initialize the Android KeyStore facility.
+ * <p>The Android KeyStore facility is accessed through a {@link KeyGenerator} API using the
+ * {@code AndroidKeyStore} provider. The {@code context} passed in may be used to pop up some UI to
+ * ask the user to unlock or initialize the Android KeyStore facility.
*
* <p>After generation, the {@code keyStoreAlias} is used with the
* {@link java.security.KeyStore#getEntry(String, java.security.KeyStore.ProtectionParameter)}
- * interface to retrieve the {@link SecretKey} and its associated {@link Certificate} chain.
+ * interface to retrieve the {@link SecretKey}.
*
* @hide
*/
@@ -52,13 +49,12 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec {
private final Date mKeyValidityStart;
private final Date mKeyValidityForOriginationEnd;
private final Date mKeyValidityForConsumptionEnd;
- private final @KeyStoreKeyConstraints.PurposeEnum Integer mPurposes;
- private final @KeyStoreKeyConstraints.PaddingEnum Integer mPadding;
- private final @KeyStoreKeyConstraints.BlockModeEnum Integer mBlockMode;
- private final Integer mMinSecondsBetweenOperations;
- private final Integer mMaxUsesPerBoot;
- private final Set<Integer> mUserAuthenticators;
- private final Integer mUserAuthenticationValidityDurationSeconds;
+ private final @KeyStoreKeyProperties.PurposeEnum int mPurposes;
+ private final String[] mEncryptionPaddings;
+ private final String[] mBlockModes;
+ private final boolean mRandomizedEncryptionRequired;
+ private final @KeyStoreKeyProperties.UserAuthenticatorEnum int mUserAuthenticators;
+ private final int mUserAuthenticationValidityDurationSeconds;
private KeyGeneratorSpec(
Context context,
@@ -68,19 +64,18 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec {
Date keyValidityStart,
Date keyValidityForOriginationEnd,
Date keyValidityForConsumptionEnd,
- @KeyStoreKeyConstraints.PurposeEnum Integer purposes,
- @KeyStoreKeyConstraints.PaddingEnum Integer padding,
- @KeyStoreKeyConstraints.BlockModeEnum Integer blockMode,
- Integer minSecondsBetweenOperations,
- Integer maxUsesPerBoot,
- Set<Integer> userAuthenticators,
- Integer userAuthenticationValidityDurationSeconds) {
+ @KeyStoreKeyProperties.PurposeEnum int purposes,
+ String[] encryptionPaddings,
+ String[] blockModes,
+ boolean randomizedEncryptionRequired,
+ @KeyStoreKeyProperties.UserAuthenticatorEnum int userAuthenticators,
+ int userAuthenticationValidityDurationSeconds) {
if (context == null) {
throw new IllegalArgumentException("context == null");
} else if (TextUtils.isEmpty(keyStoreAlias)) {
throw new IllegalArgumentException("keyStoreAlias must not be empty");
- } else if ((userAuthenticationValidityDurationSeconds != null)
- && (userAuthenticationValidityDurationSeconds < 0)) {
+ } else if ((userAuthenticationValidityDurationSeconds < 0)
+ && (userAuthenticationValidityDurationSeconds != -1)) {
throw new IllegalArgumentException(
"userAuthenticationValidityDurationSeconds must not be negative");
}
@@ -93,13 +88,11 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec {
mKeyValidityForOriginationEnd = keyValidityForOriginationEnd;
mKeyValidityForConsumptionEnd = keyValidityForConsumptionEnd;
mPurposes = purposes;
- mPadding = padding;
- mBlockMode = blockMode;
- mMinSecondsBetweenOperations = minSecondsBetweenOperations;
- mMaxUsesPerBoot = maxUsesPerBoot;
- mUserAuthenticators = (userAuthenticators != null)
- ? new HashSet<Integer>(userAuthenticators)
- : Collections.<Integer>emptySet();
+ mEncryptionPaddings =
+ ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(encryptionPaddings));
+ mBlockModes = ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(blockModes));
+ mRandomizedEncryptionRequired = randomizedEncryptionRequired;
+ mUserAuthenticators = userAuthenticators;
mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds;
}
@@ -145,8 +138,6 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec {
* Gets the time instant after which the key is no longer valid for decryption and verification.
*
* @return instant or {@code null} if not restricted.
- *
- * @hide
*/
public Date getKeyValidityForConsumptionEnd() {
return mKeyValidityForConsumptionEnd;
@@ -163,78 +154,56 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec {
/**
* Gets the set of purposes for which the key can be used.
- *
- * @return set of purposes or {@code null} if the key can be used for any purpose.
*/
- public @KeyStoreKeyConstraints.PurposeEnum Integer getPurposes() {
+ public @KeyStoreKeyProperties.PurposeEnum int getPurposes() {
return mPurposes;
}
/**
- * Gets the padding scheme to which the key is restricted.
- *
- * @return padding scheme or {@code null} if the padding scheme is not restricted.
+ * Gets the set of padding schemes with which the key can be used when encrypting/decrypting.
*/
- public @KeyStoreKeyConstraints.PaddingEnum Integer getPadding() {
- return mPadding;
+ public String[] getEncryptionPaddings() {
+ return ArrayUtils.cloneIfNotEmpty(mEncryptionPaddings);
}
/**
- * Gets the block mode to which the key is restricted when used for encryption or decryption.
- *
- * @return block more or {@code null} if block mode is not restricted.
- *
- * @hide
+ * Gets the set of block modes with which the key can be used.
*/
- public @KeyStoreKeyConstraints.BlockModeEnum Integer getBlockMode() {
- return mBlockMode;
+ public String[] getBlockModes() {
+ return ArrayUtils.cloneIfNotEmpty(mBlockModes);
}
/**
- * Gets the minimum number of seconds that must expire since the most recent use of the key
- * before it can be used again.
- *
- * @return number of seconds or {@code null} if there is no restriction on how frequently a key
- * can be used.
- *
- * @hide
+ * Returns {@code true} if encryption using this key must be sufficiently randomized to produce
+ * different ciphertexts for the same plaintext every time. The formal cryptographic property
+ * being required is <em>indistinguishability under chosen-plaintext attack ({@code
+ * IND-CPA})</em>. This property is important because it mitigates several classes of
+ * weaknesses due to which ciphertext may leak information about plaintext. For example, if a
+ * given plaintext always produces the same ciphertext, an attacker may see the repeated
+ * ciphertexts and be able to deduce something about the plaintext.
*/
- public Integer getMinSecondsBetweenOperations() {
- return mMinSecondsBetweenOperations;
+ public boolean isRandomizedEncryptionRequired() {
+ return mRandomizedEncryptionRequired;
}
/**
- * Gets the number of times the key can be used without rebooting the device.
+ * Gets the set of user authenticators which protect access to this key. The key can only be
+ * used iff the user has authenticated to at least one of these user authenticators.
*
- * @return maximum number of times or {@code null} if there is no restriction.
- * @hide
+ * @return user authenticators or {@code 0} if the key can be used without user authentication.
*/
- public Integer getMaxUsesPerBoot() {
- return mMaxUsesPerBoot;
- }
-
- /**
- * Gets the user authenticators which protect access to this key. The key can only be used iff
- * the user has authenticated to at least one of these user authenticators.
- *
- * @return user authenticators or empty set if the key can be used without user authentication.
- *
- * @hide
- */
- public Set<Integer> getUserAuthenticators() {
- return new HashSet<Integer>(mUserAuthenticators);
+ public @KeyStoreKeyProperties.UserAuthenticatorEnum int getUserAuthenticators() {
+ return mUserAuthenticators;
}
/**
* Gets the duration of time (seconds) for which this key can be used after the user
* successfully authenticates to one of the associated user authenticators.
*
- * @return duration in seconds or {@code null} if not restricted. {@code 0} means authentication
+ * @return duration in seconds or {@code -1} if not restricted. {@code 0} means authentication
* is required for every use of the key.
- *
- * @hide
*/
- public Integer getUserAuthenticationValidityDurationSeconds() {
+ public int getUserAuthenticationValidityDurationSeconds() {
return mUserAuthenticationValidityDurationSeconds;
}
@@ -253,13 +222,12 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec {
private Date mKeyValidityStart;
private Date mKeyValidityForOriginationEnd;
private Date mKeyValidityForConsumptionEnd;
- private @KeyStoreKeyConstraints.PurposeEnum Integer mPurposes;
- private @KeyStoreKeyConstraints.PaddingEnum Integer mPadding;
- private @KeyStoreKeyConstraints.BlockModeEnum Integer mBlockMode;
- private Integer mMinSecondsBetweenOperations;
- private Integer mMaxUsesPerBoot;
- private Set<Integer> mUserAuthenticators;
- private Integer mUserAuthenticationValidityDurationSeconds;
+ private @KeyStoreKeyProperties.PurposeEnum int mPurposes;
+ private String[] mEncryptionPaddings;
+ private String[] mBlockModes;
+ private boolean mRandomizedEncryptionRequired = true;
+ private @KeyStoreKeyProperties.UserAuthenticatorEnum int mUserAuthenticators;
+ private int mUserAuthenticationValidityDurationSeconds = -1;
/**
* Creates a new instance of the {@code Builder} with the given {@code context}. The
@@ -315,11 +283,9 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec {
/**
* Sets the time instant before which the key is not yet valid.
*
- * <b>By default, the key is valid at any instant.
+ * <p>By default, the key is valid at any instant.
*
* @see #setKeyValidityEnd(Date)
- *
- * @hide
*/
public Builder setKeyValidityStart(Date startDate) {
mKeyValidityStart = startDate;
@@ -329,13 +295,11 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec {
/**
* Sets the time instant after which the key is no longer valid.
*
- * <b>By default, the key is valid at any instant.
+ * <p>By default, the key is valid at any instant.
*
* @see #setKeyValidityStart(Date)
* @see #setKeyValidityForConsumptionEnd(Date)
* @see #setKeyValidityForOriginationEnd(Date)
- *
- * @hide
*/
public Builder setKeyValidityEnd(Date endDate) {
setKeyValidityForOriginationEnd(endDate);
@@ -346,11 +310,9 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec {
/**
* Sets the time instant after which the key is no longer valid for encryption and signing.
*
- * <b>By default, the key is valid at any instant.
+ * <p>By default, the key is valid at any instant.
*
* @see #setKeyValidityForConsumptionEnd(Date)
- *
- * @hide
*/
public Builder setKeyValidityForOriginationEnd(Date endDate) {
mKeyValidityForOriginationEnd = endDate;
@@ -361,11 +323,9 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec {
* Sets the time instant after which the key is no longer valid for decryption and
* verification.
*
- * <b>By default, the key is valid at any instant.
+ * <p>By default, the key is valid at any instant.
*
* @see #setKeyValidityForOriginationEnd(Date)
- *
- * @hide
*/
public Builder setKeyValidityForConsumptionEnd(Date endDate) {
mKeyValidityForConsumptionEnd = endDate;
@@ -373,65 +333,72 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec {
}
/**
- * Restricts the purposes for which the key can be used to the provided set of purposes.
+ * Sets the set of purposes for which the key can be used.
*
- * <p>By default, the key can be used for encryption, decryption, signing, and verification.
- *
- * @hide
+ * <p>This must be specified for all keys. There is no default.
*/
- public Builder setPurposes(@KeyStoreKeyConstraints.PurposeEnum int purposes) {
+ public Builder setPurposes(@KeyStoreKeyProperties.PurposeEnum int purposes) {
mPurposes = purposes;
return this;
}
/**
- * Restricts the key to being used only with the provided padding scheme. Attempts to use
- * the key with any other padding will be rejected.
- *
- * <p>This restriction must be specified for keys which are used for encryption/decryption.
+ * Sets the set of padding schemes with which the key can be used when
+ * encrypting/decrypting. Attempts to use the key with any other padding scheme will be
+ * rejected.
*
- * @hide
+ * <p>This must be specified for keys which are used for encryption/decryption.
*/
- public Builder setPadding(@KeyStoreKeyConstraints.PaddingEnum int padding) {
- mPadding = padding;
+ public Builder setEncryptionPaddings(String... paddings) {
+ mEncryptionPaddings = ArrayUtils.cloneIfNotEmpty(paddings);
return this;
}
/**
- * Restricts the key to being used only with the provided block mode when encrypting or
- * decrypting. Attempts to use the key with any other block modes will be rejected.
- *
- * <p>This restriction must be specified for keys which are used for encryption/decryption.
+ * Sets the set of block modes with which the key can be used when encrypting/decrypting.
+ * Attempts to use the key with any other block modes will be rejected.
*
- * @hide
+ * <p>This must be specified for encryption/decryption keys.
*/
- public Builder setBlockMode(@KeyStoreKeyConstraints.BlockModeEnum int blockMode) {
- mBlockMode = blockMode;
+ public Builder setBlockModes(String... blockModes) {
+ mBlockModes = ArrayUtils.cloneIfNotEmpty(blockModes);
return this;
}
/**
- * Sets the minimum number of seconds that must expire since the most recent use of the key
- * before it can be used again.
- *
- * <p>By default, there is no restriction on how frequently a key can be used.
- *
- * @hide
+ * Sets whether encryption using this key must be sufficiently randomized to produce
+ * different ciphertexts for the same plaintext every time. The formal cryptographic
+ * property being required is <em>indistinguishability under chosen-plaintext attack
+ * ({@code IND-CPA})</em>. This property is important because it mitigates several classes
+ * of weaknesses due to which ciphertext may leak information about plaintext. For example,
+ * if a given plaintext always produces the same ciphertext, an attacker may see the
+ * repeated ciphertexts and be able to deduce something about the plaintext.
+ *
+ * <p>By default, {@code IND-CPA} is required.
+ *
+ * <p>When {@code IND-CPA} is required:
+ * <ul>
+ * <li>block modes which do not offer {@code IND-CPA}, such as {@code ECB}, are prohibited;
+ * </li>
+ * <li>in block modes which use an IV, such as {@code CBC}, {@code CTR}, and {@code GCM},
+ * caller-provided IVs are rejected when encrypting, to ensure that only random IVs are
+ * used.</li>
+ *
+ * <p>Before disabling this requirement, consider the following approaches instead:
+ * <ul>
+ * <li>If you are generating a random IV for encryption and then initializing a {@code}
+ * Cipher using the IV, the solution is to let the {@code Cipher} generate a random IV
+ * instead. This will occur if the {@code Cipher} is initialized for encryption without an
+ * IV. The IV can then be queried via {@link Cipher#getIV()}.</li>
+ * <li>If you are generating a non-random IV (e.g., an IV derived from something not fully
+ * random, such as the name of the file being encrypted, or transaction ID, or password,
+ * or a device identifier), consider changing your design to use a random IV which will then
+ * be provided in addition to the ciphertext to the entities which need to decrypt the
+ * ciphertext.</li>
+ * </ul>
*/
- public Builder setMinSecondsBetweenOperations(int seconds) {
- mMinSecondsBetweenOperations = seconds;
- return this;
- }
-
- /**
- * Sets the maximum number of times a key can be used without rebooting the device.
- *
- * <p>By default, the key can be used for an unlimited number of times.
- *
- * @hide
- */
- public Builder setMaxUsesPerBoot(int count) {
- mMaxUsesPerBoot = count;
+ public Builder setRandomizedEncryptionRequired(boolean required) {
+ mRandomizedEncryptionRequired = required;
return this;
}
@@ -445,12 +412,10 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec {
* without user authentication.
*
* @see #setUserAuthenticationValidityDurationSeconds(int)
- *
- * @hide
*/
- public Builder setUserAuthenticators(Set<Integer> userAuthenticators) {
- mUserAuthenticators =
- (userAuthenticators != null) ? new HashSet<Integer>(userAuthenticators) : null;
+ public Builder setUserAuthenticators(
+ @KeyStoreKeyProperties.UserAuthenticatorEnum int userAuthenticators) {
+ mUserAuthenticators = userAuthenticators;
return this;
}
@@ -463,9 +428,7 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec {
* @param seconds duration in seconds or {@code 0} if the user needs to authenticate for
* every use of the key.
*
- * @see #setUserAuthenticators(Set)
- *
- * @hide
+ * @see #setUserAuthenticators(int)
*/
public Builder setUserAuthenticationValidityDurationSeconds(int seconds) {
mUserAuthenticationValidityDurationSeconds = seconds;
@@ -478,10 +441,19 @@ public class KeyGeneratorSpec implements AlgorithmParameterSpec {
* @throws IllegalArgumentException if a required field is missing or violates a constraint.
*/
public KeyGeneratorSpec build() {
- return new KeyGeneratorSpec(mContext, mKeystoreAlias, mFlags, mKeySize,
- mKeyValidityStart, mKeyValidityForOriginationEnd, mKeyValidityForConsumptionEnd,
- mPurposes, mPadding, mBlockMode, mMinSecondsBetweenOperations, mMaxUsesPerBoot,
- mUserAuthenticators, mUserAuthenticationValidityDurationSeconds);
+ return new KeyGeneratorSpec(mContext,
+ mKeystoreAlias,
+ mFlags,
+ mKeySize,
+ mKeyValidityStart,
+ mKeyValidityForOriginationEnd,
+ mKeyValidityForConsumptionEnd,
+ mPurposes,
+ mEncryptionPaddings,
+ mBlockModes,
+ mRandomizedEncryptionRequired,
+ mUserAuthenticators,
+ mUserAuthenticationValidityDurationSeconds);
}
}
}
diff --git a/keystore/java/android/security/KeyPairGeneratorSpec.java b/keystore/java/android/security/KeyPairGeneratorSpec.java
index 0001604..fce02df 100644
--- a/keystore/java/android/security/KeyPairGeneratorSpec.java
+++ b/keystore/java/android/security/KeyPairGeneratorSpec.java
@@ -24,10 +24,7 @@ import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.cert.Certificate;
import java.security.spec.AlgorithmParameterSpec;
-import java.util.Collections;
import java.util.Date;
-import java.util.HashSet;
-import java.util.Set;
import javax.security.auth.x500.X500Principal;
@@ -55,6 +52,11 @@ import javax.security.auth.x500.X500Principal;
*/
public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
+ private static final X500Principal DEFAULT_CERT_SUBJECT = new X500Principal("CN=fake");
+ private static final BigInteger DEFAULT_CERT_SERIAL_NUMBER = new BigInteger("1");
+ private static final Date DEFAULT_CERT_NOT_BEFORE = new Date(0L); // Jan 1 1970
+ private static final Date DEFAULT_CERT_NOT_AFTER = new Date(2461449600000L); // Jan 1 2048
+
private final Context mContext;
private final String mKeystoreAlias;
@@ -81,21 +83,21 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
private final Date mKeyValidityForConsumptionEnd;
- private final @KeyStoreKeyConstraints.PurposeEnum Integer mPurposes;
+ private final @KeyStoreKeyProperties.PurposeEnum int mPurposes;
- private final @KeyStoreKeyConstraints.DigestEnum Integer mDigest;
+ private final String[] mDigests;
- private final @KeyStoreKeyConstraints.PaddingEnum Integer mPadding;
+ private final String[] mEncryptionPaddings;
- private final @KeyStoreKeyConstraints.BlockModeEnum Integer mBlockMode;
+ private final String[] mSignaturePaddings;
- private final Integer mMinSecondsBetweenOperations;
+ private final String[] mBlockModes;
- private final Integer mMaxUsesPerBoot;
+ private final boolean mRandomizedEncryptionRequired;
- private final Set<Integer> mUserAuthenticators;
+ private final @KeyStoreKeyProperties.UserAuthenticatorEnum int mUserAuthenticators;
- private final Integer mUserAuthenticationValidityDurationSeconds;
+ private final int mUserAuthenticationValidityDurationSeconds;
/**
* Parameter specification for the "{@code AndroidKeyPairGenerator}"
@@ -135,34 +137,41 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
Date keyValidityStart,
Date keyValidityForOriginationEnd,
Date keyValidityForConsumptionEnd,
- @KeyStoreKeyConstraints.PurposeEnum Integer purposes,
- @KeyStoreKeyConstraints.DigestEnum Integer digest,
- @KeyStoreKeyConstraints.PaddingEnum Integer padding,
- @KeyStoreKeyConstraints.BlockModeEnum Integer blockMode,
- Integer minSecondsBetweenOperations,
- Integer maxUsesPerBoot,
- Set<Integer> userAuthenticators,
- Integer userAuthenticationValidityDurationSeconds) {
+ @KeyStoreKeyProperties.PurposeEnum int purposes,
+ String[] digests,
+ String[] encryptionPaddings,
+ String[] signaturePaddings,
+ String[] blockModes,
+ boolean randomizedEncryptionRequired,
+ @KeyStoreKeyProperties.UserAuthenticatorEnum int userAuthenticators,
+ int userAuthenticationValidityDurationSeconds) {
if (context == null) {
throw new IllegalArgumentException("context == null");
} else if (TextUtils.isEmpty(keyStoreAlias)) {
throw new IllegalArgumentException("keyStoreAlias must not be empty");
- } else if (subjectDN == null) {
- throw new IllegalArgumentException("subjectDN == null");
- } else if (serialNumber == null) {
- throw new IllegalArgumentException("serialNumber == null");
- } else if (startDate == null) {
- throw new IllegalArgumentException("startDate == null");
- } else if (endDate == null) {
- throw new IllegalArgumentException("endDate == null");
- } else if (endDate.before(startDate)) {
- throw new IllegalArgumentException("endDate < startDate");
- } else if ((userAuthenticationValidityDurationSeconds != null)
- && (userAuthenticationValidityDurationSeconds < 0)) {
+ } else if ((userAuthenticationValidityDurationSeconds < 0)
+ && (userAuthenticationValidityDurationSeconds != -1)) {
throw new IllegalArgumentException(
"userAuthenticationValidityDurationSeconds must not be negative");
}
+ if (subjectDN == null) {
+ subjectDN = DEFAULT_CERT_SUBJECT;
+ }
+ if (startDate == null) {
+ startDate = DEFAULT_CERT_NOT_BEFORE;
+ }
+ if (endDate == null) {
+ endDate = DEFAULT_CERT_NOT_AFTER;
+ }
+ if (serialNumber == null) {
+ serialNumber = DEFAULT_CERT_SERIAL_NUMBER;
+ }
+
+ if (endDate.before(startDate)) {
+ throw new IllegalArgumentException("endDate < startDate");
+ }
+
mContext = context;
mKeystoreAlias = keyStoreAlias;
mKeyType = keyType;
@@ -177,14 +186,13 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
mKeyValidityForOriginationEnd = keyValidityForOriginationEnd;
mKeyValidityForConsumptionEnd = keyValidityForConsumptionEnd;
mPurposes = purposes;
- mDigest = digest;
- mPadding = padding;
- mBlockMode = blockMode;
- mMinSecondsBetweenOperations = minSecondsBetweenOperations;
- mMaxUsesPerBoot = maxUsesPerBoot;
- mUserAuthenticators = (userAuthenticators != null)
- ? new HashSet<Integer>(userAuthenticators)
- : Collections.<Integer>emptySet();
+ mDigests = ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(digests));
+ mEncryptionPaddings =
+ ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(encryptionPaddings));
+ mSignaturePaddings = ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(signaturePaddings));
+ mBlockModes = ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(blockModes));
+ mRandomizedEncryptionRequired = randomizedEncryptionRequired;
+ mUserAuthenticators = userAuthenticators;
mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds;
}
@@ -195,9 +203,28 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
public KeyPairGeneratorSpec(Context context, String keyStoreAlias, String keyType, int keySize,
AlgorithmParameterSpec spec, X500Principal subjectDN, BigInteger serialNumber,
Date startDate, Date endDate, int flags) {
- this(context, keyStoreAlias, keyType, keySize, spec, subjectDN, serialNumber, startDate,
- endDate, flags, startDate, endDate, endDate, null, null, null, null, null, null,
- null, null);
+ this(context,
+ keyStoreAlias,
+ keyType,
+ keySize,
+ spec,
+ subjectDN,
+ serialNumber,
+ startDate,
+ endDate,
+ flags,
+ startDate,
+ endDate,
+ endDate,
+ 0, // purposes
+ null, // digests
+ null, // encryption paddings
+ null, // signature paddings
+ null, // block modes
+ false, // randomized encryption required
+ 0, // user authenticators
+ -1 // user authentication validity duration (seconds)
+ );
}
/**
@@ -323,90 +350,76 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
/**
* Gets the set of purposes for which the key can be used.
*
- * @return set of purposes or {@code null} if the key can be used for any purpose.
- *
* @hide
*/
- public @KeyStoreKeyConstraints.PurposeEnum Integer getPurposes() {
+ public @KeyStoreKeyProperties.PurposeEnum int getPurposes() {
return mPurposes;
}
/**
- * Gets the digest to which the key is restricted.
- *
- * @return digest or {@code null} if the digest is not restricted.
+ * Gets the set of digest algorithms with which the key can be used.
*
* @hide
*/
- public @KeyStoreKeyConstraints.DigestEnum Integer getDigest() {
- return mDigest;
+ public String[] getDigests() {
+ return ArrayUtils.cloneIfNotEmpty(mDigests);
}
/**
- * Gets the padding scheme to which the key is restricted.
- *
- * @return padding scheme or {@code null} if the padding scheme is not restricted.
+ * Gets the set of padding schemes with which the key can be used when encrypting/decrypting.
*
* @hide
*/
- public @KeyStoreKeyConstraints.PaddingEnum Integer getPadding() {
- return mPadding;
+ public String[] getEncryptionPaddings() {
+ return ArrayUtils.cloneIfNotEmpty(mEncryptionPaddings);
}
/**
- * Gets the block mode to which the key is restricted when used for encryption or decryption.
- *
- * @return block more or {@code null} if block mode is not restricted.
+ * Gets the set of padding schemes with which the key can be used when signing/verifying.
*
* @hide
*/
- public @KeyStoreKeyConstraints.BlockModeEnum Integer getBlockMode() {
- return mBlockMode;
+ public String[] getSignaturePaddings() {
+ return ArrayUtils.cloneIfNotEmpty(mSignaturePaddings);
}
/**
- * Gets the minimum number of seconds that must expire since the most recent use of the private
- * key before it can be used again.
- *
- * <p>This restriction applies only to private key operations. Public key operations are not
- * restricted.
- *
- * @return number of seconds or {@code null} if there is no restriction on how frequently a key
- * can be used.
+ * Gets the set of block modes with which the key can be used.
*
* @hide
*/
- public Integer getMinSecondsBetweenOperations() {
- return mMinSecondsBetweenOperations;
+ public String[] getBlockModes() {
+ return ArrayUtils.cloneIfNotEmpty(mBlockModes);
}
/**
- * Gets the number of times the private key can be used without rebooting the device.
- *
- * <p>This restriction applies only to private key operations. Public key operations are not
- * restricted.
- *
- * @return maximum number of times or {@code null} if there is no restriction.
+ * Returns {@code true} if encryption using this key must be sufficiently randomized to produce
+ * different ciphertexts for the same plaintext every time. The formal cryptographic property
+ * being required is <em>indistinguishability under chosen-plaintext attack ({@code
+ * IND-CPA})</em>. This property is important because it mitigates several classes of
+ * weaknesses due to which ciphertext may leak information about plaintext. For example, if a
+ * given plaintext always produces the same ciphertext, an attacker may see the repeated
+ * ciphertexts and be able to deduce something about the plaintext.
*
* @hide
*/
- public Integer getMaxUsesPerBoot() {
- return mMaxUsesPerBoot;
+ public boolean isRandomizedEncryptionRequired() {
+ return mRandomizedEncryptionRequired;
}
/**
- * Gets the user authenticators which protect access to the private key. The key can only be
- * used iff the user has authenticated to at least one of these user authenticators.
+ * Gets the set of user authenticators which protect access to the private key. The key can only
+ * be used iff the user has authenticated to at least one of these user authenticators.
*
* <p>This restriction applies only to private key operations. Public key operations are not
* restricted.
*
- * @return user authenticators or empty set if the key can be used without user authentication.
+ * @return user authenticators or {@code 0} if the key can be used without user authentication.
*
* @hide
*/
- public Set<Integer> getUserAuthenticators() {
- return new HashSet<Integer>(mUserAuthenticators);
+ public @KeyStoreKeyProperties.UserAuthenticatorEnum int getUserAuthenticators() {
+ return mUserAuthenticators;
}
/**
@@ -416,12 +429,12 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
* <p>This restriction applies only to private key operations. Public key operations are not
* restricted.
*
- * @return duration in seconds or {@code null} if not restricted. {@code 0} means authentication
+ * @return duration in seconds or {@code -1} if not restricted. {@code 0} means authentication
* is required for every use of the key.
*
* @hide
*/
- public Integer getUserAuthenticationValidityDurationSeconds() {
+ public int getUserAuthenticationValidityDurationSeconds() {
return mUserAuthenticationValidityDurationSeconds;
}
@@ -473,21 +486,21 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
private Date mKeyValidityForConsumptionEnd;
- private @KeyStoreKeyConstraints.PurposeEnum Integer mPurposes;
+ private @KeyStoreKeyProperties.PurposeEnum int mPurposes;
- private @KeyStoreKeyConstraints.DigestEnum Integer mDigest;
+ private String[] mDigests;
- private @KeyStoreKeyConstraints.PaddingEnum Integer mPadding;
+ private String[] mEncryptionPaddings;
- private @KeyStoreKeyConstraints.BlockModeEnum Integer mBlockMode;
+ private String[] mSignaturePaddings;
- private Integer mMinSecondsBetweenOperations;
+ private String[] mBlockModes;
- private Integer mMaxUsesPerBoot;
+ private boolean mRandomizedEncryptionRequired = true;
- private Set<Integer> mUserAuthenticators;
+ private @KeyStoreKeyProperties.UserAuthenticatorEnum int mUserAuthenticators;
- private Integer mUserAuthenticationValidityDurationSeconds;
+ private int mUserAuthenticationValidityDurationSeconds = -1;
/**
* Creates a new instance of the {@code Builder} with the given
@@ -558,6 +571,10 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
/**
* Sets the subject used for the self-signed certificate of the
* generated key pair.
+ *
+ * <p>The subject must be specified on API Level
+ * {@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1 LOLLIPOP_MR1} and older platforms. On
+ * newer platforms the subject defaults to {@code CN=fake} if not specified.
*/
public Builder setSubject(X500Principal subject) {
if (subject == null) {
@@ -570,6 +587,10 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
/**
* Sets the serial number used for the self-signed certificate of the
* generated key pair.
+ *
+ * <p>The serial number must be specified on API Level
+ * {@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1 LOLLIPOP_MR1} and older platforms. On
+ * newer platforms the serial number defaults to {@code 1} if not specified.
*/
public Builder setSerialNumber(BigInteger serialNumber) {
if (serialNumber == null) {
@@ -582,6 +603,10 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
/**
* Sets the start of the validity period for the self-signed certificate
* of the generated key pair.
+ *
+ * <p>The date must be specified on API Level
+ * {@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1 LOLLIPOP_MR1} and older platforms. On
+ * newer platforms the date defaults to {@code Jan 1 1970} if not specified.
*/
public Builder setStartDate(Date startDate) {
if (startDate == null) {
@@ -594,6 +619,10 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
/**
* Sets the end of the validity period for the self-signed certificate
* of the generated key pair.
+ *
+ * <p>The date must be specified on API Level
+ * {@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1 LOLLIPOP_MR1} and older platforms. On
+ * newer platforms the date defaults to {@code Jan 1 2048} if not specified.
*/
public Builder setEndDate(Date endDate) {
if (endDate == null) {
@@ -617,7 +646,7 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
/**
* Sets the time instant before which the key is not yet valid.
*
- * <b>By default, the key is valid at any instant.
+ * <p>By default, the key is valid at any instant.
*
* @see #setKeyValidityEnd(Date)
*
@@ -631,7 +660,7 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
/**
* Sets the time instant after which the key is no longer valid.
*
- * <b>By default, the key is valid at any instant.
+ * <p>By default, the key is valid at any instant.
*
* @see #setKeyValidityStart(Date)
* @see #setKeyValidityForConsumptionEnd(Date)
@@ -648,7 +677,7 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
/**
* Sets the time instant after which the key is no longer valid for encryption and signing.
*
- * <b>By default, the key is valid at any instant.
+ * <p>By default, the key is valid at any instant.
*
* @see #setKeyValidityForConsumptionEnd(Date)
*
@@ -663,7 +692,7 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
* Sets the time instant after which the key is no longer valid for decryption and
* verification.
*
- * <b>By default, the key is valid at any instant.
+ * <p>By default, the key is valid at any instant.
*
* @see #setKeyValidityForOriginationEnd(Date)
*
@@ -675,84 +704,95 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
}
/**
- * Restricts the purposes for which the key can be used to the provided set of purposes.
+ * Sets the set of purposes for which the key can be used.
*
- * <p>By default, the key can be used for encryption, decryption, signing, and verification.
+ * <p>This must be specified for all keys. There is no default.
*
* @hide
*/
- public Builder setPurposes(@KeyStoreKeyConstraints.PurposeEnum int purposes) {
+ public Builder setPurposes(@KeyStoreKeyProperties.PurposeEnum int purposes) {
mPurposes = purposes;
return this;
}
/**
- * Restricts the key to being used only with the provided digest. Attempts to use the key
- * with any other digests be rejected.
+ * Sets the set of digests with which the key can be used when signing/verifying. Attempts
+ * to use the key with any other digest will be rejected.
*
- * <p>This restriction must be specified for keys which are used for signing/verification.
+ * <p>This must be specified for keys which are used for signing/verification.
*
* @hide
*/
- public Builder setDigest(@KeyStoreKeyConstraints.DigestEnum int digest) {
- mDigest = digest;
+ public Builder setDigests(String... digests) {
+ mDigests = ArrayUtils.cloneIfNotEmpty(digests);
return this;
}
/**
- * Restricts the key to being used only with the provided padding scheme. Attempts to use
- * the key with any other padding will be rejected.
+ * Sets the set of padding schemes with which the key can be used when
+ * encrypting/decrypting. Attempts to use the key with any other padding scheme will be
+ * rejected.
*
- * <p>This restriction must be specified for keys which are used for encryption/decryption.
+ * <p>This must be specified for keys which are used for encryption/decryption.
*
* @hide
*/
- public Builder setPadding(@KeyStoreKeyConstraints.PaddingEnum int padding) {
- mPadding = padding;
+ public Builder setEncryptionPaddings(String... paddings) {
+ mEncryptionPaddings = ArrayUtils.cloneIfNotEmpty(paddings);
return this;
}
/**
- * Restricts the key to being used only with the provided block mode when encrypting or
- * decrypting. Attempts to use the key with any other block modes will be rejected.
+ * Sets the set of padding schemes with which the key can be used when
+ * signing/verifying. Attempts to use the key with any other padding scheme will be
+ * rejected.
*
- * <p>This restriction must be specified for keys which are used for encryption/decryption.
+ * <p>This must be specified for RSA keys which are used for signing/verification.
*
* @hide
*/
- public Builder setBlockMode(@KeyStoreKeyConstraints.BlockModeEnum int blockMode) {
- mBlockMode = blockMode;
+ public Builder setSignaturePaddings(String... paddings) {
+ mSignaturePaddings = ArrayUtils.cloneIfNotEmpty(paddings);
return this;
}
/**
- * Sets the minimum number of seconds that must expire since the most recent use of the key
- * before it can be used again.
+ * Sets the set of block modes with which the key can be used when encrypting/decrypting.
+ * Attempts to use the key with any other block modes will be rejected.
*
- * <p>By default, there is no restriction on how frequently a key can be used.
- *
- * <p>This restriction applies only to private key operations. Public key operations are not
- * restricted.
+ * <p>This must be specified for encryption/decryption keys.
*
* @hide
*/
- public Builder setMinSecondsBetweenOperations(int seconds) {
- mMinSecondsBetweenOperations = seconds;
+ public Builder setBlockModes(String... blockModes) {
+ mBlockModes = ArrayUtils.cloneIfNotEmpty(blockModes);
return this;
}
/**
- * Sets the maximum number of times a key can be used without rebooting the device.
+ * Sets whether encryption using this key must be sufficiently randomized to produce
+ * different ciphertexts for the same plaintext every time. The formal cryptographic
+ * property being required is <em>indistinguishability under chosen-plaintext attack
+ * ({@code IND-CPA})</em>. This property is important because it mitigates several classes
+ * of weaknesses due to which ciphertext may leak information about plaintext. For example,
+ * if a given plaintext always produces the same ciphertext, an attacker may see the
+ * repeated ciphertexts and be able to deduce something about the plaintext.
*
- * <p>By default, the key can be used for an unlimited number of times.
+ * <p>By default, {@code IND-CPA} is required.
*
- * <p>This restriction applies only to private key operations. Public key operations are not
- * restricted.
+ * <p>When {@code IND-CPA} is required, encryption/decryption transformations which do not
+ * offer {@code IND-CPA}, such as RSA without padding, are prohibited.
+ *
+ * <p>Before disabling this requirement, consider the following approaches instead:
+ * <ul>
+ * <li>If you are using RSA encryption without padding, consider switching to padding
+ * schemes which offer {@code IND-CPA}, such as PKCS#1 or OAEP.</li>
+ * </ul>
*
* @hide
*/
- public Builder setMaxUsesPerBoot(int count) {
- mMaxUsesPerBoot = count;
+ public Builder setRandomizedEncryptionRequired(boolean required) {
+ mRandomizedEncryptionRequired = required;
return this;
}
@@ -765,16 +805,16 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
* <p>This restriction applies only to private key operations. Public key operations are not
* restricted.
*
- * @param userAuthenticators user authenticators or empty list if this key can be accessed
+ * @param userAuthenticators user authenticators or {@code 0} if this key can be accessed
* without user authentication.
*
* @see #setUserAuthenticationValidityDurationSeconds(int)
*
* @hide
*/
- public Builder setUserAuthenticators(Set<Integer> userAuthenticators) {
- mUserAuthenticators =
- (userAuthenticators != null) ? new HashSet<Integer>(userAuthenticators) : null;
+ public Builder setUserAuthenticators(
+ @KeyStoreKeyProperties.UserAuthenticatorEnum int userAuthenticators) {
+ mUserAuthenticators = userAuthenticators;
return this;
}
@@ -790,7 +830,7 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
* @param seconds duration in seconds or {@code 0} if the user needs to authenticate for
* every use of the key.
*
- * @see #setUserAuthenticators(Set)
+ * @see #setUserAuthenticators(int)
*
* @hide
*/
@@ -820,11 +860,11 @@ public final class KeyPairGeneratorSpec implements AlgorithmParameterSpec {
mKeyValidityForOriginationEnd,
mKeyValidityForConsumptionEnd,
mPurposes,
- mDigest,
- mPadding,
- mBlockMode,
- mMinSecondsBetweenOperations,
- mMaxUsesPerBoot,
+ mDigests,
+ mEncryptionPaddings,
+ mSignaturePaddings,
+ mBlockModes,
+ mRandomizedEncryptionRequired,
mUserAuthenticators,
mUserAuthenticationValidityDurationSeconds);
}
diff --git a/keystore/java/android/security/KeyStoreCipherSpi.java b/keystore/java/android/security/KeyStoreCipherSpi.java
index ec358d6..7bc6378 100644
--- a/keystore/java/android/security/KeyStoreCipherSpi.java
+++ b/keystore/java/android/security/KeyStoreCipherSpi.java
@@ -48,70 +48,71 @@ import javax.crypto.spec.IvParameterSpec;
public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCryptoOperation {
public abstract static class AES extends KeyStoreCipherSpi {
- protected AES(@KeyStoreKeyConstraints.BlockModeEnum int blockMode,
- @KeyStoreKeyConstraints.PaddingEnum int padding, boolean ivUsed) {
- super(KeyStoreKeyConstraints.Algorithm.AES,
- blockMode,
- padding,
+ protected AES(int keymasterBlockMode, int keymasterPadding, boolean ivUsed) {
+ super(KeymasterDefs.KM_ALGORITHM_AES,
+ keymasterBlockMode,
+ keymasterPadding,
16,
ivUsed);
}
public abstract static class ECB extends AES {
- protected ECB(@KeyStoreKeyConstraints.PaddingEnum int padding) {
- super(KeyStoreKeyConstraints.BlockMode.ECB, padding, false);
+ protected ECB(int keymasterPadding) {
+ super(KeymasterDefs.KM_MODE_ECB, keymasterPadding, false);
}
public static class NoPadding extends ECB {
public NoPadding() {
- super(KeyStoreKeyConstraints.Padding.NONE);
+ super(KeymasterDefs.KM_PAD_NONE);
}
}
public static class PKCS7Padding extends ECB {
public PKCS7Padding() {
- super(KeyStoreKeyConstraints.Padding.PKCS7);
+ super(KeymasterDefs.KM_PAD_PKCS7);
}
}
}
public abstract static class CBC extends AES {
- protected CBC(@KeyStoreKeyConstraints.BlockModeEnum int padding) {
- super(KeyStoreKeyConstraints.BlockMode.CBC, padding, true);
+ protected CBC(int keymasterPadding) {
+ super(KeymasterDefs.KM_MODE_CBC, keymasterPadding, true);
}
public static class NoPadding extends CBC {
public NoPadding() {
- super(KeyStoreKeyConstraints.Padding.NONE);
+ super(KeymasterDefs.KM_PAD_NONE);
}
}
public static class PKCS7Padding extends CBC {
public PKCS7Padding() {
- super(KeyStoreKeyConstraints.Padding.PKCS7);
+ super(KeymasterDefs.KM_PAD_PKCS7);
}
}
}
public abstract static class CTR extends AES {
- protected CTR(@KeyStoreKeyConstraints.BlockModeEnum int padding) {
- super(KeyStoreKeyConstraints.BlockMode.CTR, padding, true);
+ protected CTR(int keymasterPadding) {
+ super(KeymasterDefs.KM_MODE_CTR, keymasterPadding, true);
}
public static class NoPadding extends CTR {
public NoPadding() {
- super(KeyStoreKeyConstraints.Padding.NONE);
+ super(KeymasterDefs.KM_PAD_NONE);
}
}
}
}
private final KeyStore mKeyStore;
- private final @KeyStoreKeyConstraints.AlgorithmEnum int mAlgorithm;
- private final @KeyStoreKeyConstraints.BlockModeEnum int mBlockMode;
- private final @KeyStoreKeyConstraints.PaddingEnum int mPadding;
+ private final int mKeymasterAlgorithm;
+ private final int mKeymasterBlockMode;
+ private final int mKeymasterPadding;
private final int mBlockSizeBytes;
- private final boolean mIvUsed;
+
+ /** Whether this transformation requires an IV. */
+ private final boolean mIvRequired;
// Fields below are populated by Cipher.init and KeyStore.begin and should be preserved after
// doFinal finishes.
@@ -119,10 +120,13 @@ public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCry
private KeyStoreSecretKey mKey;
private SecureRandom mRng;
private boolean mFirstOperationInitiated;
- byte[] mIv;
+ private byte[] mIv;
+ /** Whether the current {@code #mIv} has been used by the underlying crypto operation. */
+ private boolean mIvHasBeenUsed;
- // Fields below must be reset
+ // Fields below must be reset after doFinal
private byte[] mAdditionalEntropyForBegin;
+
/**
* Token referencing this operation inside keystore service. It is initialized by
* {@code engineInit} and is invalidated when {@code engineDoFinal} succeeds and one some
@@ -133,17 +137,17 @@ public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCry
private KeyStoreCryptoOperationChunkedStreamer mMainDataStreamer;
protected KeyStoreCipherSpi(
- @KeyStoreKeyConstraints.AlgorithmEnum int algorithm,
- @KeyStoreKeyConstraints.BlockModeEnum int blockMode,
- @KeyStoreKeyConstraints.PaddingEnum int padding,
+ int keymasterAlgorithm,
+ int keymasterBlockMode,
+ int keymasterPadding,
int blockSizeBytes,
boolean ivUsed) {
mKeyStore = KeyStore.getInstance();
- mAlgorithm = algorithm;
- mBlockMode = blockMode;
- mPadding = padding;
+ mKeymasterAlgorithm = keymasterAlgorithm;
+ mKeymasterBlockMode = keymasterBlockMode;
+ mKeymasterPadding = keymasterPadding;
mBlockSizeBytes = blockSizeBytes;
- mIvUsed = ivUsed;
+ mIvRequired = ivUsed;
}
@Override
@@ -170,7 +174,7 @@ public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCry
}
private void init(int opmode, Key key, SecureRandom random) throws InvalidKeyException {
- reset();
+ resetAll();
if (!(key instanceof KeyStoreSecretKey)) {
throw new InvalidKeyException(
"Unsupported key: " + ((key != null) ? key.getClass().getName() : "null"));
@@ -187,7 +191,25 @@ public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCry
mEncrypting = opmode == Cipher.ENCRYPT_MODE;
}
- private void reset() {
+ private void resetAll() {
+ IBinder operationToken = mOperationToken;
+ if (operationToken != null) {
+ mOperationToken = null;
+ mKeyStore.abort(operationToken);
+ }
+ mEncrypting = false;
+ mKey = null;
+ mRng = null;
+ mFirstOperationInitiated = false;
+ mIv = null;
+ mIvHasBeenUsed = false;
+ mAdditionalEntropyForBegin = null;
+ mOperationToken = null;
+ mOperationHandle = null;
+ mMainDataStreamer = null;
+ }
+
+ private void resetWhilePreservingInitState() {
IBinder operationToken = mOperationToken;
if (operationToken != null) {
mOperationToken = null;
@@ -205,11 +227,17 @@ public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCry
if (mKey == null) {
throw new IllegalStateException("Not initialized");
}
+ if ((mEncrypting) && (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.");
+ }
KeymasterArguments keymasterInputArgs = new KeymasterArguments();
- keymasterInputArgs.addInt(KeymasterDefs.KM_TAG_ALGORITHM, mAlgorithm);
- keymasterInputArgs.addInt(KeymasterDefs.KM_TAG_BLOCK_MODE, mBlockMode);
- keymasterInputArgs.addInt(KeymasterDefs.KM_TAG_PADDING, mPadding);
+ keymasterInputArgs.addInt(KeymasterDefs.KM_TAG_ALGORITHM, mKeymasterAlgorithm);
+ keymasterInputArgs.addInt(KeymasterDefs.KM_TAG_BLOCK_MODE, mKeymasterBlockMode);
+ keymasterInputArgs.addInt(KeymasterDefs.KM_TAG_PADDING, mKeymasterPadding);
addAlgorithmSpecificParametersToBegin(keymasterInputArgs);
KeymasterArguments keymasterOutputArgs = new KeymasterArguments();
@@ -234,6 +262,7 @@ public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCry
mOperationHandle = opResult.operationHandle;
loadAlgorithmSpecificParametersFromBeginResult(keymasterOutputArgs);
mFirstOperationInitiated = true;
+ mIvHasBeenUsed = true;
mMainDataStreamer = new KeyStoreCryptoOperationChunkedStreamer(
new KeyStoreCryptoOperationChunkedStreamer.MainDataStream(
mKeyStore, opResult.token));
@@ -298,7 +327,7 @@ public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCry
}
}
- reset();
+ resetWhilePreservingInitState();
return output;
}
@@ -376,7 +405,7 @@ public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCry
*/
@Override
protected AlgorithmParameters engineGetParameters() {
- if (!mIvUsed) {
+ if (!mIvRequired) {
return null;
}
if ((mIv != null) && (mIv.length > 0)) {
@@ -408,7 +437,7 @@ public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCry
*/
protected void initAlgorithmSpecificParameters(AlgorithmParameterSpec params)
throws InvalidAlgorithmParameterException {
- if (!mIvUsed) {
+ if (!mIvRequired) {
if (params != null) {
throw new InvalidAlgorithmParameterException("Unsupported parameters: " + params);
}
@@ -447,7 +476,7 @@ public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCry
*/
protected void initAlgorithmSpecificParameters(AlgorithmParameters params)
throws InvalidAlgorithmParameterException {
- if (!mIvUsed) {
+ if (!mIvRequired) {
if (params != null) {
throw new InvalidAlgorithmParameterException("Unsupported parameters: " + params);
}
@@ -492,7 +521,7 @@ public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCry
* and thus {@code Cipher.init} needs to be invoked with explicitly provided parameters.
*/
protected void initAlgorithmSpecificParameters() throws InvalidKeyException {
- if (!mIvUsed) {
+ if (!mIvRequired) {
return;
}
@@ -515,7 +544,7 @@ public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCry
if (!mFirstOperationInitiated) {
// First begin operation -- see if we need to provide additional entropy for IV
// generation.
- if (mIvUsed) {
+ if (mIvRequired) {
// IV is needed
if ((mIv == null) && (mEncrypting)) {
// TODO: Switch to keymaster-generated IV code below once keymaster supports
@@ -534,7 +563,7 @@ public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCry
}
}
- if ((mIvUsed) && (mIv != null)) {
+ if ((mIvRequired) && (mIv != null)) {
keymasterArgs.addBlob(KeymasterDefs.KM_TAG_NONCE, mIv);
}
}
@@ -557,7 +586,7 @@ public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCry
returnedIv = null;
}
- if (mIvUsed) {
+ if (mIvRequired) {
if (mIv == null) {
mIv = returnedIv;
} else if ((returnedIv != null) && (!Arrays.equals(returnedIv, mIv))) {
diff --git a/keystore/java/android/security/KeyStoreCryptoOperationChunkedStreamer.java b/keystore/java/android/security/KeyStoreCryptoOperationChunkedStreamer.java
index 1f8b7e4..aafd2fa 100644
--- a/keystore/java/android/security/KeyStoreCryptoOperationChunkedStreamer.java
+++ b/keystore/java/android/security/KeyStoreCryptoOperationChunkedStreamer.java
@@ -19,6 +19,8 @@ package android.security;
import android.os.IBinder;
import android.security.keymaster.OperationResult;
+import libcore.util.EmptyArray;
+
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@@ -95,7 +97,7 @@ public class KeyStoreCryptoOperationChunkedStreamer {
// Too much input for one chunk -- extract one max-sized chunk and feed it into the
// update operation.
inputBytesInChunk = mMaxChunkSize - mBufferedLength;
- chunk = concat(mBuffered, mBufferedOffset, mBufferedLength,
+ chunk = ArrayUtils.concat(mBuffered, mBufferedOffset, mBufferedLength,
input, inputOffset, inputBytesInChunk);
} else {
// All of available input fits into one chunk.
@@ -108,7 +110,7 @@ public class KeyStoreCryptoOperationChunkedStreamer {
} else {
// Need to combine buffered data with input data into one array.
inputBytesInChunk = inputLength;
- chunk = concat(mBuffered, mBufferedOffset, mBufferedLength,
+ chunk = ArrayUtils.concat(mBuffered, mBufferedOffset, mBufferedLength,
input, inputOffset, inputBytesInChunk);
}
}
@@ -197,7 +199,7 @@ public class KeyStoreCryptoOperationChunkedStreamer {
// Flush all buffered input and provided input into keystore/keymaster.
byte[] output = update(input, inputOffset, inputLength);
- output = concat(output, flush());
+ output = ArrayUtils.concat(output, flush());
OperationResult opResult = mKeyStoreStream.finish();
if (opResult == null) {
@@ -206,7 +208,7 @@ public class KeyStoreCryptoOperationChunkedStreamer {
throw KeyStore.getKeyStoreException(opResult.resultCode);
}
- return concat(output, opResult.output);
+ return ArrayUtils.concat(output, opResult.output);
}
/**
@@ -215,11 +217,11 @@ public class KeyStoreCryptoOperationChunkedStreamer {
*/
public byte[] flush() throws KeyStoreException {
if (mBufferedLength <= 0) {
- return EMPTY_BYTE_ARRAY;
+ return EmptyArray.BYTE;
}
- byte[] chunk = subarray(mBuffered, mBufferedOffset, mBufferedLength);
- mBuffered = EMPTY_BYTE_ARRAY;
+ byte[] chunk = ArrayUtils.subarray(mBuffered, mBufferedOffset, mBufferedLength);
+ mBuffered = EmptyArray.BYTE;
mBufferedLength = 0;
mBufferedOffset = 0;
@@ -238,46 +240,7 @@ public class KeyStoreCryptoOperationChunkedStreamer {
+ " . Provided: " + chunk.length + ", consumed: " + opResult.inputConsumed);
}
- return (opResult.output != null) ? opResult.output : EMPTY_BYTE_ARRAY;
- }
-
- private static byte[] concat(byte[] arr1, byte[] arr2) {
- if ((arr1 == null) || (arr1.length == 0)) {
- return arr2;
- } else if ((arr2 == null) || (arr2.length == 0)) {
- return arr1;
- } else {
- byte[] result = new byte[arr1.length + arr2.length];
- System.arraycopy(arr1, 0, result, 0, arr1.length);
- System.arraycopy(arr2, 0, result, arr1.length, arr2.length);
- return result;
- }
- }
-
- private static byte[] concat(byte[] arr1, int offset1, int len1, byte[] arr2, int offset2,
- int len2) {
- if (len1 == 0) {
- return subarray(arr2, offset2, len2);
- } else if (len2 == 0) {
- return subarray(arr1, offset1, len1);
- } else {
- byte[] result = new byte[len1 + len2];
- System.arraycopy(arr1, offset1, result, 0, len1);
- System.arraycopy(arr2, offset2, result, len1, len2);
- return result;
- }
- }
-
- private static byte[] subarray(byte[] arr, int offset, int len) {
- if (len == 0) {
- return EMPTY_BYTE_ARRAY;
- }
- if ((offset == 0) && (len == arr.length)) {
- return arr;
- }
- byte[] result = new byte[len];
- System.arraycopy(arr, offset, result, 0, len);
- return result;
+ return (opResult.output != null) ? opResult.output : EmptyArray.BYTE;
}
/**
diff --git a/keystore/java/android/security/KeyStoreHmacSpi.java b/keystore/java/android/security/KeyStoreHmacSpi.java
index a5864a4..a19bbda 100644
--- a/keystore/java/android/security/KeyStoreHmacSpi.java
+++ b/keystore/java/android/security/KeyStoreHmacSpi.java
@@ -35,14 +35,38 @@ import javax.crypto.MacSpi;
*/
public abstract class KeyStoreHmacSpi extends MacSpi implements KeyStoreCryptoOperation {
+ public static class HmacSHA1 extends KeyStoreHmacSpi {
+ public HmacSHA1() {
+ super(KeymasterDefs.KM_DIGEST_SHA1);
+ }
+ }
+
+ public static class HmacSHA224 extends KeyStoreHmacSpi {
+ public HmacSHA224() {
+ super(KeymasterDefs.KM_DIGEST_SHA_2_224);
+ }
+ }
+
public static class HmacSHA256 extends KeyStoreHmacSpi {
public HmacSHA256() {
- super(KeyStoreKeyConstraints.Digest.SHA256, 256 / 8);
+ super(KeymasterDefs.KM_DIGEST_SHA_2_256);
+ }
+ }
+
+ public static class HmacSHA384 extends KeyStoreHmacSpi {
+ public HmacSHA384() {
+ super(KeymasterDefs.KM_DIGEST_SHA_2_384);
+ }
+ }
+
+ public static class HmacSHA512 extends KeyStoreHmacSpi {
+ public HmacSHA512() {
+ super(KeymasterDefs.KM_DIGEST_SHA_2_512);
}
}
private final KeyStore mKeyStore = KeyStore.getInstance();
- private final @KeyStoreKeyConstraints.DigestEnum int mDigest;
+ private final int mKeymasterDigest;
private final int mMacSizeBytes;
private String mKeyAliasInKeyStore;
@@ -52,9 +76,9 @@ public abstract class KeyStoreHmacSpi extends MacSpi implements KeyStoreCryptoOp
private IBinder mOperationToken;
private Long mOperationHandle;
- protected KeyStoreHmacSpi(@KeyStoreKeyConstraints.DigestEnum int digest, int macSizeBytes) {
- mDigest = digest;
- mMacSizeBytes = macSizeBytes;
+ protected KeyStoreHmacSpi(int keymasterDigest) {
+ mKeymasterDigest = keymasterDigest;
+ mMacSizeBytes = KeymasterUtils.getDigestOutputSizeBytes(keymasterDigest);
}
@Override
@@ -105,8 +129,8 @@ public abstract class KeyStoreHmacSpi extends MacSpi implements KeyStoreCryptoOp
}
KeymasterArguments keymasterArgs = new KeymasterArguments();
- keymasterArgs.addInt(KeymasterDefs.KM_TAG_ALGORITHM, KeyStoreKeyConstraints.Algorithm.HMAC);
- keymasterArgs.addInt(KeymasterDefs.KM_TAG_DIGEST, mDigest);
+ keymasterArgs.addInt(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_HMAC);
+ keymasterArgs.addInt(KeymasterDefs.KM_TAG_DIGEST, mKeymasterDigest);
OperationResult opResult = mKeyStore.begin(mKeyAliasInKeyStore,
KeymasterDefs.KM_PURPOSE_SIGN,
diff --git a/keystore/java/android/security/KeyStoreKeyCharacteristics.java b/keystore/java/android/security/KeyStoreKeyCharacteristics.java
deleted file mode 100644
index 543b5d8..0000000
--- a/keystore/java/android/security/KeyStoreKeyCharacteristics.java
+++ /dev/null
@@ -1,68 +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;
-
-import android.annotation.IntDef;
-import android.security.keymaster.KeymasterDefs;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * Characteristics of {@code AndroidKeyStore} keys.
- *
- * @hide
- */
-public abstract class KeyStoreKeyCharacteristics {
- private KeyStoreKeyCharacteristics() {}
-
- @Retention(RetentionPolicy.SOURCE)
- @IntDef({Origin.GENERATED_INSIDE_TEE, Origin.GENERATED_OUTSIDE_OF_TEE, Origin.IMPORTED})
- public @interface OriginEnum {}
-
- /**
- * Origin of the key.
- */
- public static abstract class Origin {
- private Origin() {}
-
- /** Key was generated inside a TEE. */
- public static final int GENERATED_INSIDE_TEE = 1;
-
- /** Key was generated outside of a TEE. */
- public static final int GENERATED_OUTSIDE_OF_TEE = 2;
-
- /** Key was imported. */
- public static final int IMPORTED = 0;
-
- /**
- * @hide
- */
- public static @OriginEnum int fromKeymaster(int origin) {
- switch (origin) {
- case KeymasterDefs.KM_ORIGIN_HARDWARE:
- return GENERATED_INSIDE_TEE;
- case KeymasterDefs.KM_ORIGIN_SOFTWARE:
- return GENERATED_OUTSIDE_OF_TEE;
- case KeymasterDefs.KM_ORIGIN_IMPORTED:
- return IMPORTED;
- default:
- throw new IllegalArgumentException("Unknown origin: " + origin);
- }
- }
- }
-}
diff --git a/keystore/java/android/security/KeyStoreKeyConstraints.java b/keystore/java/android/security/KeyStoreKeyConstraints.java
deleted file mode 100644
index c27ccb1..0000000
--- a/keystore/java/android/security/KeyStoreKeyConstraints.java
+++ /dev/null
@@ -1,609 +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;
-
-import android.annotation.IntDef;
-import android.security.keymaster.KeymasterDefs;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Locale;
-import java.util.Set;
-
-/**
- * Constraints for {@code AndroidKeyStore} keys.
- *
- * @hide
- */
-public abstract class KeyStoreKeyConstraints {
- private KeyStoreKeyConstraints() {}
-
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(flag=true, value={Purpose.ENCRYPT, Purpose.DECRYPT, Purpose.SIGN, Purpose.VERIFY})
- public @interface PurposeEnum {}
-
- /**
- * Purpose of key.
- */
- public static abstract class Purpose {
- private Purpose() {}
-
- /**
- * Purpose: encryption.
- */
- public static final int ENCRYPT = 1 << 0;
-
- /**
- * Purpose: decryption.
- */
- public static final int DECRYPT = 1 << 1;
-
- /**
- * Purpose: signing.
- */
- public static final int SIGN = 1 << 2;
-
- /**
- * Purpose: signature verification.
- */
- public static final int VERIFY = 1 << 3;
-
- /**
- * Number of flags defined above. Needs to be kept in sync with the flags above.
- */
- private static final int VALUE_COUNT = 4;
-
- /**
- * @hide
- */
- public static int toKeymaster(@PurposeEnum int purpose) {
- switch (purpose) {
- case ENCRYPT:
- return KeymasterDefs.KM_PURPOSE_ENCRYPT;
- case DECRYPT:
- return KeymasterDefs.KM_PURPOSE_DECRYPT;
- case SIGN:
- return KeymasterDefs.KM_PURPOSE_SIGN;
- case VERIFY:
- return KeymasterDefs.KM_PURPOSE_VERIFY;
- default:
- throw new IllegalArgumentException("Unknown purpose: " + purpose);
- }
- }
-
- /**
- * @hide
- */
- public static @PurposeEnum int fromKeymaster(int purpose) {
- switch (purpose) {
- case KeymasterDefs.KM_PURPOSE_ENCRYPT:
- return ENCRYPT;
- case KeymasterDefs.KM_PURPOSE_DECRYPT:
- return DECRYPT;
- case KeymasterDefs.KM_PURPOSE_SIGN:
- return SIGN;
- case KeymasterDefs.KM_PURPOSE_VERIFY:
- return VERIFY;
- default:
- throw new IllegalArgumentException("Unknown purpose: " + purpose);
- }
- }
-
- /**
- * @hide
- */
- public static int[] allToKeymaster(int purposes) {
- int[] result = new int[VALUE_COUNT];
- int resultCount = 0;
- int purpose = 1;
- for (int i = 0; i < 32; i++) {
- if ((purposes & 1) != 0) {
- result[resultCount] = toKeymaster(purpose);
- resultCount++;
- }
- purposes >>>= 1;
- purpose <<= 1;
- if (purposes == 0) {
- break;
- }
- }
- return Arrays.copyOf(result, resultCount);
- }
-
- /**
- * @hide
- */
- public static @PurposeEnum int allFromKeymaster(Collection<Integer> purposes) {
- @PurposeEnum int result = 0;
- for (int keymasterPurpose : purposes) {
- result |= fromKeymaster(keymasterPurpose);
- }
- return result;
- }
- }
-
- @Retention(RetentionPolicy.SOURCE)
- @IntDef({Algorithm.AES, Algorithm.HMAC})
- public @interface AlgorithmEnum {}
-
- /**
- * Key algorithm.
- */
- public static abstract class Algorithm {
- private Algorithm() {}
-
- /**
- * Key algorithm: AES.
- */
- public static final int AES = 0;
-
- /**
- * Key algorithm: HMAC.
- */
- public static final int HMAC = 1;
-
- /**
- * @hide
- */
- public static int toKeymaster(@AlgorithmEnum int algorithm) {
- switch (algorithm) {
- case AES:
- return KeymasterDefs.KM_ALGORITHM_AES;
- case HMAC:
- return KeymasterDefs.KM_ALGORITHM_HMAC;
- default:
- throw new IllegalArgumentException("Unknown algorithm: " + algorithm);
- }
- }
-
- /**
- * @hide
- */
- public static @AlgorithmEnum int fromKeymaster(int algorithm) {
- switch (algorithm) {
- case KeymasterDefs.KM_ALGORITHM_AES:
- return AES;
- case KeymasterDefs.KM_ALGORITHM_HMAC:
- return HMAC;
- default:
- throw new IllegalArgumentException("Unknown algorithm: " + algorithm);
- }
- }
-
- /**
- * @hide
- */
- public static String toString(@AlgorithmEnum int algorithm) {
- switch (algorithm) {
- case AES:
- return "AES";
- case HMAC:
- return "HMAC";
- default:
- throw new IllegalArgumentException("Unknown algorithm: " + algorithm);
- }
- }
-
- /**
- * @hide
- */
- public static @AlgorithmEnum int fromJCASecretKeyAlgorithm(String algorithm) {
- if (algorithm == null) {
- throw new NullPointerException("algorithm == null");
- } else if ("AES".equalsIgnoreCase(algorithm)) {
- return AES;
- } else if (algorithm.toLowerCase(Locale.US).startsWith("hmac")) {
- return HMAC;
- } else {
- throw new IllegalArgumentException(
- "Unsupported secret key algorithm: " + algorithm);
- }
- }
-
- /**
- * @hide
- */
- public static String toJCASecretKeyAlgorithm(@AlgorithmEnum int algorithm,
- @DigestEnum Integer digest) {
- switch (algorithm) {
- case AES:
- return "AES";
- case HMAC:
- if (digest == null) {
- throw new IllegalArgumentException("HMAC digest not specified");
- }
- switch (digest) {
- case Digest.SHA256:
- return "HmacSHA256";
- default:
- throw new IllegalArgumentException(
- "Unsupported HMAC digest: " + digest);
- }
- default:
- throw new IllegalArgumentException("Unsupported key algorithm: " + algorithm);
- }
- }
- }
-
- @Retention(RetentionPolicy.SOURCE)
- @IntDef({Padding.NONE, Padding.ZERO, Padding.PKCS7})
- public @interface PaddingEnum {}
-
- /**
- * Padding for signing and encryption.
- */
- public static abstract class Padding {
- private Padding() {}
-
- /**
- * No padding.
- */
- public static final int NONE = 0;
-
- /**
- * Pad with zeros.
- */
- public static final int ZERO = 1;
-
- /**
- * PKCS#7 padding.
- */
- public static final int PKCS7 = 2;
-
- /**
- * @hide
- */
- public static int toKeymaster(int padding) {
- switch (padding) {
- case NONE:
- return KeymasterDefs.KM_PAD_NONE;
- case ZERO:
- return KeymasterDefs.KM_PAD_ZERO;
- case PKCS7:
- return KeymasterDefs.KM_PAD_PKCS7;
- default:
- throw new IllegalArgumentException("Unknown padding: " + padding);
- }
- }
-
- /**
- * @hide
- */
- public static @PaddingEnum int fromKeymaster(int padding) {
- switch (padding) {
- case KeymasterDefs.KM_PAD_NONE:
- return NONE;
- case KeymasterDefs.KM_PAD_ZERO:
- return ZERO;
- case KeymasterDefs.KM_PAD_PKCS7:
- return PKCS7;
- default:
- throw new IllegalArgumentException("Unknown padding: " + padding);
- }
- }
-
- /**
- * @hide
- */
- public static String toString(@PaddingEnum int padding) {
- switch (padding) {
- case NONE:
- return "NONE";
- case ZERO:
- return "ZERO";
- case PKCS7:
- return "PKCS#7";
- default:
- throw new IllegalArgumentException("Unknown padding: " + padding);
- }
- }
-
- /**
- * @hide
- */
- public static @PaddingEnum int fromJCAPadding(String padding) {
- String paddingLower = padding.toLowerCase(Locale.US);
- if ("nopadding".equals(paddingLower)) {
- return NONE;
- } else if ("pkcs7padding".equals(paddingLower)) {
- return PKCS7;
- } else {
- throw new IllegalArgumentException("Unknown padding: " + padding);
- }
- }
- }
-
- @Retention(RetentionPolicy.SOURCE)
- @IntDef({Digest.NONE, Digest.SHA256})
- public @interface DigestEnum {}
-
- /**
- * Digests that can be used with a key when signing or generating Message Authentication
- * Codes (MACs).
- */
- public static abstract class Digest {
- private Digest() {}
-
- /**
- * No digest: sign/authenticate the raw message.
- */
- public static final int NONE = 0;
-
- /**
- * SHA-256 digest.
- */
- public static final int SHA256 = 1;
-
- /**
- * @hide
- */
- public static String toString(@DigestEnum int digest) {
- switch (digest) {
- case NONE:
- return "NONE";
- case SHA256:
- return "SHA256";
- default:
- throw new IllegalArgumentException("Unknown digest: " + digest);
- }
- }
-
- /**
- * @hide
- */
- public static int toKeymaster(@DigestEnum int digest) {
- switch (digest) {
- case NONE:
- return KeymasterDefs.KM_DIGEST_NONE;
- case SHA256:
- return KeymasterDefs.KM_DIGEST_SHA_2_256;
- default:
- throw new IllegalArgumentException("Unknown digest: " + digest);
- }
- }
-
- /**
- * @hide
- */
- public static @DigestEnum int fromKeymaster(int digest) {
- switch (digest) {
- case KeymasterDefs.KM_DIGEST_NONE:
- return NONE;
- case KeymasterDefs.KM_DIGEST_SHA_2_256:
- return SHA256;
- default:
- throw new IllegalArgumentException("Unknown digest: " + digest);
- }
- }
-
- /**
- * @hide
- */
- public static @DigestEnum Integer fromJCASecretKeyAlgorithm(String algorithm) {
- String algorithmLower = algorithm.toLowerCase(Locale.US);
- if (algorithmLower.startsWith("hmac")) {
- if ("hmacsha256".equals(algorithmLower)) {
- return SHA256;
- } else {
- throw new IllegalArgumentException("Unsupported digest: "
- + algorithmLower.substring("hmac".length()));
- }
- } else {
- return null;
- }
- }
-
- /**
- * @hide
- */
- public static String toJCASignatureAlgorithmDigest(@DigestEnum int digest) {
- switch (digest) {
- case NONE:
- return "NONE";
- case SHA256:
- return "SHA256";
- default:
- throw new IllegalArgumentException("Unknown digest: " + digest);
- }
- }
-
- /**
- * @hide
- */
- public static Integer getOutputSizeBytes(@DigestEnum int digest) {
- switch (digest) {
- case NONE:
- return null;
- case SHA256:
- return 256 / 8;
- default:
- throw new IllegalArgumentException("Unknown digest: " + digest);
- }
- }
- }
-
- @Retention(RetentionPolicy.SOURCE)
- @IntDef({BlockMode.ECB, BlockMode.CBC, BlockMode.CTR})
- public @interface BlockModeEnum {}
-
- /**
- * Block modes that can be used when encrypting/decrypting using a key.
- */
- public static abstract class BlockMode {
- private BlockMode() {}
-
- /** Electronic Codebook (ECB) block mode. */
- public static final int ECB = 0;
-
- /** Cipher Block Chaining (CBC) block mode. */
- public static final int CBC = 1;
-
- /** Counter (CTR) block mode. */
- public static final int CTR = 2;
-
- /**
- * @hide
- */
- public static int toKeymaster(@BlockModeEnum int mode) {
- switch (mode) {
- case ECB:
- return KeymasterDefs.KM_MODE_ECB;
- case CBC:
- return KeymasterDefs.KM_MODE_CBC;
- case CTR:
- return KeymasterDefs.KM_MODE_CTR;
- default:
- throw new IllegalArgumentException("Unknown block mode: " + mode);
- }
- }
-
- /**
- * @hide
- */
- public static @BlockModeEnum int fromKeymaster(int mode) {
- switch (mode) {
- case KeymasterDefs.KM_MODE_ECB:
- return ECB;
- case KeymasterDefs.KM_MODE_CBC:
- return CBC;
- case KeymasterDefs.KM_MODE_CTR:
- return CTR;
- default:
- throw new IllegalArgumentException("Unknown block mode: " + mode);
- }
- }
-
- /**
- * @hide
- */
- public static String toString(@BlockModeEnum int mode) {
- switch (mode) {
- case ECB:
- return "ECB";
- case CBC:
- return "CBC";
- case CTR:
- return "CTR";
- default:
- throw new IllegalArgumentException("Unknown block mode: " + mode);
- }
- }
-
- /**
- * @hide
- */
- public static @BlockModeEnum int fromJCAMode(String mode) {
- String modeLower = mode.toLowerCase(Locale.US);
- if ("ecb".equals(modeLower)) {
- return ECB;
- } else if ("cbc".equals(modeLower)) {
- return CBC;
- } else if ("ctr".equals(modeLower)) {
- return CTR;
- } else {
- throw new IllegalArgumentException("Unknown block mode: " + mode);
- }
- }
- }
-
- @Retention(RetentionPolicy.SOURCE)
- @IntDef({UserAuthenticator.LOCK_SCREEN})
- public @interface UserAuthenticatorEnum {}
-
- /**
- * User authenticators which can be used to restrict/protect access to keys.
- */
- public static abstract class UserAuthenticator {
- private UserAuthenticator() {}
-
- /** Lock screen. */
- public static final int LOCK_SCREEN = 1;
-
- /**
- * @hide
- */
- public static int toKeymaster(@UserAuthenticatorEnum int userAuthenticator) {
- switch (userAuthenticator) {
- case LOCK_SCREEN:
- return LOCK_SCREEN;
- default:
- throw new IllegalArgumentException(
- "Unknown user authenticator: " + userAuthenticator);
- }
- }
-
- /**
- * @hide
- */
- public static @UserAuthenticatorEnum int fromKeymaster(int userAuthenticator) {
- switch (userAuthenticator) {
- case LOCK_SCREEN:
- return LOCK_SCREEN;
- default:
- throw new IllegalArgumentException(
- "Unknown user authenticator: " + userAuthenticator);
- }
- }
-
- /**
- * @hide
- */
- public static int allToKeymaster(Set<Integer> userAuthenticators) {
- int result = 0;
- for (@UserAuthenticatorEnum int userAuthenticator : userAuthenticators) {
- result |= toKeymaster(userAuthenticator);
- }
- return result;
- }
-
- /**
- * @hide
- */
- public static Set<Integer> allFromKeymaster(int userAuthenticators) {
- int userAuthenticator = 1;
- Set<Integer> result = null;
- while (userAuthenticators != 0) {
- if ((userAuthenticators & 1) != 0) {
- if (result == null) {
- result = new HashSet<Integer>();
- }
- result.add(fromKeymaster(userAuthenticator));
- }
- userAuthenticators >>>= 1;
- userAuthenticator <<= 1;
- }
- return (result != null) ? result : Collections.<Integer>emptySet();
- }
-
- /**
- * @hide
- */
- public static String toString(@UserAuthenticatorEnum int userAuthenticator) {
- switch (userAuthenticator) {
- case LOCK_SCREEN:
- return "LOCK_SCREEN";
- default:
- throw new IllegalArgumentException(
- "Unknown user authenticator: " + userAuthenticator);
- }
- }
- }
-}
diff --git a/keystore/java/android/security/KeyStoreKeyGeneratorSpi.java b/keystore/java/android/security/KeyStoreKeyGeneratorSpi.java
index c9c9bd8..87e7ee6 100644
--- a/keystore/java/android/security/KeyStoreKeyGeneratorSpi.java
+++ b/keystore/java/android/security/KeyStoreKeyGeneratorSpi.java
@@ -37,39 +37,68 @@ public abstract class KeyStoreKeyGeneratorSpi extends KeyGeneratorSpi {
public static class AES extends KeyStoreKeyGeneratorSpi {
public AES() {
- super(KeyStoreKeyConstraints.Algorithm.AES, 128);
+ super(KeymasterDefs.KM_ALGORITHM_AES, 128);
}
}
- public static class HmacSHA256 extends KeyStoreKeyGeneratorSpi {
+ protected static abstract class HmacBase extends KeyStoreKeyGeneratorSpi {
+ protected HmacBase(int keymasterDigest) {
+ super(KeymasterDefs.KM_ALGORITHM_HMAC,
+ keymasterDigest,
+ KeymasterUtils.getDigestOutputSizeBytes(keymasterDigest) * 8);
+ }
+ }
+
+ 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(KeyStoreKeyConstraints.Algorithm.HMAC,
- KeyStoreKeyConstraints.Digest.SHA256,
- KeyStoreKeyConstraints.Digest.getOutputSizeBytes(
- KeyStoreKeyConstraints.Digest.SHA256) * 8);
+ 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 @KeyStoreKeyConstraints.AlgorithmEnum int mAlgorithm;
- private final @KeyStoreKeyConstraints.DigestEnum Integer mDigest;
+ private final int mKeymasterAlgorithm;
+ private final int mKeymasterDigest;
private final int mDefaultKeySizeBits;
private KeyGeneratorSpec mSpec;
private SecureRandom mRng;
protected KeyStoreKeyGeneratorSpi(
- @KeyStoreKeyConstraints.AlgorithmEnum int algorithm,
+ int keymasterAlgorithm,
int defaultKeySizeBits) {
- this(algorithm, null, defaultKeySizeBits);
+ this(keymasterAlgorithm, -1, defaultKeySizeBits);
}
protected KeyStoreKeyGeneratorSpi(
- @KeyStoreKeyConstraints.AlgorithmEnum int algorithm,
- @KeyStoreKeyConstraints.DigestEnum Integer digest,
+ int keymasterAlgorithm,
+ int keymasterDigest,
int defaultKeySizeBits) {
- mAlgorithm = algorithm;
- mDigest = digest;
+ mKeymasterAlgorithm = keymasterAlgorithm;
+ mKeymasterDigest = keymasterDigest;
mDefaultKeySizeBits = defaultKeySizeBits;
}
@@ -88,60 +117,58 @@ public abstract class KeyStoreKeyGeneratorSpi extends KeyGeneratorSpi {
}
KeymasterArguments args = new KeymasterArguments();
- args.addInt(KeymasterDefs.KM_TAG_ALGORITHM,
- KeyStoreKeyConstraints.Algorithm.toKeymaster(mAlgorithm));
- if (mDigest != null) {
- args.addInt(KeymasterDefs.KM_TAG_DIGEST,
- KeyStoreKeyConstraints.Digest.toKeymaster(mDigest));
- Integer digestOutputSizeBytes =
- KeyStoreKeyConstraints.Digest.getOutputSizeBytes(mDigest);
- if (digestOutputSizeBytes != null) {
+ args.addInt(KeymasterDefs.KM_TAG_ALGORITHM, mKeymasterAlgorithm);
+ if (mKeymasterDigest != -1) {
+ args.addInt(KeymasterDefs.KM_TAG_DIGEST, mKeymasterDigest);
+ int digestOutputSizeBytes =
+ KeymasterUtils.getDigestOutputSizeBytes(mKeymasterDigest);
+ if (digestOutputSizeBytes != -1) {
// TODO: Remove MAC length constraint once Keymaster API no longer requires it.
// TODO: Switch to bits instead of bytes, once this is fixed in Keymaster
args.addInt(KeymasterDefs.KM_TAG_MAC_LENGTH, digestOutputSizeBytes);
}
}
- if (mAlgorithm == KeyStoreKeyConstraints.Algorithm.HMAC) {
- if (mDigest == null) {
- throw new IllegalStateException("Digest algorithm must be specified for key"
- + " algorithm " + KeyStoreKeyConstraints.Algorithm.toString(mAlgorithm));
+ if (mKeymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_HMAC) {
+ if (mKeymasterDigest == -1) {
+ throw new IllegalStateException("Digest algorithm must be specified for HMAC key");
}
}
int keySizeBits = (spec.getKeySize() != null) ? spec.getKeySize() : mDefaultKeySizeBits;
args.addInt(KeymasterDefs.KM_TAG_KEY_SIZE, keySizeBits);
- @KeyStoreKeyConstraints.PurposeEnum int purposes = (spec.getPurposes() != null)
- ? spec.getPurposes()
- : (KeyStoreKeyConstraints.Purpose.ENCRYPT
- | KeyStoreKeyConstraints.Purpose.DECRYPT
- | KeyStoreKeyConstraints.Purpose.SIGN
- | KeyStoreKeyConstraints.Purpose.VERIFY);
+ @KeyStoreKeyProperties.PurposeEnum int purposes = spec.getPurposes();
+ int[] keymasterBlockModes = KeymasterUtils.getKeymasterBlockModesFromJcaBlockModes(
+ spec.getBlockModes());
+ if (((purposes & KeyStoreKeyProperties.Purpose.ENCRYPT) != 0)
+ && (spec.isRandomizedEncryptionRequired())) {
+ for (int keymasterBlockMode : keymasterBlockModes) {
+ if (!KeymasterUtils.isKeymasterBlockModeIndCpaCompatible(keymasterBlockMode)) {
+ throw new IllegalStateException(
+ "Randomized encryption (IND-CPA) required but may be violated by block"
+ + " mode: "
+ + KeymasterUtils.getJcaBlockModeFromKeymasterBlockMode(
+ keymasterBlockMode)
+ + ". See KeyGeneratorSpec documentation.");
+ }
+ }
+ }
+
for (int keymasterPurpose :
- KeyStoreKeyConstraints.Purpose.allToKeymaster(purposes)) {
+ KeyStoreKeyProperties.Purpose.allToKeymaster(purposes)) {
args.addInt(KeymasterDefs.KM_TAG_PURPOSE, keymasterPurpose);
}
- if (spec.getBlockMode() != null) {
- args.addInt(KeymasterDefs.KM_TAG_BLOCK_MODE,
- KeyStoreKeyConstraints.BlockMode.toKeymaster(spec.getBlockMode()));
- }
- if (spec.getPadding() != null) {
- args.addInt(KeymasterDefs.KM_TAG_PADDING,
- KeyStoreKeyConstraints.Padding.toKeymaster(spec.getPadding()));
- }
- if (spec.getMaxUsesPerBoot() != null) {
- args.addInt(KeymasterDefs.KM_TAG_MAX_USES_PER_BOOT, spec.getMaxUsesPerBoot());
- }
- if (spec.getMinSecondsBetweenOperations() != null) {
- args.addInt(KeymasterDefs.KM_TAG_MIN_SECONDS_BETWEEN_OPS,
- spec.getMinSecondsBetweenOperations());
- }
- if (spec.getUserAuthenticators().isEmpty()) {
+ args.addInts(KeymasterDefs.KM_TAG_BLOCK_MODE, keymasterBlockModes);
+ args.addInts(
+ KeymasterDefs.KM_TAG_PADDING,
+ KeymasterUtils.getKeymasterPaddingsFromJcaEncryptionPaddings(
+ spec.getEncryptionPaddings()));
+ if (spec.getUserAuthenticators() == 0) {
args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
} else {
args.addInt(KeymasterDefs.KM_TAG_USER_AUTH_TYPE,
- KeyStoreKeyConstraints.UserAuthenticator.allToKeymaster(
+ KeyStoreKeyProperties.UserAuthenticator.allToKeymaster(
spec.getUserAuthenticators()));
}
- if (spec.getUserAuthenticationValidityDurationSeconds() != null) {
+ if (spec.getUserAuthenticationValidityDurationSeconds() != -1) {
args.addInt(KeymasterDefs.KM_TAG_AUTH_TIMEOUT,
spec.getUserAuthenticationValidityDurationSeconds());
}
@@ -155,9 +182,9 @@ public abstract class KeyStoreKeyGeneratorSpi extends KeyGeneratorSpi {
(spec.getKeyValidityForConsumptionEnd() != null)
? spec.getKeyValidityForConsumptionEnd() : new Date(Long.MAX_VALUE));
- if (((purposes & KeyStoreKeyConstraints.Purpose.ENCRYPT) != 0)
- || ((purposes & KeyStoreKeyConstraints.Purpose.DECRYPT) != 0)) {
- // Permit caller-specified IV. This is needed due to the Cipher abstraction.
+ if (((purposes & KeyStoreKeyProperties.Purpose.ENCRYPT) != 0)
+ && (!spec.isRandomizedEncryptionRequired())) {
+ // Permit caller-provided IV when encrypting with this key
args.addBoolean(KeymasterDefs.KM_TAG_CALLER_NONCE);
}
@@ -176,7 +203,7 @@ public abstract class KeyStoreKeyGeneratorSpi extends KeyGeneratorSpi {
throw KeyStore.getCryptoOperationException(errorCode);
}
String keyAlgorithmJCA =
- KeyStoreKeyConstraints.Algorithm.toJCASecretKeyAlgorithm(mAlgorithm, mDigest);
+ KeymasterUtils.getJcaSecretKeyAlgorithm(mKeymasterAlgorithm, mKeymasterDigest);
return new KeyStoreSecretKey(keyAliasInKeystore, keyAlgorithmJCA);
}
diff --git a/keystore/java/android/security/KeyStoreKeyProperties.java b/keystore/java/android/security/KeyStoreKeyProperties.java
new file mode 100644
index 0000000..d8ad1d3
--- /dev/null
+++ b/keystore/java/android/security/KeyStoreKeyProperties.java
@@ -0,0 +1,274 @@
+/*
+ * 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;
+
+import android.annotation.IntDef;
+import android.security.keymaster.KeymasterDefs;
+
+import libcore.util.EmptyArray;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Collection;
+
+/**
+ * Properties of {@code AndroidKeyStore} keys.
+ *
+ * @hide
+ */
+public abstract class KeyStoreKeyProperties {
+ private KeyStoreKeyProperties() {}
+
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag = true,
+ value = {Purpose.ENCRYPT, Purpose.DECRYPT, Purpose.SIGN, Purpose.VERIFY})
+ public @interface PurposeEnum {}
+
+ /**
+ * Purpose of key.
+ */
+ public static abstract class Purpose {
+ private Purpose() {}
+
+ /**
+ * Purpose: encryption.
+ */
+ public static final int ENCRYPT = 1 << 0;
+
+ /**
+ * Purpose: decryption.
+ */
+ public static final int DECRYPT = 1 << 1;
+
+ /**
+ * Purpose: signing.
+ */
+ public static final int SIGN = 1 << 2;
+
+ /**
+ * Purpose: signature verification.
+ */
+ public static final int VERIFY = 1 << 3;
+
+ /**
+ * @hide
+ */
+ public static int toKeymaster(@PurposeEnum int purpose) {
+ switch (purpose) {
+ case ENCRYPT:
+ return KeymasterDefs.KM_PURPOSE_ENCRYPT;
+ case DECRYPT:
+ return KeymasterDefs.KM_PURPOSE_DECRYPT;
+ case SIGN:
+ return KeymasterDefs.KM_PURPOSE_SIGN;
+ case VERIFY:
+ return KeymasterDefs.KM_PURPOSE_VERIFY;
+ default:
+ throw new IllegalArgumentException("Unknown purpose: " + purpose);
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public static @PurposeEnum int fromKeymaster(int purpose) {
+ switch (purpose) {
+ case KeymasterDefs.KM_PURPOSE_ENCRYPT:
+ return ENCRYPT;
+ case KeymasterDefs.KM_PURPOSE_DECRYPT:
+ return DECRYPT;
+ case KeymasterDefs.KM_PURPOSE_SIGN:
+ return SIGN;
+ case KeymasterDefs.KM_PURPOSE_VERIFY:
+ return VERIFY;
+ default:
+ throw new IllegalArgumentException("Unknown purpose: " + purpose);
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public static int[] allToKeymaster(@PurposeEnum int purposes) {
+ int[] result = getSetFlags(purposes);
+ for (int i = 0; i < result.length; i++) {
+ result[i] = toKeymaster(result[i]);
+ }
+ return result;
+ }
+
+ /**
+ * @hide
+ */
+ public static @PurposeEnum int allFromKeymaster(Collection<Integer> purposes) {
+ @PurposeEnum int result = 0;
+ for (int keymasterPurpose : purposes) {
+ result |= fromKeymaster(keymasterPurpose);
+ }
+ return result;
+ }
+ }
+
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag = true,
+ value = {UserAuthenticator.LOCK_SCREEN})
+ public @interface UserAuthenticatorEnum {}
+
+ /**
+ * User authenticators which can be used to restrict/protect access to keys.
+ */
+ public static abstract class UserAuthenticator {
+ private UserAuthenticator() {}
+
+ /** Lock screen. */
+ public static final int LOCK_SCREEN = 1 << 0;
+
+ /**
+ * @hide
+ */
+ public static int toKeymaster(@UserAuthenticatorEnum int userAuthenticator) {
+ switch (userAuthenticator) {
+ case LOCK_SCREEN:
+ return KeymasterDefs.HW_AUTH_PASSWORD;
+ default:
+ throw new IllegalArgumentException(
+ "Unknown user authenticator: " + userAuthenticator);
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public static @UserAuthenticatorEnum int fromKeymaster(int userAuthenticator) {
+ switch (userAuthenticator) {
+ case KeymasterDefs.HW_AUTH_PASSWORD:
+ return LOCK_SCREEN;
+ default:
+ throw new IllegalArgumentException(
+ "Unknown user authenticator: " + userAuthenticator);
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public static int allToKeymaster(@UserAuthenticatorEnum int userAuthenticators) {
+ int result = 0;
+ int userAuthenticator = 1;
+ while (userAuthenticators != 0) {
+ if ((userAuthenticators & 1) != 0) {
+ result |= toKeymaster(userAuthenticator);
+ }
+ userAuthenticators >>>= 1;
+ userAuthenticator <<= 1;
+ }
+ return result;
+ }
+
+ /**
+ * @hide
+ */
+ public static @UserAuthenticatorEnum int allFromKeymaster(int userAuthenticators) {
+ @UserAuthenticatorEnum int result = 0;
+ int userAuthenticator = 1;
+ while (userAuthenticators != 0) {
+ if ((userAuthenticators & 1) != 0) {
+ result |= fromKeymaster(userAuthenticator);
+ }
+ userAuthenticators >>>= 1;
+ userAuthenticator <<= 1;
+ }
+ return result;
+ }
+
+ /**
+ * @hide
+ */
+ public static String toString(@UserAuthenticatorEnum int userAuthenticator) {
+ switch (userAuthenticator) {
+ case LOCK_SCREEN:
+ return "LOCK_SCREEN";
+ default:
+ throw new IllegalArgumentException(
+ "Unknown user authenticator: " + userAuthenticator);
+ }
+ }
+ }
+
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({Origin.GENERATED, Origin.IMPORTED})
+ public @interface OriginEnum {}
+
+ /**
+ * Origin of the key.
+ */
+ public static abstract class Origin {
+ private Origin() {}
+
+ /** Key was generated inside AndroidKeyStore. */
+ public static final int GENERATED = 1 << 0;
+
+ /** Key was imported into AndroidKeyStore. */
+ public static final int IMPORTED = 1 << 1;
+
+ /**
+ * @hide
+ */
+ public static @OriginEnum int fromKeymaster(int origin) {
+ switch (origin) {
+ case KeymasterDefs.KM_ORIGIN_HARDWARE:
+ return GENERATED;
+ case KeymasterDefs.KM_ORIGIN_IMPORTED:
+ return IMPORTED;
+ default:
+ throw new IllegalArgumentException("Unknown origin: " + origin);
+ }
+ }
+ }
+
+ private static int[] getSetFlags(int flags) {
+ if (flags == 0) {
+ return EmptyArray.INT;
+ }
+ int result[] = new int[getSetBitCount(flags)];
+ int resultOffset = 0;
+ int flag = 1;
+ while (flags != 0) {
+ if ((flags & 1) != 0) {
+ result[resultOffset] = flag;
+ resultOffset++;
+ }
+ flags >>>= 1;
+ flag <<= 1;
+ }
+ return result;
+ }
+
+ private static int getSetBitCount(int value) {
+ if (value == 0) {
+ return 0;
+ }
+ int result = 0;
+ while (value != 0) {
+ if ((value & 1) != 0) {
+ result++;
+ }
+ value >>>= 1;
+ }
+ return result;
+ }
+}
diff --git a/keystore/java/android/security/KeyStoreKeySpec.java b/keystore/java/android/security/KeyStoreKeySpec.java
index ddeefbd..861ed34 100644
--- a/keystore/java/android/security/KeyStoreKeySpec.java
+++ b/keystore/java/android/security/KeyStoreKeySpec.java
@@ -17,10 +17,7 @@
package android.security;
import java.security.spec.KeySpec;
-import java.util.Collections;
import java.util.Date;
-import java.util.HashSet;
-import java.util.Set;
/**
* Information about a key from the <a href="{@docRoot}training/articles/keystore.html">Android
@@ -31,58 +28,55 @@ import java.util.Set;
public class KeyStoreKeySpec implements KeySpec {
private final String mKeystoreAlias;
private final int mKeySize;
- private final @KeyStoreKeyCharacteristics.OriginEnum int mOrigin;
+ private final boolean mTeeBacked;
+ private final @KeyStoreKeyProperties.OriginEnum int mOrigin;
private final Date mKeyValidityStart;
private final Date mKeyValidityForOriginationEnd;
private final Date mKeyValidityForConsumptionEnd;
- private final @KeyStoreKeyConstraints.PurposeEnum int mPurposes;
- private final @KeyStoreKeyConstraints.AlgorithmEnum int mAlgorithm;
- private final @KeyStoreKeyConstraints.PaddingEnum Integer mPadding;
- private final @KeyStoreKeyConstraints.DigestEnum Integer mDigest;
- private final @KeyStoreKeyConstraints.BlockModeEnum Integer mBlockMode;
- private final Integer mMinSecondsBetweenOperations;
- private final Integer mMaxUsesPerBoot;
- private final Set<Integer> mUserAuthenticators;
- private final Set<Integer> mTeeBackedUserAuthenticators;
- private final Integer mUserAuthenticationValidityDurationSeconds;
+ private final @KeyStoreKeyProperties.PurposeEnum int mPurposes;
+ private final String[] mEncryptionPaddings;
+ private final String[] mSignaturePaddings;
+ private final String[] mDigests;
+ private final String[] mBlockModes;
+ private final @KeyStoreKeyProperties.UserAuthenticatorEnum int mUserAuthenticators;
+ private final @KeyStoreKeyProperties.UserAuthenticatorEnum int mTeeEnforcedUserAuthenticators;
+ private final int mUserAuthenticationValidityDurationSeconds;
/**
* @hide
*/
KeyStoreKeySpec(String keystoreKeyAlias,
- @KeyStoreKeyCharacteristics.OriginEnum int origin,
- int keySize, Date keyValidityStart, Date keyValidityForOriginationEnd,
+ boolean teeBacked,
+ @KeyStoreKeyProperties.OriginEnum int origin,
+ int keySize,
+ Date keyValidityStart,
+ Date keyValidityForOriginationEnd,
Date keyValidityForConsumptionEnd,
- @KeyStoreKeyConstraints.PurposeEnum int purposes,
- @KeyStoreKeyConstraints.AlgorithmEnum int algorithm,
- @KeyStoreKeyConstraints.PaddingEnum Integer padding,
- @KeyStoreKeyConstraints.DigestEnum Integer digest,
- @KeyStoreKeyConstraints.BlockModeEnum Integer blockMode,
- Integer minSecondsBetweenOperations,
- Integer maxUsesPerBoot,
- Set<Integer> userAuthenticators,
- Set<Integer> teeBackedUserAuthenticators,
- Integer userAuthenticationValidityDurationSeconds) {
+ @KeyStoreKeyProperties.PurposeEnum int purposes,
+ String[] encryptionPaddings,
+ String[] signaturePaddings,
+ String[] digests,
+ String[] blockModes,
+ @KeyStoreKeyProperties.UserAuthenticatorEnum int userAuthenticators,
+ @KeyStoreKeyProperties.UserAuthenticatorEnum int teeEnforcedUserAuthenticators,
+ int userAuthenticationValidityDurationSeconds) {
mKeystoreAlias = keystoreKeyAlias;
+ mTeeBacked = teeBacked;
mOrigin = origin;
mKeySize = keySize;
mKeyValidityStart = keyValidityStart;
mKeyValidityForOriginationEnd = keyValidityForOriginationEnd;
mKeyValidityForConsumptionEnd = keyValidityForConsumptionEnd;
mPurposes = purposes;
- mAlgorithm = algorithm;
- mPadding = padding;
- mDigest = digest;
- mBlockMode = blockMode;
- mMinSecondsBetweenOperations = minSecondsBetweenOperations;
- mMaxUsesPerBoot = maxUsesPerBoot;
- mUserAuthenticators = (userAuthenticators != null)
- ? new HashSet<Integer>(userAuthenticators)
- : Collections.<Integer>emptySet();
- mTeeBackedUserAuthenticators = (teeBackedUserAuthenticators != null)
- ? new HashSet<Integer>(teeBackedUserAuthenticators)
- : Collections.<Integer>emptySet();
+ mEncryptionPaddings =
+ ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(encryptionPaddings));
+ mSignaturePaddings =
+ ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(signaturePaddings));
+ mDigests = ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(digests));
+ mBlockModes = ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(blockModes));
+ mUserAuthenticators = userAuthenticators;
+ mTeeEnforcedUserAuthenticators = teeEnforcedUserAuthenticators;
mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds;
}
@@ -94,14 +88,22 @@ public class KeyStoreKeySpec implements KeySpec {
}
/**
+ * Returns {@code true} if the key is TEE-backed. Key material of TEE-backed keys is available
+ * in plaintext only inside the TEE.
+ */
+ public boolean isTeeBacked() {
+ return mTeeBacked;
+ }
+
+ /**
* Gets the origin of the key.
*/
- public @KeyStoreKeyCharacteristics.OriginEnum int getOrigin() {
+ public @KeyStoreKeyProperties.OriginEnum int getOrigin() {
return mOrigin;
}
/**
- * Gets the key's size in bits.
+ * Gets the size of the key in bits.
*/
public int getKeySize() {
return mKeySize;
@@ -137,90 +139,65 @@ public class KeyStoreKeySpec implements KeySpec {
/**
* Gets the set of purposes for which the key can be used.
*/
- public @KeyStoreKeyConstraints.PurposeEnum int getPurposes() {
+ public @KeyStoreKeyProperties.PurposeEnum int getPurposes() {
return mPurposes;
}
/**
- * Gets the algorithm of the key.
+ * Gets the set of block modes with which the key can be used.
*/
- public @KeyStoreKeyConstraints.AlgorithmEnum int getAlgorithm() {
- return mAlgorithm;
+ public String[] getBlockModes() {
+ return ArrayUtils.cloneIfNotEmpty(mBlockModes);
}
/**
- * Gets the only block mode with which the key can be used.
- *
- * @return block mode or {@code null} if the block mode is not restricted.
+ * Gets the set of padding modes with which the key can be used when encrypting/decrypting.
*/
- public @KeyStoreKeyConstraints.BlockModeEnum Integer getBlockMode() {
- return mBlockMode;
+ public String[] getEncryptionPaddings() {
+ return ArrayUtils.cloneIfNotEmpty(mEncryptionPaddings);
}
/**
- * Gets the only padding mode with which the key can be used.
- *
- * @return padding mode or {@code null} if the padding mode is not restricted.
+ * Gets the set of padding modes with which the key can be used when signing/verifying.
*/
- public @KeyStoreKeyConstraints.PaddingEnum Integer getPadding() {
- return mPadding;
+ public String[] getSignaturePaddings() {
+ return ArrayUtils.cloneIfNotEmpty(mSignaturePaddings);
}
/**
- * Gets the only digest algorithm with which the key can be used.
- *
- * @return digest algorithm or {@code null} if the digest algorithm is not restricted.
- */
- public @KeyStoreKeyConstraints.DigestEnum Integer getDigest() {
- return mDigest;
- }
-
- /**
- * Gets the minimum number of seconds that must expire since the most recent use of the key
- * before it can be used again.
- *
- * @return number of seconds or {@code null} if there is no restriction on how frequently a key
- * can be used.
- */
- public Integer getMinSecondsBetweenOperations() {
- return mMinSecondsBetweenOperations;
- }
-
- /**
- * Gets the number of times the key can be used without rebooting the device.
- *
- * @return maximum number of times or {@code null} if there is no restriction.
+ * Gets the set of digest algorithms with which the key can be used.
*/
- public Integer getMaxUsesPerBoot() {
- return mMaxUsesPerBoot;
+ public String[] getDigests() {
+ return ArrayUtils.cloneIfNotEmpty(mDigests);
}
/**
- * Gets the user authenticators which protect access to the key. The key can only be used iff
- * the user has authenticated to at least one of these user authenticators.
+ * Gets the set of user authenticators which protect access to the key. The key can only be used
+ * iff the user has authenticated to at least one of these user authenticators.
*
- * @return user authenticators or empty set if the key can be used without user authentication.
+ * @return user authenticators or {@code 0} if the key can be used without user authentication.
*/
- public Set<Integer> getUserAuthenticators() {
- return new HashSet<Integer>(mUserAuthenticators);
+ public @KeyStoreKeyProperties.UserAuthenticatorEnum int getUserAuthenticators() {
+ return mUserAuthenticators;
}
/**
- * Gets the TEE-backed user authenticators which protect access to the key. This is a subset of
- * the user authentications returned by {@link #getUserAuthenticators()}.
+ * Gets the set of user authenticators for which the TEE enforces access restrictions for this
+ * key. This is a subset of the user authentications returned by
+ * {@link #getUserAuthenticators()}.
*/
- public Set<Integer> getTeeBackedUserAuthenticators() {
- return new HashSet<Integer>(mTeeBackedUserAuthenticators);
+ public @KeyStoreKeyProperties.UserAuthenticatorEnum int getTeeEnforcedUserAuthenticators() {
+ return mTeeEnforcedUserAuthenticators;
}
/**
* Gets the duration of time (seconds) for which the key can be used after the user
* successfully authenticates to one of the associated user authenticators.
*
- * @return duration in seconds or {@code null} if not restricted. {@code 0} means authentication
+ * @return duration in seconds or {@code -1} if not restricted. {@code 0} means authentication
* is required for every use of the key.
*/
- public Integer getUserAuthenticationValidityDurationSeconds() {
+ public int getUserAuthenticationValidityDurationSeconds() {
return mUserAuthenticationValidityDurationSeconds;
}
}
diff --git a/keystore/java/android/security/KeyStoreParameter.java b/keystore/java/android/security/KeyStoreParameter.java
index 998e1d9..9fce177 100644
--- a/keystore/java/android/security/KeyStoreParameter.java
+++ b/keystore/java/android/security/KeyStoreParameter.java
@@ -18,16 +18,15 @@ package android.security;
import android.content.Context;
-import java.security.KeyPairGenerator;
+import java.security.Key;
import java.security.KeyStore.ProtectionParameter;
-import java.util.Collections;
import java.util.Date;
-import java.util.HashSet;
-import java.util.Set;
+
+import javax.crypto.Cipher;
/**
- * This provides the optional parameters that can be specified for
- * {@code KeyStore} entries that work with
+ * Parameters specifying how to secure and restrict the use of a key being
+ * imported into the
* <a href="{@docRoot}training/articles/keystore.html">Android KeyStore
* facility</a>. The Android KeyStore facility is accessed through a
* {@link java.security.KeyStore} API using the {@code AndroidKeyStore}
@@ -38,43 +37,35 @@ import java.util.Set;
* there is only one logical instance of the {@code KeyStore} per application
* UID so apps using the {@code sharedUid} facility will also share a
* {@code KeyStore}.
- * <p>
- * Keys may be generated using the {@link KeyPairGenerator} facility with a
- * {@link KeyPairGeneratorSpec} to specify the entry's {@code alias}. A
- * self-signed X.509 certificate will be attached to generated entries, but that
- * may be replaced at a later time by a certificate signed by a real Certificate
- * Authority.
*/
public final class KeyStoreParameter implements ProtectionParameter {
private int mFlags;
private final Date mKeyValidityStart;
private final Date mKeyValidityForOriginationEnd;
private final Date mKeyValidityForConsumptionEnd;
- private final @KeyStoreKeyConstraints.PurposeEnum Integer mPurposes;
- private final @KeyStoreKeyConstraints.AlgorithmEnum Integer mAlgorithm;
- private final @KeyStoreKeyConstraints.PaddingEnum Integer mPadding;
- private final @KeyStoreKeyConstraints.DigestEnum Integer mDigest;
- private final @KeyStoreKeyConstraints.BlockModeEnum Integer mBlockMode;
- private final Integer mMinSecondsBetweenOperations;
- private final Integer mMaxUsesPerBoot;
- private final Set<Integer> mUserAuthenticators;
- private final Integer mUserAuthenticationValidityDurationSeconds;
+ private final @KeyStoreKeyProperties.PurposeEnum int mPurposes;
+ private final String[] mEncryptionPaddings;
+ private final String[] mSignaturePaddings;
+ private final String[] mDigests;
+ private final String[] mBlockModes;
+ private final boolean mRandomizedEncryptionRequired;
+ private final @KeyStoreKeyProperties.UserAuthenticatorEnum int mUserAuthenticators;
+ private final int mUserAuthenticationValidityDurationSeconds;
private KeyStoreParameter(int flags,
Date keyValidityStart,
Date keyValidityForOriginationEnd,
Date keyValidityForConsumptionEnd,
- @KeyStoreKeyConstraints.PurposeEnum Integer purposes,
- @KeyStoreKeyConstraints.AlgorithmEnum Integer algorithm,
- @KeyStoreKeyConstraints.PaddingEnum Integer padding,
- @KeyStoreKeyConstraints.DigestEnum Integer digest,
- @KeyStoreKeyConstraints.BlockModeEnum Integer blockMode,
- Integer minSecondsBetweenOperations,
- Integer maxUsesPerBoot,
- Set<Integer> userAuthenticators,
- Integer userAuthenticationValidityDurationSeconds) {
- if ((userAuthenticationValidityDurationSeconds != null)
- && (userAuthenticationValidityDurationSeconds < 0)) {
+ @KeyStoreKeyProperties.PurposeEnum int purposes,
+ String[] encryptionPaddings,
+ String[] signaturePaddings,
+ String[] digests,
+ String[] blockModes,
+ boolean randomizedEncryptionRequired,
+ @KeyStoreKeyProperties.UserAuthenticatorEnum int userAuthenticators,
+ int userAuthenticationValidityDurationSeconds) {
+ if ((userAuthenticationValidityDurationSeconds < 0)
+ && (userAuthenticationValidityDurationSeconds != -1)) {
throw new IllegalArgumentException(
"userAuthenticationValidityDurationSeconds must not be negative");
}
@@ -84,15 +75,14 @@ public final class KeyStoreParameter implements ProtectionParameter {
mKeyValidityForOriginationEnd = keyValidityForOriginationEnd;
mKeyValidityForConsumptionEnd = keyValidityForConsumptionEnd;
mPurposes = purposes;
- mAlgorithm = algorithm;
- mPadding = padding;
- mDigest = digest;
- mBlockMode = blockMode;
- mMinSecondsBetweenOperations = minSecondsBetweenOperations;
- mMaxUsesPerBoot = maxUsesPerBoot;
- mUserAuthenticators = (userAuthenticators != null)
- ? new HashSet<Integer>(userAuthenticators)
- : Collections.<Integer>emptySet();
+ mEncryptionPaddings =
+ ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(encryptionPaddings));
+ mSignaturePaddings =
+ ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(signaturePaddings));
+ mDigests = ArrayUtils.cloneIfNotEmpty(digests);
+ mBlockModes = ArrayUtils.cloneIfNotEmpty(ArrayUtils.nullToEmpty(blockModes));
+ mRandomizedEncryptionRequired = randomizedEncryptionRequired;
+ mUserAuthenticators = userAuthenticators;
mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds;
}
@@ -144,105 +134,107 @@ public final class KeyStoreParameter implements ProtectionParameter {
}
/**
- * Gets the set of purposes for which the key can be used to the provided set of purposes.
- *
- * @return set of purposes or {@code null} if the key can be used for any purpose.
+ * Gets the set of purposes for which the key can be used.
*
* @hide
*/
- public @KeyStoreKeyConstraints.PurposeEnum Integer getPurposes() {
+ public @KeyStoreKeyProperties.PurposeEnum int getPurposes() {
return mPurposes;
}
/**
- * Gets the algorithm to which the key is restricted.
+ * Gets the set of padding schemes with which the key can be used when encrypting/decrypting.
*
- * @return algorithm or {@code null} if it's not restricted.
* @hide
*/
- public @KeyStoreKeyConstraints.AlgorithmEnum Integer getAlgorithm() {
- return mAlgorithm;
+ public String[] getEncryptionPaddings() {
+ return ArrayUtils.cloneIfNotEmpty(mEncryptionPaddings);
}
/**
- * Gets the padding scheme to which the key is restricted.
- *
- * @return padding scheme or {@code null} if the padding scheme is not restricted.
+ * Gets the set of padding schemes with which the key can be used when signing or verifying
+ * signatures.
*
* @hide
*/
- public @KeyStoreKeyConstraints.PaddingEnum Integer getPadding() {
- return mPadding;
+ public String[] getSignaturePaddings() {
+ return ArrayUtils.cloneIfNotEmpty(mSignaturePaddings);
}
/**
- * Gets the digest to which the key is restricted when generating signatures or Message
- * Authentication Codes (MACs).
+ * Gets the set of digest algorithms with which the key can be used.
*
- * @return digest or {@code null} if the digest is not restricted.
+ * @throws IllegalStateException if this set has not been specified.
+ *
+ * @see #isDigestsSpecified()
*
* @hide
*/
- public @KeyStoreKeyConstraints.DigestEnum Integer getDigest() {
- return mDigest;
+ public String[] getDigests() {
+ if (mDigests == null) {
+ throw new IllegalStateException("Digests not specified");
+ }
+ return ArrayUtils.cloneIfNotEmpty(mDigests);
}
/**
- * Gets the block mode to which the key is restricted when used for encryption or decryption.
+ * Returns {@code true} if the set of digest algorithms with which the key can be used has been
+ * specified.
*
- * @return block more or {@code null} if block mode is not restricted.
+ * @see #getDigests()
*
* @hide
*/
- public @KeyStoreKeyConstraints.BlockModeEnum Integer getBlockMode() {
- return mBlockMode;
+ public boolean isDigestsSpecified() {
+ return mDigests != null;
}
/**
- * Gets the minimum number of seconds that must expire since the most recent use of the key
- * before it can be used again.
- *
- * @return number of seconds or {@code null} if there is no restriction on how frequently a key
- * can be used.
+ * Gets the set of block modes with which the key can be used.
*
* @hide
*/
- public Integer getMinSecondsBetweenOperations() {
- return mMinSecondsBetweenOperations;
+ public String[] getBlockModes() {
+ return ArrayUtils.cloneIfNotEmpty(mBlockModes);
}
/**
- * Gets the number of times the key can be used without rebooting the device.
+ * Returns {@code true} if encryption using this key must be sufficiently randomized to produce
+ * different ciphertexts for the same plaintext every time. The formal cryptographic property
+ * being required is <em>indistinguishability under chosen-plaintext attack ({@code
+ * IND-CPA})</em>. This property is important because it mitigates several classes of
+ * weaknesses due to which ciphertext may leak information about plaintext. For example, if a
+ * given plaintext always produces the same ciphertext, an attacker may see the repeated
+ * ciphertexts and be able to deduce something about the plaintext.
*
- * @return maximum number of times or {@code null} if there is no restriction.
* @hide
*/
- public Integer getMaxUsesPerBoot() {
- return mMaxUsesPerBoot;
+ public boolean isRandomizedEncryptionRequired() {
+ return mRandomizedEncryptionRequired;
}
/**
- * Gets the user authenticators which protect access to this key. The key can only be used iff
- * the user has authenticated to at least one of these user authenticators.
+ * Gets the set of user authenticators which protect access to this key. The key can only be
+ * used iff the user has authenticated to at least one of these user authenticators.
*
- * @return user authenticators or empty set if the key can be used without user authentication.
+ * @return user authenticators or {@code 0} if the key can be used without user authentication.
*
* @hide
*/
- public Set<Integer> getUserAuthenticators() {
- return new HashSet<Integer>(mUserAuthenticators);
+ public @KeyStoreKeyProperties.UserAuthenticatorEnum int getUserAuthenticators() {
+ return mUserAuthenticators;
}
/**
* Gets the duration of time (seconds) for which this key can be used after the user
* successfully authenticates to one of the associated user authenticators.
*
- * @return duration in seconds or {@code null} if not restricted. {@code 0} means authentication
+ * @return duration in seconds or {@code -1} if not restricted. {@code 0} means authentication
* is required for every use of the key.
*
* @hide
*/
- public Integer getUserAuthenticationValidityDurationSeconds() {
+ public int getUserAuthenticationValidityDurationSeconds() {
return mUserAuthenticationValidityDurationSeconds;
}
@@ -268,15 +260,14 @@ public final class KeyStoreParameter implements ProtectionParameter {
private Date mKeyValidityStart;
private Date mKeyValidityForOriginationEnd;
private Date mKeyValidityForConsumptionEnd;
- private @KeyStoreKeyConstraints.PurposeEnum Integer mPurposes;
- private @KeyStoreKeyConstraints.AlgorithmEnum Integer mAlgorithm;
- private @KeyStoreKeyConstraints.PaddingEnum Integer mPadding;
- private @KeyStoreKeyConstraints.DigestEnum Integer mDigest;
- private @KeyStoreKeyConstraints.BlockModeEnum Integer mBlockMode;
- private Integer mMinSecondsBetweenOperations;
- private Integer mMaxUsesPerBoot;
- private Set<Integer> mUserAuthenticators;
- private Integer mUserAuthenticationValidityDurationSeconds;
+ private @KeyStoreKeyProperties.PurposeEnum int mPurposes;
+ private String[] mEncryptionPaddings;
+ private String[] mSignaturePaddings;
+ private String[] mDigests;
+ private String[] mBlockModes;
+ private boolean mRandomizedEncryptionRequired = true;
+ private @KeyStoreKeyProperties.UserAuthenticatorEnum int mUserAuthenticators;
+ private int mUserAuthenticationValidityDurationSeconds = -1;
/**
* Creates a new instance of the {@code Builder} with the given
@@ -310,7 +301,7 @@ public final class KeyStoreParameter implements ProtectionParameter {
/**
* Sets the time instant before which the key is not yet valid.
*
- * <b>By default, the key is valid at any instant.
+ * <p>By default, the key is valid at any instant.
*
* @see #setKeyValidityEnd(Date)
*
@@ -324,7 +315,7 @@ public final class KeyStoreParameter implements ProtectionParameter {
/**
* Sets the time instant after which the key is no longer valid.
*
- * <b>By default, the key is valid at any instant.
+ * <p>By default, the key is valid at any instant.
*
* @see #setKeyValidityStart(Date)
* @see #setKeyValidityForConsumptionEnd(Date)
@@ -341,7 +332,7 @@ public final class KeyStoreParameter implements ProtectionParameter {
/**
* Sets the time instant after which the key is no longer valid for encryption and signing.
*
- * <b>By default, the key is valid at any instant.
+ * <p>By default, the key is valid at any instant.
*
* @see #setKeyValidityForConsumptionEnd(Date)
*
@@ -356,7 +347,7 @@ public final class KeyStoreParameter implements ProtectionParameter {
* Sets the time instant after which the key is no longer valid for decryption and
* verification.
*
- * <b>By default, the key is valid at any instant.
+ * <p>By default, the key is valid at any instant.
*
* @see #setKeyValidityForOriginationEnd(Date)
*
@@ -368,96 +359,111 @@ public final class KeyStoreParameter implements ProtectionParameter {
}
/**
- * Restricts the purposes for which the key can be used to the provided set of purposes.
+ * Sets the set of purposes for which the key can be used.
*
- * <p>By default, the key can be used for encryption, decryption, signing, and verification.
+ * <p>This must be specified for all keys. There is no default.
*
* @hide
*/
- public Builder setPurposes(@KeyStoreKeyConstraints.PurposeEnum int purposes) {
+ public Builder setPurposes(@KeyStoreKeyProperties.PurposeEnum int purposes) {
mPurposes = purposes;
return this;
}
/**
- * Sets the algorithm of the key.
+ * Sets the set of padding schemes with which the key can be used when
+ * encrypting/decrypting. Attempts to use the key with any other padding scheme will be
+ * rejected.
*
- * <p>The algorithm of symmetric keys can be deduced from the key itself. Thus, explicitly
- * specifying the algorithm of symmetric keys using this method is not necessary.
+ * <p>This must be specified for keys which are used for encryption/decryption.
*
* @hide
*/
- public Builder setAlgorithm(@KeyStoreKeyConstraints.AlgorithmEnum int algorithm) {
- mAlgorithm = algorithm;
+ public Builder setEncryptionPaddings(String... paddings) {
+ mEncryptionPaddings = ArrayUtils.cloneIfNotEmpty(paddings);
return this;
}
/**
- * Restricts the key to being used only with the provided padding scheme. Attempts to use
- * the key with any other padding will be rejected.
+ * Sets the set of padding schemes with which the key can be used when
+ * signing/verifying. Attempts to use the key with any other padding scheme will be
+ * rejected.
*
- * <p>This restriction must be specified for keys which are used for encryption/decryption.
+ * <p>This must be specified for RSA keys which are used for signing/verification.
*
* @hide
*/
- public Builder setPadding(@KeyStoreKeyConstraints.PaddingEnum int padding) {
- mPadding = padding;
+ public Builder setSignaturePaddings(String... paddings) {
+ mSignaturePaddings = ArrayUtils.cloneIfNotEmpty(paddings);
return this;
}
- /**
- * Restricts the key to being used only with the provided digest when generating signatures
- * or Message Authentication Codes (MACs). Attempts to use the key with any other digest
- * will be rejected.
- *
- * <p>For MAC keys, the default is to restrict to the digest specified in the key algorithm
- * name. For asymmetric signing keys this constraint must be specified because there is no
- * default.
- *
- * @see java.security.Key#getAlgorithm()
- *
- * @hide
- */
- public Builder setDigest(@KeyStoreKeyConstraints.DigestEnum int digest) {
- mDigest = digest;
- return this;
- }
/**
- * Restricts the key to being used only with the provided block mode when encrypting or
- * decrypting. Attempts to use the key with any other block modes will be rejected.
+ * Sets the set of digests with which the key can be used when signing/verifying or
+ * generating MACs. Attempts to use the key with any other digest will be rejected.
*
- * <p>This restriction must be specified for keys which are used for encryption/decryption.
+ * <p>For HMAC keys, the default is the digest specified in {@link Key#getAlgorithm()}. For
+ * asymmetric signing keys this constraint must be specified.
*
* @hide
*/
- public Builder setBlockMode(@KeyStoreKeyConstraints.BlockModeEnum int blockMode) {
- mBlockMode = blockMode;
+ public Builder setDigests(String... digests) {
+ mDigests = ArrayUtils.cloneIfNotEmpty(digests);
return this;
}
/**
- * Sets the minimum number of seconds that must expire since the most recent use of the key
- * before it can be used again.
+ * Sets the set of block modes with which the key can be used when encrypting/decrypting.
+ * Attempts to use the key with any other block modes will be rejected.
*
- * <p>By default, there is no restriction on how frequently a key can be used.
+ * <p>This must be specified for encryption/decryption keys.
*
* @hide
*/
- public Builder setMinSecondsBetweenOperations(int seconds) {
- mMinSecondsBetweenOperations = seconds;
+ public Builder setBlockModes(String... blockModes) {
+ mBlockModes = ArrayUtils.cloneIfNotEmpty(blockModes);
return this;
}
/**
- * Sets the maximum number of times a key can be used without rebooting the device.
- *
- * <p>By default, the key can be used for an unlimited number of times.
+ * Sets whether encryption using this key must be sufficiently randomized to produce
+ * different ciphertexts for the same plaintext every time. The formal cryptographic
+ * property being required is <em>indistinguishability under chosen-plaintext attack
+ * ({@code IND-CPA})</em>. This property is important because it mitigates several classes
+ * of weaknesses due to which ciphertext may leak information about plaintext. For example,
+ * if a given plaintext always produces the same ciphertext, an attacker may see the
+ * repeated ciphertexts and be able to deduce something about the plaintext.
+ *
+ * <p>By default, {@code IND-CPA} is required.
+ *
+ * <p>When {@code IND-CPA} is required:
+ * <ul>
+ * <li>transformation which do not offer {@code IND-CPA}, such as symmetric ciphers using
+ * {@code ECB} mode or RSA encryption without padding, are prohibited;</li>
+ * <li>in transformations which use an IV, such as symmetric ciphers in {@code CBC},
+ * {@code CTR}, and {@code GCM} block modes, caller-provided IVs are rejected when
+ * encrypting, to ensure that only random IVs are used.</li>
+ *
+ * <p>Before disabling this requirement, consider the following approaches instead:
+ * <ul>
+ * <li>If you are generating a random IV for encryption and then initializing a {@code}
+ * Cipher using the IV, the solution is to let the {@code Cipher} generate a random IV
+ * instead. This will occur if the {@code Cipher} is initialized for encryption without an
+ * IV. The IV can then be queried via {@link Cipher#getIV()}.</li>
+ * <li>If you are generating a non-random IV (e.g., an IV derived from something not fully
+ * random, such as the name of the file being encrypted, or transaction ID, or password,
+ * or a device identifier), consider changing your design to use a random IV which will then
+ * be provided in addition to the ciphertext to the entities which need to decrypt the
+ * ciphertext.</li>
+ * <li>If you are using RSA encryption without padding, consider switching to padding
+ * schemes which offer {@code IND-CPA}, such as PKCS#1 or OAEP.</li>
+ * </ul>
*
* @hide
*/
- public Builder setMaxUsesPerBoot(int count) {
- mMaxUsesPerBoot = count;
+ public Builder setRandomizedEncryptionRequired(boolean required) {
+ mRandomizedEncryptionRequired = required;
return this;
}
@@ -467,16 +473,16 @@ public final class KeyStoreParameter implements ProtectionParameter {
*
* <p>By default, the key can be used without user authentication.
*
- * @param userAuthenticators user authenticators or empty list if this key can be accessed
+ * @param userAuthenticators user authenticators or {@code 0} if this key can be accessed
* without user authentication.
*
* @see #setUserAuthenticationValidityDurationSeconds(int)
*
* @hide
*/
- public Builder setUserAuthenticators(Set<Integer> userAuthenticators) {
- mUserAuthenticators =
- (userAuthenticators != null) ? new HashSet<Integer>(userAuthenticators) : null;
+ public Builder setUserAuthenticators(
+ @KeyStoreKeyProperties.UserAuthenticatorEnum int userAuthenticators) {
+ mUserAuthenticators = userAuthenticators;
return this;
}
@@ -489,7 +495,7 @@ public final class KeyStoreParameter implements ProtectionParameter {
* @param seconds duration in seconds or {@code 0} if the user needs to authenticate for
* every use of the key.
*
- * @see #setUserAuthenticators(Set)
+ * @see #setUserAuthenticators(int)
*
* @hide
*/
@@ -510,12 +516,11 @@ public final class KeyStoreParameter implements ProtectionParameter {
mKeyValidityForOriginationEnd,
mKeyValidityForConsumptionEnd,
mPurposes,
- mAlgorithm,
- mPadding,
- mDigest,
- mBlockMode,
- mMinSecondsBetweenOperations,
- mMaxUsesPerBoot,
+ mEncryptionPaddings,
+ mSignaturePaddings,
+ mDigests,
+ mBlockModes,
+ mRandomizedEncryptionRequired,
mUserAuthenticators,
mUserAuthenticationValidityDurationSeconds);
}
diff --git a/keystore/java/android/security/KeyStoreSecretKeyFactorySpi.java b/keystore/java/android/security/KeyStoreSecretKeyFactorySpi.java
index f552759..33073a4 100644
--- a/keystore/java/android/security/KeyStoreSecretKeyFactorySpi.java
+++ b/keystore/java/android/security/KeyStoreSecretKeyFactorySpi.java
@@ -19,11 +19,14 @@ package android.security;
import android.security.keymaster.KeyCharacteristics;
import android.security.keymaster.KeymasterDefs;
+import libcore.util.EmptyArray;
+
import java.security.InvalidKeyException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
+import java.util.ArrayList;
import java.util.Date;
-import java.util.Set;
+import java.util.List;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactorySpi;
@@ -71,94 +74,107 @@ public class KeyStoreSecretKeyFactorySpi extends SecretKeyFactorySpi {
+ " Keystore error: " + errorCode);
}
- @KeyStoreKeyCharacteristics.OriginEnum Integer origin;
+ boolean teeBacked;
+ @KeyStoreKeyProperties.OriginEnum int origin;
int keySize;
- @KeyStoreKeyConstraints.PurposeEnum int purposes;
- @KeyStoreKeyConstraints.AlgorithmEnum int algorithm;
- @KeyStoreKeyConstraints.PaddingEnum Integer padding;
- @KeyStoreKeyConstraints.DigestEnum Integer digest;
- @KeyStoreKeyConstraints.BlockModeEnum Integer blockMode;
+ @KeyStoreKeyProperties.PurposeEnum int purposes;
+ String[] encryptionPaddings;
+ String[] digests;
+ String[] blockModes;
+ @KeyStoreKeyProperties.UserAuthenticatorEnum int userAuthenticators;
+ @KeyStoreKeyProperties.UserAuthenticatorEnum int teeEnforcedUserAuthenticators;
try {
- origin = KeymasterUtils.getInt(keyCharacteristics, KeymasterDefs.KM_TAG_ORIGIN);
- if (origin == null) {
+ if (keyCharacteristics.hwEnforced.containsTag(KeymasterDefs.KM_TAG_ORIGIN)) {
+ teeBacked = true;
+ origin = KeyStoreKeyProperties.Origin.fromKeymaster(
+ keyCharacteristics.hwEnforced.getInt(KeymasterDefs.KM_TAG_ORIGIN, -1));
+ } else if (keyCharacteristics.swEnforced.containsTag(KeymasterDefs.KM_TAG_ORIGIN)) {
+ teeBacked = false;
+ origin = KeyStoreKeyProperties.Origin.fromKeymaster(
+ keyCharacteristics.swEnforced.getInt(KeymasterDefs.KM_TAG_ORIGIN, -1));
+ } else {
throw new InvalidKeySpecException("Key origin not available");
}
- origin = KeyStoreKeyCharacteristics.Origin.fromKeymaster(origin);
- Integer keySizeInteger =
- KeymasterUtils.getInt(keyCharacteristics, KeymasterDefs.KM_TAG_KEY_SIZE);
+ Integer keySizeInteger = keyCharacteristics.getInteger(KeymasterDefs.KM_TAG_KEY_SIZE);
if (keySizeInteger == null) {
throw new InvalidKeySpecException("Key size not available");
}
keySize = keySizeInteger;
- purposes = KeyStoreKeyConstraints.Purpose.allFromKeymaster(
- KeymasterUtils.getInts(keyCharacteristics, KeymasterDefs.KM_TAG_PURPOSE));
- Integer alg = KeymasterUtils.getInt(keyCharacteristics, KeymasterDefs.KM_TAG_ALGORITHM);
- if (alg == null) {
- throw new InvalidKeySpecException("Key algorithm not available");
- }
- algorithm = KeyStoreKeyConstraints.Algorithm.fromKeymaster(alg);
- padding = KeymasterUtils.getInt(keyCharacteristics, KeymasterDefs.KM_TAG_PADDING);
- if (padding != null) {
- padding = KeyStoreKeyConstraints.Padding.fromKeymaster(padding);
- }
- digest = KeymasterUtils.getInt(keyCharacteristics, KeymasterDefs.KM_TAG_DIGEST);
- if (digest != null) {
- digest = KeyStoreKeyConstraints.Digest.fromKeymaster(digest);
- }
- blockMode = KeymasterUtils.getInt(keyCharacteristics, KeymasterDefs.KM_TAG_BLOCK_MODE);
- if (blockMode != null) {
- blockMode = KeyStoreKeyConstraints.BlockMode.fromKeymaster(blockMode);
+ purposes = KeyStoreKeyProperties.Purpose.allFromKeymaster(
+ keyCharacteristics.getInts(KeymasterDefs.KM_TAG_PURPOSE));
+
+ List<String> encryptionPaddingsList = new ArrayList<String>();
+ for (int keymasterPadding : keyCharacteristics.getInts(KeymasterDefs.KM_TAG_PADDING)) {
+ String jcaPadding;
+ try {
+ jcaPadding = KeymasterUtils.getJcaEncryptionPaddingFromKeymasterPadding(
+ keymasterPadding);
+ } catch (IllegalArgumentException e) {
+ throw new InvalidKeySpecException(
+ "Unsupported encryption padding: " + keymasterPadding);
+ }
+ encryptionPaddingsList.add(jcaPadding);
}
+ encryptionPaddings =
+ encryptionPaddingsList.toArray(new String[encryptionPaddingsList.size()]);
+
+ digests = KeymasterUtils.getJcaDigestAlgorithmsFromKeymasterDigests(
+ keyCharacteristics.getInts(KeymasterDefs.KM_TAG_DIGEST));
+ blockModes = KeymasterUtils.getJcaBlockModesFromKeymasterBlockModes(
+ keyCharacteristics.getInts(KeymasterDefs.KM_TAG_BLOCK_MODE));
+
+ @KeyStoreKeyProperties.UserAuthenticatorEnum
+ int swEnforcedKeymasterUserAuthenticators =
+ keyCharacteristics.swEnforced.getInt(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, 0);
+ @KeyStoreKeyProperties.UserAuthenticatorEnum
+ int hwEnforcedKeymasterUserAuthenticators =
+ keyCharacteristics.hwEnforced.getInt(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, 0);
+ @KeyStoreKeyProperties.UserAuthenticatorEnum
+ int keymasterUserAuthenticators =
+ swEnforcedKeymasterUserAuthenticators | hwEnforcedKeymasterUserAuthenticators;
+ userAuthenticators = KeyStoreKeyProperties.UserAuthenticator.allFromKeymaster(
+ keymasterUserAuthenticators);
+ teeEnforcedUserAuthenticators =
+ KeyStoreKeyProperties.UserAuthenticator.allFromKeymaster(
+ hwEnforcedKeymasterUserAuthenticators);
} catch (IllegalArgumentException e) {
throw new InvalidKeySpecException("Unsupported key characteristic", e);
}
- Date keyValidityStart =
- KeymasterUtils.getDate(keyCharacteristics, KeymasterDefs.KM_TAG_ACTIVE_DATETIME);
+ Date keyValidityStart = keyCharacteristics.getDate(KeymasterDefs.KM_TAG_ACTIVE_DATETIME);
if ((keyValidityStart != null) && (keyValidityStart.getTime() <= 0)) {
keyValidityStart = null;
}
- Date keyValidityForOriginationEnd = KeymasterUtils.getDate(keyCharacteristics,
- KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME);
+ Date keyValidityForOriginationEnd =
+ keyCharacteristics.getDate(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME);
if ((keyValidityForOriginationEnd != null)
&& (keyValidityForOriginationEnd.getTime() == Long.MAX_VALUE)) {
keyValidityForOriginationEnd = null;
}
- Date keyValidityForConsumptionEnd = KeymasterUtils.getDate(keyCharacteristics,
- KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME);
+ Date keyValidityForConsumptionEnd =
+ keyCharacteristics.getDate(KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME);
if ((keyValidityForConsumptionEnd != null)
&& (keyValidityForConsumptionEnd.getTime() == Long.MAX_VALUE)) {
keyValidityForConsumptionEnd = null;
}
-
- int swEnforcedUserAuthenticatorIds =
- keyCharacteristics.swEnforced.getInt(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, 0);
- int hwEnforcedUserAuthenticatorIds =
- keyCharacteristics.hwEnforced.getInt(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, 0);
- int userAuthenticatorIds = swEnforcedUserAuthenticatorIds | hwEnforcedUserAuthenticatorIds;
- Set<Integer> userAuthenticators =
- KeyStoreKeyConstraints.UserAuthenticator.allFromKeymaster(userAuthenticatorIds);
- Set<Integer> teeBackedUserAuthenticators =
- KeyStoreKeyConstraints.UserAuthenticator.allFromKeymaster(
- hwEnforcedUserAuthenticatorIds);
+ int userAuthenticationValidityDurationSeconds =
+ keyCharacteristics.getInt(KeymasterDefs.KM_TAG_AUTH_TIMEOUT, -1);
return new KeyStoreKeySpec(entryAlias,
+ teeBacked,
origin,
keySize,
keyValidityStart,
keyValidityForOriginationEnd,
keyValidityForConsumptionEnd,
purposes,
- algorithm,
- padding,
- digest,
- blockMode,
- KeymasterUtils.getInt(keyCharacteristics,
- KeymasterDefs.KM_TAG_MIN_SECONDS_BETWEEN_OPS),
- KeymasterUtils.getInt(keyCharacteristics, KeymasterDefs.KM_TAG_MAX_USES_PER_BOOT),
+ encryptionPaddings,
+ EmptyArray.STRING, // no signature paddings -- this is symmetric crypto
+ digests,
+ blockModes,
userAuthenticators,
- teeBackedUserAuthenticators,
- KeymasterUtils.getInt(keyCharacteristics, KeymasterDefs.KM_TAG_AUTH_TIMEOUT));
+ teeEnforcedUserAuthenticators,
+ userAuthenticationValidityDurationSeconds);
}
@Override
diff --git a/keystore/java/android/security/KeymasterUtils.java b/keystore/java/android/security/KeymasterUtils.java
index 3143d4d..67f75c2 100644
--- a/keystore/java/android/security/KeymasterUtils.java
+++ b/keystore/java/android/security/KeymasterUtils.java
@@ -16,48 +16,327 @@
package android.security;
-import android.security.keymaster.KeyCharacteristics;
+import android.security.keymaster.KeymasterDefs;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
+import libcore.util.EmptyArray;
+
+import java.util.Collection;
+import java.util.Locale;
/**
* @hide
*/
public abstract class KeymasterUtils {
+
private KeymasterUtils() {}
- public static Integer getInt(KeyCharacteristics keyCharacteristics, int tag) {
- if (keyCharacteristics.hwEnforced.containsTag(tag)) {
- return keyCharacteristics.hwEnforced.getInt(tag, -1);
- } else if (keyCharacteristics.swEnforced.containsTag(tag)) {
- return keyCharacteristics.swEnforced.getInt(tag, -1);
+ public static int getKeymasterAlgorithmFromJcaSecretKeyAlgorithm(String jcaKeyAlgorithm) {
+ if ("AES".equalsIgnoreCase(jcaKeyAlgorithm)) {
+ return KeymasterDefs.KM_ALGORITHM_AES;
+ } else if (jcaKeyAlgorithm.toUpperCase(Locale.US).startsWith("HMAC")) {
+ return KeymasterDefs.KM_ALGORITHM_HMAC;
} else {
- return null;
+ throw new IllegalArgumentException(
+ "Unsupported secret key algorithm: " + jcaKeyAlgorithm);
+ }
+ }
+
+ public static String getJcaSecretKeyAlgorithm(int keymasterAlgorithm, int keymasterDigest) {
+ switch (keymasterAlgorithm) {
+ case KeymasterDefs.KM_ALGORITHM_AES:
+ if (keymasterDigest != -1) {
+ throw new IllegalArgumentException(
+ "Digest not supported for AES key: " + keymasterDigest);
+ }
+ return "AES";
+ case KeymasterDefs.KM_ALGORITHM_HMAC:
+ switch (keymasterDigest) {
+ case KeymasterDefs.KM_DIGEST_SHA1:
+ return "HmacSHA1";
+ case KeymasterDefs.KM_DIGEST_SHA_2_224:
+ return "HmacSHA224";
+ case KeymasterDefs.KM_DIGEST_SHA_2_256:
+ return "HmacSHA256";
+ case KeymasterDefs.KM_DIGEST_SHA_2_384:
+ return "HmacSHA384";
+ case KeymasterDefs.KM_DIGEST_SHA_2_512:
+ return "HmacSHA512";
+ default:
+ throw new IllegalArgumentException(
+ "Unsupported HMAC digest: " + keymasterDigest);
+ }
+ default:
+ throw new IllegalArgumentException("Unsupported algorithm: " + keymasterAlgorithm);
}
}
- public static List<Integer> getInts(KeyCharacteristics keyCharacteristics, int tag) {
- List<Integer> result = new ArrayList<Integer>();
- result.addAll(keyCharacteristics.hwEnforced.getInts(tag));
- result.addAll(keyCharacteristics.swEnforced.getInts(tag));
+ public static String getJcaKeyPairAlgorithmFromKeymasterAlgorithm(int keymasterAlgorithm) {
+ switch (keymasterAlgorithm) {
+ case KeymasterDefs.KM_ALGORITHM_RSA:
+ return "RSA";
+ case KeymasterDefs.KM_ALGORITHM_EC:
+ return "EC";
+ default:
+ throw new IllegalArgumentException("Unsupported algorithm: " + keymasterAlgorithm);
+ }
+ }
+
+ public static int getKeymasterDigestfromJcaSecretKeyAlgorithm(String jcaKeyAlgorithm) {
+ String algorithmUpper = jcaKeyAlgorithm.toUpperCase(Locale.US);
+ if (algorithmUpper.startsWith("HMAC")) {
+ String digestUpper = algorithmUpper.substring("HMAC".length());
+ switch (digestUpper) {
+ case "MD5":
+ return KeymasterDefs.KM_DIGEST_MD5;
+ case "SHA1":
+ return KeymasterDefs.KM_DIGEST_SHA1;
+ case "SHA224":
+ return KeymasterDefs.KM_DIGEST_SHA_2_224;
+ case "SHA256":
+ return KeymasterDefs.KM_DIGEST_SHA_2_256;
+ case "SHA384":
+ return KeymasterDefs.KM_DIGEST_SHA_2_384;
+ case "SHA512":
+ return KeymasterDefs.KM_DIGEST_SHA_2_512;
+ default:
+ throw new IllegalArgumentException("Unsupported HMAC digest: " + digestUpper);
+ }
+ } else {
+ return -1;
+ }
+ }
+
+ public static int getKeymasterDigestFromJcaDigestAlgorithm(String jcaDigestAlgorithm) {
+ if (jcaDigestAlgorithm.equalsIgnoreCase("SHA-1")) {
+ return KeymasterDefs.KM_DIGEST_SHA1;
+ } else if (jcaDigestAlgorithm.equalsIgnoreCase("SHA-224")) {
+ return KeymasterDefs.KM_DIGEST_SHA_2_224;
+ } else if (jcaDigestAlgorithm.equalsIgnoreCase("SHA-256")) {
+ return KeymasterDefs.KM_DIGEST_SHA_2_256;
+ } else if (jcaDigestAlgorithm.equalsIgnoreCase("SHA-384")) {
+ return KeymasterDefs.KM_DIGEST_SHA_2_384;
+ } else if (jcaDigestAlgorithm.equalsIgnoreCase("SHA-512")) {
+ return KeymasterDefs.KM_DIGEST_SHA_2_512;
+ } else if (jcaDigestAlgorithm.equalsIgnoreCase("NONE")) {
+ return KeymasterDefs.KM_DIGEST_NONE;
+ } else if (jcaDigestAlgorithm.equalsIgnoreCase("MD5")) {
+ return KeymasterDefs.KM_DIGEST_MD5;
+ } else {
+ throw new IllegalArgumentException(
+ "Unsupported digest algorithm: " + jcaDigestAlgorithm);
+ }
+ }
+
+ public static String getJcaDigestAlgorithmFromKeymasterDigest(int keymasterDigest) {
+ switch (keymasterDigest) {
+ case KeymasterDefs.KM_DIGEST_NONE:
+ return "NONE";
+ case KeymasterDefs.KM_DIGEST_MD5:
+ return "MD5";
+ case KeymasterDefs.KM_DIGEST_SHA1:
+ return "SHA-1";
+ case KeymasterDefs.KM_DIGEST_SHA_2_224:
+ return "SHA-224";
+ case KeymasterDefs.KM_DIGEST_SHA_2_256:
+ return "SHA-256";
+ case KeymasterDefs.KM_DIGEST_SHA_2_384:
+ return "SHA-384";
+ case KeymasterDefs.KM_DIGEST_SHA_2_512:
+ return "SHA-512";
+ default:
+ throw new IllegalArgumentException(
+ "Unsupported digest algorithm: " + keymasterDigest);
+ }
+ }
+
+ public static String[] getJcaDigestAlgorithmsFromKeymasterDigests(
+ Collection<Integer> keymasterDigests) {
+ if (keymasterDigests.isEmpty()) {
+ return EmptyArray.STRING;
+ }
+ String[] result = new String[keymasterDigests.size()];
+ int offset = 0;
+ for (int keymasterDigest : keymasterDigests) {
+ result[offset] = getJcaDigestAlgorithmFromKeymasterDigest(keymasterDigest);
+ offset++;
+ }
return result;
}
- public static Date getDate(KeyCharacteristics keyCharacteristics, int tag) {
- Date result = keyCharacteristics.hwEnforced.getDate(tag, null);
- if (result == null) {
- result = keyCharacteristics.swEnforced.getDate(tag, null);
+ public static int[] getKeymasterDigestsFromJcaDigestAlgorithms(String[] jcaDigestAlgorithms) {
+ if ((jcaDigestAlgorithms == null) || (jcaDigestAlgorithms.length == 0)) {
+ return EmptyArray.INT;
+ }
+ int[] result = new int[jcaDigestAlgorithms.length];
+ int offset = 0;
+ for (String jcaDigestAlgorithm : jcaDigestAlgorithms) {
+ result[offset] = getKeymasterDigestFromJcaDigestAlgorithm(jcaDigestAlgorithm);
+ offset++;
}
return result;
}
- public static boolean getBoolean(KeyCharacteristics keyCharacteristics, int tag) {
- if (keyCharacteristics.hwEnforced.containsTag(tag)) {
- return keyCharacteristics.hwEnforced.getBoolean(tag, false);
+ public static int getDigestOutputSizeBytes(int keymasterDigest) {
+ switch (keymasterDigest) {
+ case KeymasterDefs.KM_DIGEST_NONE:
+ return -1;
+ case KeymasterDefs.KM_DIGEST_MD5:
+ return 128 / 8;
+ case KeymasterDefs.KM_DIGEST_SHA1:
+ return 160 / 8;
+ case KeymasterDefs.KM_DIGEST_SHA_2_224:
+ return 224 / 8;
+ case KeymasterDefs.KM_DIGEST_SHA_2_256:
+ return 256 / 8;
+ case KeymasterDefs.KM_DIGEST_SHA_2_384:
+ return 384 / 8;
+ case KeymasterDefs.KM_DIGEST_SHA_2_512:
+ return 512 / 8;
+ default:
+ throw new IllegalArgumentException("Unknown digest: " + keymasterDigest);
+ }
+ }
+
+ public static int getKeymasterBlockModeFromJcaBlockMode(String jcaBlockMode) {
+ if ("ECB".equalsIgnoreCase(jcaBlockMode)) {
+ return KeymasterDefs.KM_MODE_ECB;
+ } else if ("CBC".equalsIgnoreCase(jcaBlockMode)) {
+ return KeymasterDefs.KM_MODE_CBC;
+ } else if ("CTR".equalsIgnoreCase(jcaBlockMode)) {
+ return KeymasterDefs.KM_MODE_CTR;
+ } else if ("GCM".equalsIgnoreCase(jcaBlockMode)) {
+ return KeymasterDefs.KM_MODE_GCM;
} else {
- return keyCharacteristics.swEnforced.getBoolean(tag, false);
+ throw new IllegalArgumentException("Unsupported block mode: " + jcaBlockMode);
}
}
+
+ public static String getJcaBlockModeFromKeymasterBlockMode(int keymasterBlockMode) {
+ switch (keymasterBlockMode) {
+ case KeymasterDefs.KM_MODE_ECB:
+ return "ECB";
+ case KeymasterDefs.KM_MODE_CBC:
+ return "CBC";
+ case KeymasterDefs.KM_MODE_CTR:
+ return "CTR";
+ case KeymasterDefs.KM_MODE_GCM:
+ return "GCM";
+ default:
+ throw new IllegalArgumentException("Unsupported block mode: " + keymasterBlockMode);
+ }
+ }
+
+ public static String[] getJcaBlockModesFromKeymasterBlockModes(
+ Collection<Integer> keymasterBlockModes) {
+ if ((keymasterBlockModes == null) || (keymasterBlockModes.isEmpty())) {
+ return EmptyArray.STRING;
+ }
+ String[] result = new String[keymasterBlockModes.size()];
+ int offset = 0;
+ for (int keymasterBlockMode : keymasterBlockModes) {
+ result[offset] = getJcaBlockModeFromKeymasterBlockMode(keymasterBlockMode);
+ offset++;
+ }
+ return result;
+ }
+
+ public static int[] getKeymasterBlockModesFromJcaBlockModes(String[] jcaBlockModes) {
+ if ((jcaBlockModes == null) || (jcaBlockModes.length == 0)) {
+ return EmptyArray.INT;
+ }
+ int[] result = new int[jcaBlockModes.length];
+ for (int i = 0; i < jcaBlockModes.length; i++) {
+ result[i] = getKeymasterBlockModeFromJcaBlockMode(jcaBlockModes[i]);
+ }
+ return result;
+ }
+
+ public static boolean isKeymasterBlockModeIndCpaCompatible(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 int getKeymasterPaddingFromJcaEncryptionPadding(String jcaPadding) {
+ if ("NoPadding".equalsIgnoreCase(jcaPadding)) {
+ return KeymasterDefs.KM_PAD_NONE;
+ } else if ("PKCS7Padding".equalsIgnoreCase(jcaPadding)) {
+ return KeymasterDefs.KM_PAD_PKCS7;
+ } else if ("PKCS1Padding".equalsIgnoreCase(jcaPadding)) {
+ return KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_ENCRYPT;
+ } else if ("OEAPPadding".equalsIgnoreCase(jcaPadding)) {
+ return KeymasterDefs.KM_PAD_RSA_OAEP;
+ } else {
+ throw new IllegalArgumentException(
+ "Unsupported encryption padding scheme: " + jcaPadding);
+ }
+ }
+
+ public static String getJcaEncryptionPaddingFromKeymasterPadding(int keymasterPadding) {
+ switch (keymasterPadding) {
+ case KeymasterDefs.KM_PAD_NONE:
+ return "NoPadding";
+ case KeymasterDefs.KM_PAD_PKCS7:
+ return "PKCS7Padding";
+ case KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_ENCRYPT:
+ return "PKCS1Padding";
+ case KeymasterDefs.KM_PAD_RSA_OAEP:
+ return "OEAPPadding";
+ default:
+ throw new IllegalArgumentException(
+ "Unsupported encryption padding: " + keymasterPadding);
+ }
+ }
+
+ public static int getKeymasterPaddingFromJcaSignaturePadding(String jcaPadding) {
+ if ("PKCS#1".equalsIgnoreCase(jcaPadding)) {
+ return KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_SIGN;
+ } if ("PSS".equalsIgnoreCase(jcaPadding)) {
+ return KeymasterDefs.KM_PAD_RSA_PSS;
+ } else {
+ throw new IllegalArgumentException(
+ "Unsupported signature padding scheme: " + jcaPadding);
+ }
+ }
+
+ public static String getJcaSignaturePaddingFromKeymasterPadding(int keymasterPadding) {
+ switch (keymasterPadding) {
+ case KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_SIGN:
+ return "PKCS#1";
+ case KeymasterDefs.KM_PAD_RSA_PSS:
+ return "PSS";
+ default:
+ throw new IllegalArgumentException(
+ "Unsupported signature padding: " + keymasterPadding);
+ }
+ }
+
+ public static int[] getKeymasterPaddingsFromJcaEncryptionPaddings(String[] jcaPaddings) {
+ if ((jcaPaddings == null) || (jcaPaddings.length == 0)) {
+ return EmptyArray.INT;
+ }
+ int[] result = new int[jcaPaddings.length];
+ for (int i = 0; i < jcaPaddings.length; i++) {
+ result[i] = getKeymasterPaddingFromJcaEncryptionPadding(jcaPaddings[i]);
+ }
+ return result;
+ }
+
+ public static int[] getKeymasterPaddingsFromJcaSignaturePaddings(String[] jcaPaddings) {
+ if ((jcaPaddings == null) || (jcaPaddings.length == 0)) {
+ return EmptyArray.INT;
+ }
+ int[] result = new int[jcaPaddings.length];
+ for (int i = 0; i < jcaPaddings.length; i++) {
+ result[i] = getKeymasterPaddingFromJcaSignaturePadding(jcaPaddings[i]);
+ }
+ return result;
+ }
}
diff --git a/keystore/tests/src/android/security/KeyPairGeneratorSpecTest.java b/keystore/tests/src/android/security/KeyPairGeneratorSpecTest.java
index bc8dd13..681a9ff 100644
--- a/keystore/tests/src/android/security/KeyPairGeneratorSpecTest.java
+++ b/keystore/tests/src/android/security/KeyPairGeneratorSpecTest.java
@@ -24,6 +24,11 @@ import java.util.Date;
import javax.security.auth.x500.X500Principal;
public class KeyPairGeneratorSpecTest extends AndroidTestCase {
+ private static final X500Principal DEFAULT_CERT_SUBJECT = new X500Principal("CN=fake");
+ private static final BigInteger DEFAULT_CERT_SERIAL_NUMBER = new BigInteger("1");
+ private static final Date DEFAULT_CERT_NOT_BEFORE = new Date(0L); // Jan 1 1980
+ private static final Date DEFAULT_CERT_NOT_AFTER = new Date(2461449600000L); // Jan 1 2048
+
private static final String TEST_ALIAS_1 = "test1";
private static final X500Principal TEST_DN_1 = new X500Principal("CN=test1");
@@ -105,46 +110,37 @@ public class KeyPairGeneratorSpecTest extends AndroidTestCase {
}
}
- public void testConstructor_NullSubjectDN_Failure() throws Exception {
- try {
- new KeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, "RSA", 1024, null, null, SERIAL_1, NOW,
- NOW_PLUS_10_YEARS, 0);
- fail("Should throw IllegalArgumentException when subjectDN is null");
- } catch (IllegalArgumentException success) {
- }
+ public void testConstructor_NullSubjectDN_Success() throws Exception {
+ KeyPairGeneratorSpec spec = new KeyPairGeneratorSpec(
+ getContext(), TEST_ALIAS_1, "RSA", 1024, null, null, SERIAL_1, NOW,
+ NOW_PLUS_10_YEARS, 0);
+ assertEquals(DEFAULT_CERT_SUBJECT, spec.getSubjectDN());
}
- public void testConstructor_NullSerial_Failure() throws Exception {
- try {
- new KeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, "RSA", 1024, null, TEST_DN_1, null, NOW,
- NOW_PLUS_10_YEARS, 0);
- fail("Should throw IllegalArgumentException when startDate is null");
- } catch (IllegalArgumentException success) {
- }
+ public void testConstructor_NullSerial_Success() throws Exception {
+ KeyPairGeneratorSpec spec = new KeyPairGeneratorSpec(
+ getContext(), TEST_ALIAS_1, "RSA", 1024, null, TEST_DN_1, null, NOW,
+ NOW_PLUS_10_YEARS, 0);
+ assertEquals(DEFAULT_CERT_SERIAL_NUMBER, spec.getSerialNumber());
}
- public void testConstructor_NullStartDate_Failure() throws Exception {
- try {
- new KeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, "RSA", 1024, null, TEST_DN_1, SERIAL_1,
- null, NOW_PLUS_10_YEARS, 0);
- fail("Should throw IllegalArgumentException when startDate is null");
- } catch (IllegalArgumentException success) {
- }
+ public void testConstructor_NullStartDate_Success() throws Exception {
+ KeyPairGeneratorSpec spec = new KeyPairGeneratorSpec(
+ getContext(), TEST_ALIAS_1, "RSA", 1024, null, TEST_DN_1, SERIAL_1, null,
+ NOW_PLUS_10_YEARS, 0);
+ assertEquals(DEFAULT_CERT_NOT_BEFORE, spec.getStartDate());
}
- public void testConstructor_NullEndDate_Failure() throws Exception {
- try {
- new KeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, "RSA", 1024, null, TEST_DN_1, SERIAL_1,
- NOW, null, 0);
- fail("Should throw IllegalArgumentException when keystoreAlias is null");
- } catch (IllegalArgumentException success) {
- }
+ public void testConstructor_NullEndDate_Success() throws Exception {
+ KeyPairGeneratorSpec spec = new KeyPairGeneratorSpec(
+ getContext(), TEST_ALIAS_1, "RSA", 1024, null, TEST_DN_1, SERIAL_1, NOW, null, 0);
+ assertEquals(DEFAULT_CERT_NOT_AFTER, spec.getEndDate());
}
public void testConstructor_EndBeforeStart_Failure() throws Exception {
try {
- new KeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, "RSA", 1024, null, TEST_DN_1, SERIAL_1,
- NOW_PLUS_10_YEARS, NOW, 0);
+ new KeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, "RSA", 1024, null, TEST_DN_1,
+ SERIAL_1, NOW_PLUS_10_YEARS, NOW, 0);
fail("Should throw IllegalArgumentException when end is before start");
} catch (IllegalArgumentException success) {
}
diff --git a/keystore/tests/src/android/security/KeyStoreTest.java b/keystore/tests/src/android/security/KeyStoreTest.java
index c9a140c..1a5552a 100644
--- a/keystore/tests/src/android/security/KeyStoreTest.java
+++ b/keystore/tests/src/android/security/KeyStoreTest.java
@@ -294,14 +294,14 @@ public class KeyStoreTest extends ActivityUnitTestCase<Activity> {
public void testSaw_ungrantedUid_Bluetooth() throws Exception {
String[] results1 = mKeyStore.saw(TEST_KEYNAME, Process.BLUETOOTH_UID);
- assertNull(results1);
+ assertEquals(0, results1.length);
mKeyStore.password(TEST_PASSWD);
mKeyStore.put(TEST_KEYNAME1, TEST_KEYVALUE, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED);
mKeyStore.put(TEST_KEYNAME2, TEST_KEYVALUE, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED);
String[] results2 = mKeyStore.saw(TEST_KEYNAME, Process.BLUETOOTH_UID);
- assertNull(results2);
+ assertEquals(0, results2.length);
}
public void testSaw_grantedUid_Wifi() throws Exception {
@@ -798,7 +798,7 @@ public class KeyStoreTest extends ActivityUnitTestCase<Activity> {
// TODO: Verify we have an RSA public key that's well formed.
}
- public void testAesOcbEncryptSuccess() throws Exception {
+ public void testAesGcmEncryptSuccess() throws Exception {
String name = "test";
KeymasterArguments args = new KeymasterArguments();
args.addInt(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_ENCRYPT);
@@ -806,7 +806,7 @@ public class KeyStoreTest extends ActivityUnitTestCase<Activity> {
args.addInt(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_AES);
args.addInt(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_NONE);
args.addInt(KeymasterDefs.KM_TAG_KEY_SIZE, 256);
- args.addInt(KeymasterDefs.KM_TAG_BLOCK_MODE, KeymasterDefs.KM_MODE_OCB);
+ args.addInt(KeymasterDefs.KM_TAG_BLOCK_MODE, KeymasterDefs.KM_MODE_GCM);
args.addInt(KeymasterDefs.KM_TAG_CHUNK_LENGTH, 4096);
args.addInt(KeymasterDefs.KM_TAG_MAC_LENGTH, 16);
args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
@@ -903,9 +903,7 @@ public class KeyStoreTest extends ActivityUnitTestCase<Activity> {
args.addInt(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_AES);
args.addInt(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_NONE);
args.addInt(KeymasterDefs.KM_TAG_KEY_SIZE, 256);
- args.addInt(KeymasterDefs.KM_TAG_BLOCK_MODE, KeymasterDefs.KM_MODE_OCB);
- args.addInt(KeymasterDefs.KM_TAG_CHUNK_LENGTH, 4096);
- args.addInt(KeymasterDefs.KM_TAG_MAC_LENGTH, 16);
+ args.addInt(KeymasterDefs.KM_TAG_BLOCK_MODE, KeymasterDefs.KM_MODE_CTR);
args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
KeyCharacteristics outCharacteristics = new KeyCharacteristics();
@@ -935,11 +933,9 @@ public class KeyStoreTest extends ActivityUnitTestCase<Activity> {
args.addInt(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_ENCRYPT);
args.addInt(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_DECRYPT);
args.addInt(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_AES);
- args.addInt(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_NONE);
+ args.addInt(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_PKCS7);
args.addInt(KeymasterDefs.KM_TAG_KEY_SIZE, 256);
- args.addInt(KeymasterDefs.KM_TAG_BLOCK_MODE, KeymasterDefs.KM_MODE_OCB);
- args.addInt(KeymasterDefs.KM_TAG_CHUNK_LENGTH, 4096);
- args.addInt(KeymasterDefs.KM_TAG_MAC_LENGTH, 16);
+ args.addInt(KeymasterDefs.KM_TAG_BLOCK_MODE, KeymasterDefs.KM_MODE_ECB);
args.addInt(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, 1);
KeyCharacteristics outCharacteristics = new KeyCharacteristics();
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index 5b5b098..c1b50c1 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -183,6 +183,8 @@ void FontRenderer::flushAllAndInvalidate() {
for (uint32_t i = 0; i < mRGBACacheTextures.size(); i++) {
mRGBACacheTextures[i]->init();
}
+
+ mDrawn = false;
}
void FontRenderer::flushLargeCaches(Vector<CacheTexture*>& cacheTextures) {
diff --git a/libs/hwui/RenderBufferCache.cpp b/libs/hwui/RenderBufferCache.cpp
index 830a13a..022820b 100644
--- a/libs/hwui/RenderBufferCache.cpp
+++ b/libs/hwui/RenderBufferCache.cpp
@@ -158,6 +158,11 @@ bool RenderBufferCache::put(RenderBuffer* buffer) {
buffer->getWidth(), buffer->getHeight());
return true;
+ } else {
+ RENDER_BUFFER_LOGD("Deleted %s render buffer (%dx%d) Size=%d, MaxSize=%d",
+ RenderBuffer::formatName(buffer->getFormat()),
+ buffer->getWidth(), buffer->getHeight(), size, mMaxSize);
+ delete buffer;
}
return false;
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index e66934e..fae0643 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -773,6 +773,11 @@ public class KeyguardViewMediator extends SystemUI {
synchronized (this) {
if (DEBUG) Log.d(TAG, "setKeyguardEnabled(" + enabled + ")");
+ if (isSecure()) {
+ Log.d(TAG, "current mode is SecurityMode, ignore hide keyguard");
+ return;
+ }
+
mExternallyEnabled = enabled;
if (!enabled && mShowing) {
diff --git a/rs/java/android/renderscript/FieldPacker.java b/rs/java/android/renderscript/FieldPacker.java
index 0f967fc..de1c497 100644
--- a/rs/java/android/renderscript/FieldPacker.java
+++ b/rs/java/android/renderscript/FieldPacker.java
@@ -47,6 +47,15 @@ public class FieldPacker {
// subAlign() can never work correctly for copied FieldPacker objects.
}
+ static FieldPacker createFromArray(Object[] args) {
+ FieldPacker fp = new FieldPacker(RenderScript.sPointerSize * 8);
+ for (Object arg : args) {
+ fp.addSafely(arg);
+ }
+ fp.resize(fp.mPos);
+ return fp;
+ }
+
public void align(int v) {
if ((v <= 0) || ((v & (v - 1)) != 0)) {
throw new RSIllegalArgumentException("argument must be a non-negative non-zero power of 2: " + v);
@@ -618,294 +627,182 @@ public class FieldPacker {
return mPos;
}
- private static void addToPack(FieldPacker fp, Object obj) {
+ private void add(Object obj) {
if (obj instanceof Boolean) {
- fp.addBoolean(((Boolean)obj).booleanValue());
+ addBoolean((Boolean)obj);
return;
}
if (obj instanceof Byte) {
- fp.addI8(((Byte)obj).byteValue());
+ addI8((Byte)obj);
return;
}
if (obj instanceof Short) {
- fp.addI16(((Short)obj).shortValue());
+ addI16((Short)obj);
return;
}
if (obj instanceof Integer) {
- fp.addI32(((Integer)obj).intValue());
+ addI32((Integer)obj);
return;
}
if (obj instanceof Long) {
- fp.addI64(((Long)obj).longValue());
+ addI64((Long)obj);
return;
}
if (obj instanceof Float) {
- fp.addF32(((Float)obj).floatValue());
+ addF32((Float)obj);
return;
}
if (obj instanceof Double) {
- fp.addF64(((Double)obj).doubleValue());
+ addF64((Double)obj);
return;
}
if (obj instanceof Byte2) {
- fp.addI8((Byte2)obj);
+ addI8((Byte2)obj);
return;
}
if (obj instanceof Byte3) {
- fp.addI8((Byte3)obj);
+ addI8((Byte3)obj);
return;
}
if (obj instanceof Byte4) {
- fp.addI8((Byte4)obj);
+ addI8((Byte4)obj);
return;
}
if (obj instanceof Short2) {
- fp.addI16((Short2)obj);
+ addI16((Short2)obj);
return;
}
if (obj instanceof Short3) {
- fp.addI16((Short3)obj);
+ addI16((Short3)obj);
return;
}
if (obj instanceof Short4) {
- fp.addI16((Short4)obj);
+ addI16((Short4)obj);
return;
}
if (obj instanceof Int2) {
- fp.addI32((Int2)obj);
+ addI32((Int2)obj);
return;
}
if (obj instanceof Int3) {
- fp.addI32((Int3)obj);
+ addI32((Int3)obj);
return;
}
if (obj instanceof Int4) {
- fp.addI32((Int4)obj);
+ addI32((Int4)obj);
return;
}
if (obj instanceof Long2) {
- fp.addI64((Long2)obj);
+ addI64((Long2)obj);
return;
}
if (obj instanceof Long3) {
- fp.addI64((Long3)obj);
+ addI64((Long3)obj);
return;
}
if (obj instanceof Long4) {
- fp.addI64((Long4)obj);
+ addI64((Long4)obj);
return;
}
if (obj instanceof Float2) {
- fp.addF32((Float2)obj);
+ addF32((Float2)obj);
return;
}
if (obj instanceof Float3) {
- fp.addF32((Float3)obj);
+ addF32((Float3)obj);
return;
}
if (obj instanceof Float4) {
- fp.addF32((Float4)obj);
+ addF32((Float4)obj);
return;
}
if (obj instanceof Double2) {
- fp.addF64((Double2)obj);
+ addF64((Double2)obj);
return;
}
if (obj instanceof Double3) {
- fp.addF64((Double3)obj);
+ addF64((Double3)obj);
return;
}
if (obj instanceof Double4) {
- fp.addF64((Double4)obj);
+ addF64((Double4)obj);
return;
}
if (obj instanceof Matrix2f) {
- fp.addMatrix((Matrix2f)obj);
+ addMatrix((Matrix2f)obj);
return;
}
if (obj instanceof Matrix3f) {
- fp.addMatrix((Matrix3f)obj);
+ addMatrix((Matrix3f)obj);
return;
}
if (obj instanceof Matrix4f) {
- fp.addMatrix((Matrix4f)obj);
+ addMatrix((Matrix4f)obj);
return;
}
if (obj instanceof BaseObj) {
- fp.addObj((BaseObj)obj);
+ addObj((BaseObj)obj);
return;
}
}
- private static int getPackedSize(Object obj) {
- if (obj instanceof Boolean) {
- return 1;
- }
-
- if (obj instanceof Byte) {
- return 1;
- }
-
- if (obj instanceof Short) {
- return 2;
- }
-
- if (obj instanceof Integer) {
- return 4;
- }
-
- if (obj instanceof Long) {
- return 8;
- }
-
- if (obj instanceof Float) {
- return 4;
- }
-
- if (obj instanceof Double) {
- return 8;
- }
-
- if (obj instanceof Byte2) {
- return 2;
- }
-
- if (obj instanceof Byte3) {
- return 3;
- }
-
- if (obj instanceof Byte4) {
- return 4;
- }
-
- if (obj instanceof Short2) {
- return 4;
- }
-
- if (obj instanceof Short3) {
- return 6;
- }
-
- if (obj instanceof Short4) {
- return 8;
- }
-
- if (obj instanceof Int2) {
- return 8;
- }
-
- if (obj instanceof Int3) {
- return 12;
- }
-
- if (obj instanceof Int4) {
- return 16;
- }
-
- if (obj instanceof Long2) {
- return 16;
- }
-
- if (obj instanceof Long3) {
- return 24;
- }
-
- if (obj instanceof Long4) {
- return 32;
- }
-
- if (obj instanceof Float2) {
- return 8;
- }
-
- if (obj instanceof Float3) {
- return 12;
+ private boolean resize(int newSize) {
+ if (newSize == mLen) {
+ return false;
}
- if (obj instanceof Float4) {
- return 16;
- }
-
- if (obj instanceof Double2) {
- return 16;
- }
-
- if (obj instanceof Double3) {
- return 24;
- }
-
- if (obj instanceof Double4) {
- return 32;
- }
-
- if (obj instanceof Matrix2f) {
- return 16;
- }
-
- if (obj instanceof Matrix3f) {
- return 36;
- }
-
- if (obj instanceof Matrix4f) {
- return 64;
- }
-
- if (obj instanceof BaseObj) {
- if (RenderScript.sPointerSize == 8) {
- return 32;
- } else {
- return 4;
- }
- }
-
- return 0;
+ byte[] newData = new byte[newSize];
+ System.arraycopy(mData, 0, newData, 0, mPos);
+ mData = newData;
+ mLen = newSize;
+ return true;
}
- static FieldPacker createFieldPack(Object[] args) {
- int len = 0;
- for (Object arg : args) {
- len += getPackedSize(arg);
- }
- FieldPacker fp = new FieldPacker(len);
- for (Object arg : args) {
- addToPack(fp, arg);
- }
- return fp;
+ private void addSafely(Object obj) {
+ boolean retry;
+ final int oldPos = mPos;
+ do {
+ retry = false;
+ try {
+ add(obj);
+ } catch (ArrayIndexOutOfBoundsException e) {
+ mPos = oldPos;
+ resize(mLen * 2);
+ retry = true;
+ }
+ } while (retry);
}
- private final byte mData[];
+ private byte mData[];
private int mPos;
private int mLen;
private BitSet mAlignment;
-
}
-
-
diff --git a/rs/java/android/renderscript/RenderScript.java b/rs/java/android/renderscript/RenderScript.java
index 45f0ca6..9f3348c 100644
--- a/rs/java/android/renderscript/RenderScript.java
+++ b/rs/java/android/renderscript/RenderScript.java
@@ -130,8 +130,6 @@ public class RenderScript {
native void nContextInitToClient(long con);
native void nContextDeinitToClient(long con);
- static File mCacheDir;
-
// this should be a monotonically increasing ID
// used in conjunction with the API version of a device
static final long sMinorID = 1;
@@ -146,23 +144,6 @@ public class RenderScript {
return sMinorID;
}
- /**
- * Sets the directory to use as a persistent storage for the
- * renderscript object file cache.
- *
- * @hide
- * @param cacheDir A directory the current process can write to
- */
- public static void setupDiskCache(File cacheDir) {
- if (!sInitialized) {
- Log.e(LOG_TAG, "RenderScript.setupDiskCache() called when disabled");
- return;
- }
-
- // Defer creation of cache path to nScriptCCreate().
- mCacheDir = cacheDir;
- }
-
/**
* ContextType specifies the specific type of context to be created.
*
@@ -251,6 +232,11 @@ public class RenderScript {
validate();
rsnContextSetPriority(mContext, p);
}
+ native void rsnContextSetCacheDir(long con, String cacheDir);
+ synchronized void nContextSetCacheDir(String cacheDir) {
+ validate();
+ rsnContextSetCacheDir(mContext, cacheDir);
+ }
native void rsnContextDump(long con, int bits);
synchronized void nContextDump(int bits) {
validate();
@@ -346,10 +332,12 @@ public class RenderScript {
rsnClosureSetGlobal(mContext, closureID, fieldID, value, size);
}
- native long rsnScriptGroup2Create(long con, String cachePath, long[] closures);
- synchronized long nScriptGroup2Create(String cachePath, long[] closures) {
+ native long rsnScriptGroup2Create(long con, String name, String cachePath,
+ long[] closures);
+ synchronized long nScriptGroup2Create(String name, String cachePath,
+ long[] closures) {
validate();
- return rsnScriptGroup2Create(mContext, cachePath, closures);
+ return rsnScriptGroup2Create(mContext, name, cachePath, closures);
}
native void rsnScriptGroup2Execute(long con, long groupID);
@@ -1346,6 +1334,14 @@ public class RenderScript {
if (rs.mContext == 0) {
throw new RSDriverException("Failed to create RS context.");
}
+
+ // set up cache directory for entire context
+ final String CACHE_PATH = "com.android.renderscript.cache";
+ File f = new File(RenderScriptCacheDir.mCacheDir, CACHE_PATH);
+ String mCachePath = f.getAbsolutePath();
+ f.mkdirs();
+ rs.nContextSetCacheDir(mCachePath);
+
rs.mMessageThread = new MessageThread(rs);
rs.mMessageThread.start();
return rs;
diff --git a/rs/java/android/renderscript/RenderScriptCacheDir.java b/rs/java/android/renderscript/RenderScriptCacheDir.java
new file mode 100644
index 0000000..95a9d75
--- /dev/null
+++ b/rs/java/android/renderscript/RenderScriptCacheDir.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2008-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.renderscript;
+
+import java.io.File;
+
+/**
+ * Used only for tracking the RenderScript cache directory.
+ * @hide
+ */
+public class RenderScriptCacheDir {
+ /**
+ * Sets the directory to use as a persistent storage for the
+ * renderscript object file cache.
+ *
+ * @hide
+ * @param cacheDir A directory the current process can write to
+ */
+ public static void setupDiskCache(File cacheDir) {
+ // Defer creation of cache path to nScriptCCreate().
+ mCacheDir = cacheDir;
+ }
+
+ static File mCacheDir;
+
+}
diff --git a/rs/java/android/renderscript/ScriptC.java b/rs/java/android/renderscript/ScriptC.java
index 64d21e4..bf706c1 100644
--- a/rs/java/android/renderscript/ScriptC.java
+++ b/rs/java/android/renderscript/ScriptC.java
@@ -124,7 +124,7 @@ public class ScriptC extends Script {
// Create the RS cache path if we haven't done so already.
if (mCachePath == null) {
- File f = new File(rs.mCacheDir, CACHE_PATH);
+ File f = new File(RenderScriptCacheDir.mCacheDir, CACHE_PATH);
mCachePath = f.getAbsolutePath();
f.mkdirs();
}
@@ -135,7 +135,7 @@ public class ScriptC extends Script {
private static synchronized long internalStringCreate(RenderScript rs, String resName, byte[] bitcode) {
// Create the RS cache path if we haven't done so already.
if (mCachePath == null) {
- File f = new File(rs.mCacheDir, CACHE_PATH);
+ File f = new File(RenderScriptCacheDir.mCacheDir, CACHE_PATH);
mCachePath = f.getAbsolutePath();
f.mkdirs();
}
diff --git a/rs/java/android/renderscript/ScriptGroup2.java b/rs/java/android/renderscript/ScriptGroup2.java
index 13e22aa..417bbee 100644
--- a/rs/java/android/renderscript/ScriptGroup2.java
+++ b/rs/java/android/renderscript/ScriptGroup2.java
@@ -112,7 +112,7 @@ public class ScriptGroup2 extends BaseObj {
public Closure(RenderScript rs, Script.InvokeID invokeID,
Object[] args, Map<Script.FieldID, Object> globals) {
super(0, rs);
- mFP = FieldPacker.createFieldPack(args);
+ mFP = FieldPacker.createFromArray(args);
mArgs = args;
mBindings = globals;
@@ -289,6 +289,7 @@ public class ScriptGroup2 extends BaseObj {
}
}
+ String mName;
List<Closure> mClosures;
List<UnboundValue> mInputs;
Future[] mOutputs;
@@ -299,9 +300,10 @@ public class ScriptGroup2 extends BaseObj {
super(id, rs);
}
- ScriptGroup2(RenderScript rs, List<Closure> closures,
+ ScriptGroup2(RenderScript rs, String name, List<Closure> closures,
List<UnboundValue> inputs, Future[] outputs) {
super(0, rs);
+ mName = name;
mClosures = closures;
mInputs = inputs;
mOutputs = outputs;
@@ -310,7 +312,7 @@ public class ScriptGroup2 extends BaseObj {
for (int i = 0; i < closureIDs.length; i++) {
closureIDs[i] = closures.get(i).getID(rs);
}
- long id = rs.nScriptGroup2Create(ScriptC.mCachePath, closureIDs);
+ long id = rs.nScriptGroup2Create(name, ScriptC.mCachePath, closureIDs);
setID(id);
}
@@ -412,8 +414,12 @@ public class ScriptGroup2 extends BaseObj {
return addInvoke(invoke, args.toArray(), bindingMap);
}
- public ScriptGroup2 create(Future... outputs) {
- ScriptGroup2 ret = new ScriptGroup2(mRS, mClosures, mInputs, outputs);
+ public ScriptGroup2 create(String name, Future... outputs) {
+ if (name == null || name.isEmpty() || name.length() > 100 ||
+ !name.equals(name.replaceAll("[^a-zA-Z0-9-]", "_"))) {
+ throw new RSIllegalArgumentException("invalid script group name");
+ }
+ ScriptGroup2 ret = new ScriptGroup2(mRS, name, mClosures, mInputs, outputs);
return ret;
}
diff --git a/rs/java/android/renderscript/ScriptIntrinsicBlur.java b/rs/java/android/renderscript/ScriptIntrinsicBlur.java
index 5c4edd3..60e2b6d 100644
--- a/rs/java/android/renderscript/ScriptIntrinsicBlur.java
+++ b/rs/java/android/renderscript/ScriptIntrinsicBlur.java
@@ -34,7 +34,7 @@ public final class ScriptIntrinsicBlur extends ScriptIntrinsic {
* Create an intrinsic for applying a blur to an allocation. The
* default radius is 5.0.
*
- * Supported elements types are {@link Element#U8_4}
+ * Supported elements types are {@link Element#U8_4 Element#U8}
*
* @param rs The RenderScript context
* @param e Element type for inputs and outputs
diff --git a/rs/jni/android_renderscript_RenderScript.cpp b/rs/jni/android_renderscript_RenderScript.cpp
index 3591199..ba194ee 100644
--- a/rs/jni/android_renderscript_RenderScript.cpp
+++ b/rs/jni/android_renderscript_RenderScript.cpp
@@ -423,8 +423,9 @@ nClosureSetGlobal(JNIEnv *_env, jobject _this, jlong con, jlong closureID,
}
static long
-nScriptGroup2Create(JNIEnv *_env, jobject _this, jlong con,
+nScriptGroup2Create(JNIEnv *_env, jobject _this, jlong con, jstring name,
jstring cacheDir, jlongArray closureArray) {
+ AutoJavaStringToUTF8 nameUTF(_env, name);
AutoJavaStringToUTF8 cacheDirUTF(_env, cacheDir);
jlong* jClosures = _env->GetLongArrayElements(closureArray, nullptr);
@@ -435,7 +436,8 @@ nScriptGroup2Create(JNIEnv *_env, jobject _this, jlong con,
}
return (jlong)(uintptr_t)rsScriptGroup2Create(
- (RsContext)con, cacheDirUTF.c_str(), cacheDirUTF.length(),
+ (RsContext)con, nameUTF.c_str(), nameUTF.length(),
+ cacheDirUTF.c_str(), cacheDirUTF.length(),
closures, numClosures);
}
@@ -689,6 +691,17 @@ nContextSetPriority(JNIEnv *_env, jobject _this, jlong con, jint p)
rsContextSetPriority((RsContext)con, p);
}
+static void
+nContextSetCacheDir(JNIEnv *_env, jobject _this, jlong con, jstring cacheDir)
+{
+ AutoJavaStringToUTF8 cacheDirUTF(_env, cacheDir);
+
+ if (kLogApi) {
+ ALOGD("ContextSetCacheDir, con(%p), cacheDir(%s)", (RsContext)con, cacheDirUTF.c_str());
+ }
+ rsContextSetCacheDir((RsContext)con, cacheDirUTF.c_str(), cacheDirUTF.length());
+}
+
static void
@@ -2312,6 +2325,7 @@ static JNINativeMethod methods[] = {
{"rsnContextCreateGL", "(JIIIIIIIIIIIIFI)J", (void*)nContextCreateGL },
{"rsnContextFinish", "(J)V", (void*)nContextFinish },
{"rsnContextSetPriority", "(JI)V", (void*)nContextSetPriority },
+{"rsnContextSetCacheDir", "(JLjava/lang/String;)V", (void*)nContextSetCacheDir },
{"rsnContextSetSurface", "(JIILandroid/view/Surface;)V", (void*)nContextSetSurface },
{"rsnContextDestroy", "(J)V", (void*)nContextDestroy },
{"rsnContextDump", "(JI)V", (void*)nContextDump },
@@ -2402,7 +2416,7 @@ static JNINativeMethod methods[] = {
{"rsnScriptInvokeIDCreate", "(JJI)J", (void*)nScriptInvokeIDCreate },
{"rsnScriptFieldIDCreate", "(JJI)J", (void*)nScriptFieldIDCreate },
{"rsnScriptGroupCreate", "(J[J[J[J[J[J)J", (void*)nScriptGroupCreate },
-{"rsnScriptGroup2Create", "(JLjava/lang/String;[J)J", (void*)nScriptGroup2Create },
+{"rsnScriptGroup2Create", "(JLjava/lang/String;Ljava/lang/String;[J)J", (void*)nScriptGroup2Create },
{"rsnScriptGroupSetInput", "(JJJJ)V", (void*)nScriptGroupSetInput },
{"rsnScriptGroupSetOutput", "(JJJJ)V", (void*)nScriptGroupSetOutput },
{"rsnScriptGroupExecute", "(JJ)V", (void*)nScriptGroupExecute },
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index d9ef766..758b0fc 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -2022,6 +2022,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
ReapUnvalidatedNetworks.DONT_REAP);
}
}
+ NetworkFactoryInfo nfi = mNetworkFactoryInfos.remove(msg.replyTo);
+ if (DBG && nfi != null) log("unregisterNetworkFactory for " + nfi.name);
}
// If this method proves to be too slow then we can maintain a separate
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index a9d6a69..4e7aa77 100755
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -2228,7 +2228,7 @@ public final class ActiveServices {
EventLog.writeEvent(EventLogTags.AM_SERVICE_CRASHED_TOO_MUCH,
sr.userId, sr.crashCount, sr.shortName, app.pid);
bringDownServiceLocked(sr);
- } else if (!allowRestart) {
+ } else if (!allowRestart || !mAm.isUserRunningLocked(sr.userId, false)) {
bringDownServiceLocked(sr);
} else {
boolean canceled = scheduleServiceRestartLocked(sr, true);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 09ebe60..05a4d7e 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -91,6 +91,7 @@ import com.google.android.collect.Lists;
import com.google.android.collect.Maps;
import libcore.io.IoUtils;
+import libcore.util.EmptyArray;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -14163,7 +14164,7 @@ public final class ActivityManagerService extends ActivityManagerNative
} else if ("-h".equals(opt)) {
pw.println("meminfo dump options: [-a] [-d] [-c] [--oom] [process]");
pw.println(" -a: include all available information for each process.");
- pw.println(" -d: include dalvik details when dumping process details.");
+ pw.println(" -d: include dalvik details.");
pw.println(" -c: dump in a compact machine-parseable representation.");
pw.println(" --oom: only show processes organized by oom adj.");
pw.println(" --local: only collect details locally, don't call process.");
@@ -14250,6 +14251,8 @@ public final class ActivityManagerService extends ActivityManagerNative
final SparseArray<MemItem> procMemsMap = new SparseArray<MemItem>();
long nativePss = 0;
long dalvikPss = 0;
+ long[] dalvikSubitemPss = dumpDalvik ? new long[Debug.MemoryInfo.NUM_DVK_STATS] :
+ EmptyArray.LONG;
long otherPss = 0;
long[] miscPss = new long[Debug.MemoryInfo.NUM_OTHER_STATS];
@@ -14327,6 +14330,9 @@ public final class ActivityManagerService extends ActivityManagerNative
nativePss += mi.nativePss;
dalvikPss += mi.dalvikPss;
+ for (int j=0; j<dalvikSubitemPss.length; j++) {
+ dalvikSubitemPss[j] += mi.getOtherPss(Debug.MemoryInfo.NUM_OTHER_STATS + j);
+ }
otherPss += mi.otherPss;
for (int j=0; j<Debug.MemoryInfo.NUM_OTHER_STATS; j++) {
long mem = mi.getOtherPss(j);
@@ -14385,6 +14391,10 @@ public final class ActivityManagerService extends ActivityManagerNative
nativePss += mi.nativePss;
dalvikPss += mi.dalvikPss;
+ for (int j=0; j<dalvikSubitemPss.length; j++) {
+ dalvikSubitemPss[j] += mi.getOtherPss(
+ Debug.MemoryInfo.NUM_OTHER_STATS + j);
+ }
otherPss += mi.otherPss;
for (int j=0; j<Debug.MemoryInfo.NUM_OTHER_STATS; j++) {
long mem = mi.getOtherPss(j);
@@ -14403,7 +14413,16 @@ public final class ActivityManagerService extends ActivityManagerNative
ArrayList<MemItem> catMems = new ArrayList<MemItem>();
catMems.add(new MemItem("Native", "Native", nativePss, -1));
- catMems.add(new MemItem("Dalvik", "Dalvik", dalvikPss, -2));
+ final MemItem dalvikItem = new MemItem("Dalvik", "Dalvik", dalvikPss, -2);
+ if (dalvikSubitemPss.length > 0) {
+ dalvikItem.subitems = new ArrayList<MemItem>();
+ for (int j=0; j<dalvikSubitemPss.length; j++) {
+ final String name = Debug.MemoryInfo.getOtherLabel(
+ Debug.MemoryInfo.NUM_OTHER_STATS + j);
+ dalvikItem.subitems.add(new MemItem(name, name, dalvikSubitemPss[j], j));
+ }
+ }
+ catMems.add(dalvikItem);
catMems.add(new MemItem("Unknown", "Unknown", otherPss, -3));
for (int j=0; j<Debug.MemoryInfo.NUM_OTHER_STATS; j++) {
String label = Debug.MemoryInfo.getOtherLabel(j);
@@ -15690,8 +15709,9 @@ public final class ActivityManagerService extends ActivityManagerNative
}
synchronized (this) {
- if (callerApp != null && callerApp.pid == 0) {
- // Caller already died
+ if (callerApp != null && (callerApp.thread == null
+ || callerApp.thread.asBinder() != caller.asBinder())) {
+ // Original caller already died
return null;
}
ReceiverList rl
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 82c71e3..ada16e7 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -899,6 +899,11 @@ final class ActivityStack {
r.userId, System.identityHashCode(r), r.shortComponentName,
mPausingActivity != null
? mPausingActivity.shortComponentName : "(none)");
+ if (r.finishing && r.state == ActivityState.PAUSING) {
+ if (DEBUG_PAUSE) Slog.v(TAG,
+ "Executing finish of failed to pause activity: " + r);
+ finishCurrentActivityLocked(r, FINISH_AFTER_VISIBLE, false);
+ }
}
}
}
@@ -3900,16 +3905,18 @@ final class ActivityStack {
}
void getTasksLocked(List<RunningTaskInfo> list, int callingUid, boolean allowed) {
+ boolean focusedStack = mStackSupervisor.getFocusedStack() == this;
+ boolean topTask = true;
for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
final TaskRecord task = mTaskHistory.get(taskNdx);
+ if (task.getTopActivity() == null) {
+ continue;
+ }
ActivityRecord r = null;
ActivityRecord top = null;
int numActivities = 0;
int numRunning = 0;
final ArrayList<ActivityRecord> activities = task.mActivities;
- if (activities.isEmpty()) {
- continue;
- }
if (!allowed && !task.isHomeTask() && task.effectiveUid != callingUid) {
continue;
}
@@ -3938,14 +3945,18 @@ final class ActivityStack {
ci.baseActivity = r.intent.getComponent();
ci.topActivity = top.intent.getComponent();
ci.lastActiveTime = task.lastActiveTime;
+ if (focusedStack && topTask) {
+ // Give the latest time to ensure foreground task can be sorted
+ // at the first, because lastActiveTime of creating task is 0.
+ ci.lastActiveTime = System.currentTimeMillis();
+ topTask = false;
+ }
if (top.task != null) {
ci.description = top.task.lastDescription;
}
ci.numActivities = numActivities;
ci.numRunning = numRunning;
- //System.out.println(
- // "#" + maxNum + ": " + " descr=" + ci.description);
list.add(ci);
}
}
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index b4a44a6..ce31f98 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -20,7 +20,9 @@ import android.annotation.Nullable;
import android.content.Context;
import android.content.pm.PackageStats;
import android.os.Build;
+import android.text.TextUtils;
import android.util.Slog;
+
import dalvik.system.VMRuntime;
import com.android.internal.os.InstallerConnection;
@@ -42,9 +44,24 @@ public final class Installer extends SystemService {
ping();
}
+ private static String escapeNull(String arg) {
+ if (TextUtils.isEmpty(arg)) {
+ return "!";
+ } else {
+ return arg;
+ }
+ }
+
+ @Deprecated
public int install(String name, int uid, int gid, String seinfo) {
+ return install(null, name, uid, gid, seinfo);
+ }
+
+ public int install(String uuid, String name, int uid, int gid, String seinfo) {
StringBuilder builder = new StringBuilder("install");
builder.append(' ');
+ builder.append(escapeNull(uuid));
+ builder.append(' ');
builder.append(name);
builder.append(' ');
builder.append(uid);
@@ -55,43 +72,25 @@ public final class Installer extends SystemService {
return mInstaller.execute(builder.toString());
}
- public int patchoat(String apkPath, int uid, boolean isPublic, String pkgName,
- String instructionSet) {
- if (!isValidInstructionSet(instructionSet)) {
- Slog.e(TAG, "Invalid instruction set: " + instructionSet);
- return -1;
- }
-
- return mInstaller.patchoat(apkPath, uid, isPublic, pkgName, instructionSet);
- }
-
- public int patchoat(String apkPath, int uid, boolean isPublic, String instructionSet) {
+ public int dexopt(String apkPath, int uid, boolean isPublic,
+ String instructionSet, int dexoptNeeded) {
if (!isValidInstructionSet(instructionSet)) {
Slog.e(TAG, "Invalid instruction set: " + instructionSet);
return -1;
}
- return mInstaller.patchoat(apkPath, uid, isPublic, instructionSet);
- }
-
- public int dexopt(String apkPath, int uid, boolean isPublic, String instructionSet) {
- if (!isValidInstructionSet(instructionSet)) {
- Slog.e(TAG, "Invalid instruction set: " + instructionSet);
- return -1;
- }
-
- return mInstaller.dexopt(apkPath, uid, isPublic, instructionSet);
+ return mInstaller.dexopt(apkPath, uid, isPublic, instructionSet, dexoptNeeded);
}
public int dexopt(String apkPath, int uid, boolean isPublic, String pkgName,
- String instructionSet, boolean vmSafeMode, boolean debuggable,
- @Nullable String outputPath) {
+ String instructionSet, int dexoptNeeded, boolean vmSafeMode,
+ boolean debuggable, @Nullable String outputPath) {
if (!isValidInstructionSet(instructionSet)) {
Slog.e(TAG, "Invalid instruction set: " + instructionSet);
return -1;
}
-
- return mInstaller.dexopt(apkPath, uid, isPublic, pkgName, instructionSet, vmSafeMode,
+ return mInstaller.dexopt(apkPath, uid, isPublic, pkgName,
+ instructionSet, dexoptNeeded, vmSafeMode,
debuggable, outputPath);
}
@@ -146,9 +145,16 @@ public final class Installer extends SystemService {
return mInstaller.execute(builder.toString());
}
+ @Deprecated
public int remove(String name, int userId) {
+ return remove(null, name, userId);
+ }
+
+ public int remove(String uuid, String name, int userId) {
StringBuilder builder = new StringBuilder("remove");
builder.append(' ');
+ builder.append(escapeNull(uuid));
+ builder.append(' ');
builder.append(name);
builder.append(' ');
builder.append(userId);
@@ -164,9 +170,16 @@ public final class Installer extends SystemService {
return mInstaller.execute(builder.toString());
}
+ @Deprecated
public int fixUid(String name, int uid, int gid) {
+ return fixUid(null, name, uid, gid);
+ }
+
+ public int fixUid(String uuid, String name, int uid, int gid) {
StringBuilder builder = new StringBuilder("fixuid");
builder.append(' ');
+ builder.append(escapeNull(uuid));
+ builder.append(' ');
builder.append(name);
builder.append(' ');
builder.append(uid);
@@ -175,27 +188,48 @@ public final class Installer extends SystemService {
return mInstaller.execute(builder.toString());
}
+ @Deprecated
public int deleteCacheFiles(String name, int userId) {
+ return deleteCacheFiles(null, name, userId);
+ }
+
+ public int deleteCacheFiles(String uuid, String name, int userId) {
StringBuilder builder = new StringBuilder("rmcache");
builder.append(' ');
+ builder.append(escapeNull(uuid));
+ builder.append(' ');
builder.append(name);
builder.append(' ');
builder.append(userId);
return mInstaller.execute(builder.toString());
}
+ @Deprecated
public int deleteCodeCacheFiles(String name, int userId) {
+ return deleteCodeCacheFiles(null, name, userId);
+ }
+
+ public int deleteCodeCacheFiles(String uuid, String name, int userId) {
StringBuilder builder = new StringBuilder("rmcodecache");
builder.append(' ');
+ builder.append(escapeNull(uuid));
+ builder.append(' ');
builder.append(name);
builder.append(' ');
builder.append(userId);
return mInstaller.execute(builder.toString());
}
+ @Deprecated
public int createUserData(String name, int uid, int userId, String seinfo) {
+ return createUserData(null, name, uid, userId, seinfo);
+ }
+
+ public int createUserData(String uuid, String name, int uid, int userId, String seinfo) {
StringBuilder builder = new StringBuilder("mkuserdata");
builder.append(' ');
+ builder.append(escapeNull(uuid));
+ builder.append(' ');
builder.append(name);
builder.append(' ');
builder.append(uid);
@@ -213,16 +247,30 @@ public final class Installer extends SystemService {
return mInstaller.execute(builder.toString());
}
+ @Deprecated
public int removeUserDataDirs(int userId) {
+ return removeUserDataDirs(null, userId);
+ }
+
+ public int removeUserDataDirs(String uuid, int userId) {
StringBuilder builder = new StringBuilder("rmuser");
builder.append(' ');
+ builder.append(escapeNull(uuid));
+ builder.append(' ');
builder.append(userId);
return mInstaller.execute(builder.toString());
}
+ @Deprecated
public int clearUserData(String name, int userId) {
+ return clearUserData(null, name, userId);
+ }
+
+ public int clearUserData(String uuid, String name, int userId) {
StringBuilder builder = new StringBuilder("rmuserdata");
builder.append(' ');
+ builder.append(escapeNull(uuid));
+ builder.append(' ');
builder.append(name);
builder.append(' ');
builder.append(userId);
@@ -249,15 +297,30 @@ public final class Installer extends SystemService {
}
}
+ @Deprecated
public int freeCache(long freeStorageSize) {
+ return freeCache(null, freeStorageSize);
+ }
+
+ public int freeCache(String uuid, long freeStorageSize) {
StringBuilder builder = new StringBuilder("freecache");
builder.append(' ');
+ builder.append(escapeNull(uuid));
+ builder.append(' ');
builder.append(String.valueOf(freeStorageSize));
return mInstaller.execute(builder.toString());
}
+ @Deprecated
public int getSizeInfo(String pkgName, int persona, String apkPath, String libDirPath,
String fwdLockApkPath, String asecPath, String[] instructionSets, PackageStats pStats) {
+ return getSizeInfo(null, pkgName, persona, apkPath, libDirPath, fwdLockApkPath, asecPath,
+ instructionSets, pStats);
+ }
+
+ public int getSizeInfo(String uuid, String pkgName, int persona, String apkPath,
+ String libDirPath, String fwdLockApkPath, String asecPath, String[] instructionSets,
+ PackageStats pStats) {
for (String instructionSet : instructionSets) {
if (!isValidInstructionSet(instructionSet)) {
Slog.e(TAG, "Invalid instruction set: " + instructionSet);
@@ -267,6 +330,8 @@ public final class Installer extends SystemService {
StringBuilder builder = new StringBuilder("getsize");
builder.append(' ');
+ builder.append(escapeNull(uuid));
+ builder.append(' ');
builder.append(pkgName);
builder.append(' ');
builder.append(persona);
@@ -306,6 +371,11 @@ public final class Installer extends SystemService {
return mInstaller.execute("movefiles");
}
+ @Deprecated
+ public int linkNativeLibraryDirectory(String dataPath, String nativeLibPath32, int userId) {
+ return linkNativeLibraryDirectory(null, dataPath, nativeLibPath32, userId);
+ }
+
/**
* Links the 32 bit native library directory in an application's data directory to the
* real location for backward compatibility. Note that no such symlink is created for
@@ -313,7 +383,8 @@ public final class Installer extends SystemService {
*
* @return -1 on error
*/
- public int linkNativeLibraryDirectory(String dataPath, String nativeLibPath32, int userId) {
+ public int linkNativeLibraryDirectory(String uuid, String dataPath, String nativeLibPath32,
+ int userId) {
if (dataPath == null) {
Slog.e(TAG, "linkNativeLibraryDirectory dataPath is null");
return -1;
@@ -322,7 +393,10 @@ public final class Installer extends SystemService {
return -1;
}
- StringBuilder builder = new StringBuilder("linklib ");
+ StringBuilder builder = new StringBuilder("linklib");
+ builder.append(' ');
+ builder.append(escapeNull(uuid));
+ builder.append(' ');
builder.append(dataPath);
builder.append(' ');
builder.append(nativeLibPath32);
@@ -332,9 +406,16 @@ public final class Installer extends SystemService {
return mInstaller.execute(builder.toString());
}
+ @Deprecated
public boolean restoreconData(String pkgName, String seinfo, int uid) {
+ return restoreconData(null, pkgName, seinfo, uid);
+ }
+
+ public boolean restoreconData(String uuid, String pkgName, String seinfo, int uid) {
StringBuilder builder = new StringBuilder("restorecondata");
builder.append(' ');
+ builder.append(escapeNull(uuid));
+ builder.append(' ');
builder.append(pkgName);
builder.append(' ');
builder.append(seinfo != null ? seinfo : "!");
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index 680ec4b..4c36fa6 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -113,64 +113,48 @@ final class PackageDexOptimizer {
for (String path : paths) {
try {
- // This will return DEXOPT_NEEDED if we either cannot find any odex file for this
- // package or the one we find does not match the image checksum (i.e. it was
- // compiled against an old image). It will return PATCHOAT_NEEDED if we can find a
- // odex file and it matches the checksum of the image but not its base address,
- // meaning we need to move it.
- final byte isDexOptNeeded = DexFile.isDexOptNeededInternal(path,
- pkg.packageName, dexCodeInstructionSet, defer);
- if (forceDex || (!defer && isDexOptNeeded == DexFile.DEXOPT_NEEDED)) {
- File oatDir = createOatDirIfSupported(pkg, dexCodeInstructionSet);
- Log.i(TAG, "Running dexopt on: " + path + " pkg="
- + pkg.applicationInfo.packageName + " isa=" + dexCodeInstructionSet
- + " vmSafeMode=" + vmSafeMode + " debuggable=" + debuggable
- + " oatDir = " + oatDir);
- final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
+ final int dexoptNeeded;
+ if (forceDex) {
+ dexoptNeeded = DexFile.DEX2OAT_NEEDED;
+ } else {
+ dexoptNeeded = DexFile.getDexOptNeeded(path,
+ pkg.packageName, dexCodeInstructionSet, defer);
+ }
- if (oatDir != null) {
- int ret = mPackageManagerService.mInstaller.dexopt(
- path, sharedGid, !pkg.isForwardLocked(), pkg.packageName,
- dexCodeInstructionSet, vmSafeMode, debuggable,
- oatDir.getAbsolutePath());
- if (ret < 0) {
- return DEX_OPT_FAILED;
- }
+ if (!forceDex && defer && dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) {
+ // We're deciding to defer a needed dexopt. Don't bother dexopting for other
+ // paths and instruction sets. We'll deal with them all together when we process
+ // our list of deferred dexopts.
+ addPackageForDeferredDexopt(pkg);
+ return DEX_OPT_DEFERRED;
+ }
+
+ if (dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) {
+ final String dexoptType;
+ String oatDir = null;
+ if (dexoptNeeded == DexFile.DEX2OAT_NEEDED) {
+ dexoptType = "dex2oat";
+ oatDir = createOatDirIfSupported(pkg, dexCodeInstructionSet);
+ } else if (dexoptNeeded == DexFile.PATCHOAT_NEEDED) {
+ dexoptType = "patchoat";
+ } else if (dexoptNeeded == DexFile.SELF_PATCHOAT_NEEDED) {
+ dexoptType = "self patchoat";
} else {
- final int ret = mPackageManagerService.mInstaller
- .dexopt(path, sharedGid,
- !pkg.isForwardLocked(), pkg.packageName,
- dexCodeInstructionSet,
- vmSafeMode, debuggable, null);
- if (ret < 0) {
- return DEX_OPT_FAILED;
- }
+ throw new IllegalStateException("Invalid dexopt needed: " + dexoptNeeded);
}
-
- performedDexOpt = true;
- } else if (!defer && isDexOptNeeded == DexFile.PATCHOAT_NEEDED) {
- Log.i(TAG, "Running patchoat on: " + pkg.applicationInfo.packageName);
+ Log.i(TAG, "Running dexopt (" + dexoptType + ") on: " + path + " pkg="
+ + pkg.applicationInfo.packageName + " isa=" + dexCodeInstructionSet
+ + " vmSafeMode=" + vmSafeMode + " debuggable=" + debuggable
+ + " oatDir = " + oatDir);
final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
- final int ret = mPackageManagerService.mInstaller.patchoat(path, sharedGid,
- !pkg.isForwardLocked(), pkg.packageName, dexCodeInstructionSet);
-
+ final int ret = mPackageManagerService.mInstaller.dexopt(path, sharedGid,
+ !pkg.isForwardLocked(), pkg.packageName, dexCodeInstructionSet,
+ dexoptNeeded, vmSafeMode, debuggable, oatDir);
if (ret < 0) {
- // Don't bother running patchoat again if we failed, it will probably
- // just result in an error again. Also, don't bother dexopting for other
- // paths & ISAs.
return DEX_OPT_FAILED;
}
-
performedDexOpt = true;
}
-
- // We're deciding to defer a needed dexopt. Don't bother dexopting for other
- // paths and instruction sets. We'll deal with them all together when we process
- // our list of deferred dexopts.
- if (defer && isDexOptNeeded != DexFile.UP_TO_DATE) {
- addPackageForDeferredDexopt(pkg);
- return DEX_OPT_DEFERRED;
- }
} catch (FileNotFoundException e) {
Slog.w(TAG, "Apk not found for dexopt: " + path);
return DEX_OPT_FAILED;
@@ -187,7 +171,7 @@ final class PackageDexOptimizer {
}
// At this point we haven't failed dexopt and we haven't deferred dexopt. We must
- // either have either succeeded dexopt, or have had isDexOptNeededInternal tell us
+ // either have either succeeded dexopt, or have had getDexOptNeeded tell us
// it isn't required. We therefore mark that this package doesn't need dexopt unless
// it's forced. performedDexOpt will tell us whether we performed dex-opt or skipped
// it.
@@ -209,10 +193,11 @@ final class PackageDexOptimizer {
* <li>Package location is not a directory, i.e. monolithic install.</li>
* </ul>
*
- * @return oat directory or null, if oat directory cannot be created.
+ * @return Absolute path to the oat directory or null, if oat directory
+ * cannot be created.
*/
@Nullable
- private File createOatDirIfSupported(PackageParser.Package pkg, String dexInstructionSet)
+ private String createOatDirIfSupported(PackageParser.Package pkg, String dexInstructionSet)
throws IOException {
if (pkg.isSystemApp() && !pkg.isUpdatedSystemApp()) {
return null;
@@ -222,7 +207,7 @@ final class PackageDexOptimizer {
File oatDir = getOatDir(codePath);
mPackageManagerService.mInstaller.createOatDir(oatDir.getAbsolutePath(),
dexInstructionSet);
- return oatDir;
+ return oatDir.getAbsolutePath();
}
return null;
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 67d3cbe..3f0e8b0 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -1457,18 +1457,10 @@ public class PackageManagerService extends IPackageManager.Stub {
}
try {
- byte dexoptRequired = DexFile.isDexOptNeededInternal(lib, null,
- dexCodeInstructionSet,
- false);
- if (dexoptRequired != DexFile.UP_TO_DATE) {
+ int dexoptNeeded = DexFile.getDexOptNeeded(lib, null, dexCodeInstructionSet, false);
+ if (dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) {
alreadyDexOpted.add(lib);
-
- // The list of "shared libraries" we have at this point is
- if (dexoptRequired == DexFile.DEXOPT_NEEDED) {
- mInstaller.dexopt(lib, Process.SYSTEM_UID, true, dexCodeInstructionSet);
- } else {
- mInstaller.patchoat(lib, Process.SYSTEM_UID, true, dexCodeInstructionSet);
- }
+ mInstaller.dexopt(lib, Process.SYSTEM_UID, true, dexCodeInstructionSet, dexoptNeeded);
}
} catch (FileNotFoundException e) {
Slog.w(TAG, "Library not found: " + lib);
@@ -1514,13 +1506,9 @@ public class PackageManagerService extends IPackageManager.Stub {
continue;
}
try {
- byte dexoptRequired = DexFile.isDexOptNeededInternal(path, null,
- dexCodeInstructionSet,
- false);
- if (dexoptRequired == DexFile.DEXOPT_NEEDED) {
- mInstaller.dexopt(path, Process.SYSTEM_UID, true, dexCodeInstructionSet);
- } else if (dexoptRequired == DexFile.PATCHOAT_NEEDED) {
- mInstaller.patchoat(path, Process.SYSTEM_UID, true, dexCodeInstructionSet);
+ int dexoptNeeded = DexFile.getDexOptNeeded(path, null, dexCodeInstructionSet, false);
+ if (dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) {
+ mInstaller.dexopt(path, Process.SYSTEM_UID, true, dexCodeInstructionSet, dexoptNeeded);
}
} catch (FileNotFoundException e) {
Slog.w(TAG, "Jar not found: " + path);
@@ -10447,13 +10435,13 @@ public class PackageManagerService extends IPackageManager.Stub {
return;
}
+ // Call with SCAN_NO_DEX, since dexopt has already been made
if (replace) {
- // Call replacePackageLI with SCAN_NO_DEX, since we already made dexopt
replacePackageLI(pkg, parseFlags, scanFlags | SCAN_REPLACING | SCAN_NO_DEX, args.user,
installerPackageName, res);
} else {
- installNewPackageLI(pkg, parseFlags, scanFlags | SCAN_DELETE_DATA_ON_FAILURES,
- args.user, installerPackageName, res);
+ installNewPackageLI(pkg, parseFlags, scanFlags | SCAN_DELETE_DATA_ON_FAILURES
+ | SCAN_NO_DEX, args.user, installerPackageName, res);
}
synchronized (mPackages) {
final PackageSetting ps = mSettings.mPackages.get(pkgName);
diff --git a/services/core/java/com/android/server/pm/SELinuxMMAC.java b/services/core/java/com/android/server/pm/SELinuxMMAC.java
index 95ed7bc..d517642 100644
--- a/services/core/java/com/android/server/pm/SELinuxMMAC.java
+++ b/services/core/java/com/android/server/pm/SELinuxMMAC.java
@@ -37,6 +37,7 @@ import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -55,14 +56,15 @@ import org.xmlpull.v1.XmlPullParserException;
*/
public final class SELinuxMMAC {
- private static final String TAG = "SELinuxMMAC";
+ static final String TAG = "SELinuxMMAC";
private static final boolean DEBUG_POLICY = false;
private static final boolean DEBUG_POLICY_INSTALL = DEBUG_POLICY || false;
+ private static final boolean DEBUG_POLICY_ORDER = DEBUG_POLICY || false;
// All policy stanzas read from mac_permissions.xml. This is also the lock
// to synchronize access during policy load and access attempts.
- private static final List<Policy> sPolicies = new ArrayList<Policy>();
+ private static List<Policy> sPolicies = new ArrayList<>();
// Data policy override version file.
private static final String DATA_VERSION_FILE =
@@ -115,17 +117,9 @@ public final class SELinuxMMAC {
* were loaded successfully; no partial loading is possible.
*/
public static boolean readInstallPolicy() {
- // Temp structure to hold the rules while we parse the xml file. We add
- // all the rules once we know there's no problems.
+ // Temp structure to hold the rules while we parse the xml file
List<Policy> policies = new ArrayList<>();
- // A separate structure to hold the default stanza. We need to add this to
- // the end of the policies list structure.
- Policy defaultPolicy = null;
-
- // Track sets of known policy certs so we can enforce rules across stanzas.
- Set<Set<Signature>> knownCerts = new HashSet<>();
-
FileReader policyFile = null;
XmlPullParser parser = Xml.newPullParser();
try {
@@ -141,31 +135,15 @@ public final class SELinuxMMAC {
continue;
}
- String tagName = parser.getName();
- if ("signer".equals(tagName)) {
- Policy signerPolicy = readSignerOrThrow(parser);
- // Return of a Policy instance ensures certain invariants have
- // passed, however, we still want to do some cross policy checking.
- // Thus, check that we haven't seen the certs in another stanza.
- Set<Signature> certs = signerPolicy.getSignatures();
- if (knownCerts.contains(certs)) {
- String msg = "Separate stanzas have identical certs";
- throw new IllegalStateException(msg);
- }
- knownCerts.add(certs);
- policies.add(signerPolicy);
- } else if ("default".equals(tagName)) {
- Policy defPolicy = readDefaultOrThrow(parser);
- // Return of a Policy instance ensures certain invariants have
- // passed, however, we still want to do some cross policy checking.
- // Thus, check that we haven't already seen a default stanza.
- if (defaultPolicy != null) {
- String msg = "Multiple default stanzas identified";
- throw new IllegalStateException(msg);
- }
- defaultPolicy = defPolicy;
- } else {
- skip(parser);
+ switch (parser.getName()) {
+ case "signer":
+ policies.add(readSignerOrThrow(parser));
+ break;
+ case "default":
+ policies.add(readDefaultOrThrow(parser));
+ break;
+ default:
+ skip(parser);
}
}
} catch (IllegalStateException | IllegalArgumentException |
@@ -185,15 +163,22 @@ public final class SELinuxMMAC {
IoUtils.closeQuietly(policyFile);
}
- // Add the default policy to the end if there is one. This will ensure that
- // the default stanza is consulted last when performing policy lookups.
- if (defaultPolicy != null) {
- policies.add(defaultPolicy);
+ // Now sort the policy stanzas
+ PolicyComparator policySort = new PolicyComparator();
+ Collections.sort(policies, policySort);
+ if (policySort.foundDuplicate()) {
+ Slog.w(TAG, "ERROR! Duplicate entries found parsing " + MAC_PERMISSIONS);
+ return false;
}
synchronized (sPolicies) {
- sPolicies.clear();
- sPolicies.addAll(policies);
+ sPolicies = policies;
+
+ if (DEBUG_POLICY_ORDER) {
+ for (Policy policy : sPolicies) {
+ Slog.d(TAG, "Policy: " + policy.toString());
+ }
+ }
}
return true;
@@ -497,30 +482,42 @@ public final class SELinuxMMAC {
* of invariants before being built and returned. Each instance can be guaranteed to
* hold one valid policy stanza as outlined in the external/sepolicy/mac_permissions.xml
* file.
- * </p>
+ * <p>
* The following is an example of how to use {@link Policy.PolicyBuilder} to create a
- * signer based Policy instance.
+ * signer based Policy instance with only inner package name refinements.
* </p>
* <pre>
* {@code
* Policy policy = new Policy.PolicyBuilder()
* .addSignature("308204a8...")
* .addSignature("483538c8...")
- * .setGlobalSeinfoOrThrow("paltform")
* .addInnerPackageMapOrThrow("com.foo.", "bar")
* .addInnerPackageMapOrThrow("com.foo.other", "bar")
* .build();
* }
* </pre>
* <p>
- * An example of how to use {@link Policy.PolicyBuilder} to create a default based Policy
- * instance.
+ * The following is an example of how to use {@link Policy.PolicyBuilder} to create a
+ * signer based Policy instance with only a global seinfo tag.
+ * </p>
+ * <pre>
+ * {@code
+ * Policy policy = new Policy.PolicyBuilder()
+ * .addSignature("308204a8...")
+ * .addSignature("483538c8...")
+ * .setGlobalSeinfoOrThrow("paltform")
+ * .build();
+ * }
+ * </pre>
+ * <p>
+ * The following is an example of how to use {@link Policy.PolicyBuilder} to create a
+ * default based Policy instance.
* </p>
* <pre>
* {@code
* Policy policy = new Policy.PolicyBuilder()
* .setAsDefaultPolicy()
- * .setGlobalSeinfoOrThrow("defualt")
+ * .setGlobalSeinfoOrThrow("default")
* .build();
* }
* </pre>
@@ -551,6 +548,65 @@ final class Policy {
}
/**
+ * Return whether this policy object represents a default stanza.
+ *
+ * @return A boolean indicating if this object represents a default policy stanza.
+ */
+ public boolean isDefaultStanza() {
+ return mDefaultStanza;
+ }
+
+ /**
+ * Return whether this policy object contains package name mapping refinements.
+ *
+ * @return A boolean indicating if this object has inner package name mappings.
+ */
+ public boolean hasInnerPackages() {
+ return !mPkgMap.isEmpty();
+ }
+
+ /**
+ * Return the mapping of all package name refinements.
+ *
+ * @return A Map object whose keys are the package names and whose values are
+ * the seinfo assignments.
+ */
+ public Map<String, String> getInnerPackages() {
+ return mPkgMap;
+ }
+
+ /**
+ * Return whether the policy object has a global seinfo tag attached.
+ *
+ * @return A boolean indicating if this stanza has a global seinfo tag.
+ */
+ public boolean hasGlobalSeinfo() {
+ return mSeinfo != null;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ if (mDefaultStanza) {
+ sb.append("defaultStanza=true ");
+ }
+
+ for (Signature cert : mCerts) {
+ sb.append("cert=" + cert.toCharsString().substring(0, 11) + "... ");
+ }
+
+ if (mSeinfo != null) {
+ sb.append("seinfo=" + mSeinfo);
+ }
+
+ for (String name : mPkgMap.keySet()) {
+ sb.append(" " + name + "=" + mPkgMap.get(name));
+ }
+
+ return sb.toString();
+ }
+
+ /**
* <p>
* Determine the seinfo value to assign to an apk. The appropriate seinfo value
* is determined using the following steps:
@@ -623,7 +679,7 @@ final class Policy {
}
/**
- * Sets this stanza as a defualt stanza. All policy stanzas are assumed to
+ * Sets this stanza as a default stanza. All policy stanzas are assumed to
* be signer stanzas unless this method is explicitly called. Default stanzas
* are treated differently with respect to allowable child tags, ordering and
* when and how policy decisions are enforced.
@@ -757,7 +813,7 @@ final class Policy {
* <ul>
* <li> at least one cert must be found </li>
* <li> either a global seinfo value is present OR at least one
- * inner package mapping must be present. </li>
+ * inner package mapping must be present BUT not both. </li>
* </ul>
* </li>
* </ul>
@@ -786,9 +842,9 @@ final class Policy {
String err = "Missing certs with signer tag. Expecting at least one.";
throw new IllegalStateException(err);
}
- if ((p.mSeinfo == null) && (p.mPkgMap.isEmpty())) {
- String err = "Missing seinfo OR package tags with signer tag. At " +
- "least one must be present.";
+ if (!(p.mSeinfo == null ^ p.mPkgMap.isEmpty())) {
+ String err = "Only seinfo tag XOR package tags are allowed within " +
+ "a signer stanza.";
throw new IllegalStateException(err);
}
}
@@ -797,3 +853,58 @@ final class Policy {
}
}
}
+
+/**
+ * Comparision imposing an ordering on Policy objects. It is understood that Policy
+ * objects can only take one of three forms and ordered according to the following
+ * set of rules most specific to least.
+ * <ul>
+ * <li> signer stanzas with inner package mappings </li>
+ * <li> signer stanzas with global seinfo tags </li>
+ * <li> default stanza </li>
+ * </ul>
+ * This comparison also checks for duplicate entries on the input selectors. Any
+ * found duplicates will be flagged and can be checked with {@link #foundDuplicate}.
+ */
+
+final class PolicyComparator implements Comparator<Policy> {
+
+ private boolean duplicateFound = false;
+
+ public boolean foundDuplicate() {
+ return duplicateFound;
+ }
+
+ @Override
+ public int compare(Policy p1, Policy p2) {
+
+ // Give precedence to signature stanzas over default stanzas
+ if (p1.isDefaultStanza() != p2.isDefaultStanza()) {
+ return p1.isDefaultStanza() ? 1 : -1;
+ }
+
+ // Give precedence to stanzas with inner package mappings
+ if (p1.hasInnerPackages() != p2.hasInnerPackages()) {
+ return p1.hasInnerPackages() ? -1 : 1;
+ }
+
+ // Check for duplicate entries
+ if (p1.getSignatures().equals(p2.getSignatures())) {
+ // Checks if default stanza or a signer w/o inner package names
+ if (p1.hasGlobalSeinfo()) {
+ duplicateFound = true;
+ Slog.e(SELinuxMMAC.TAG, "Duplicate policy entry: " + p1.toString());
+ }
+
+ // Look for common inner package name mappings
+ final Map<String, String> p1Packages = p1.getInnerPackages();
+ final Map<String, String> p2Packages = p2.getInnerPackages();
+ if (!Collections.disjoint(p1Packages.keySet(), p2Packages.keySet())) {
+ duplicateFound = true;
+ Slog.e(SELinuxMMAC.TAG, "Duplicate policy entry: " + p1.toString());
+ }
+ }
+
+ return 0;
+ }
+}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index de7cb33..8998d39 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -504,7 +504,12 @@ public class WindowManagerService extends IWindowManager.Stub
int mLastDisplayFreezeDuration = 0;
Object mLastFinishedFreezeSource = null;
boolean mWaitingForConfig = false;
- boolean mWindowsFreezingScreen = false;
+
+ final static int WINDOWS_FREEZING_SCREENS_NONE = 0;
+ final static int WINDOWS_FREEZING_SCREENS_ACTIVE = 1;
+ final static int WINDOWS_FREEZING_SCREENS_TIMEOUT = 2;
+ private int mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_NONE;
+
boolean mClientFreezingScreen = false;
int mAppsFreezingScreen = 0;
int mLastWindowForcedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
@@ -4712,7 +4717,8 @@ public class WindowManagerService extends IWindowManager.Stub
WindowState w = wtoken.allAppWindows.get(i);
if (w.mAppFreezing) {
w.mAppFreezing = false;
- if (w.mHasSurface && !w.mOrientationChanging) {
+ if (w.mHasSurface && !w.mOrientationChanging
+ && mWindowsFreezingScreen != WINDOWS_FREEZING_SCREENS_TIMEOUT) {
if (DEBUG_ORIENTATION) Slog.v(TAG, "set mOrientationChanging of " + w);
w.mOrientationChanging = true;
mInnerFields.mOrientationChangeComplete = false;
@@ -4761,7 +4767,7 @@ public class WindowManagerService extends IWindowManager.Stub
if (mAppsFreezingScreen == 1) {
startFreezingDisplayLocked(false, 0, 0);
mH.removeMessages(H.APP_FREEZE_TIMEOUT);
- mH.sendEmptyMessageDelayed(H.APP_FREEZE_TIMEOUT, 5000);
+ mH.sendEmptyMessageDelayed(H.APP_FREEZE_TIMEOUT, 2000);
}
}
final int N = wtoken.allAppWindows.size();
@@ -6550,7 +6556,7 @@ public class WindowManagerService extends IWindowManager.Stub
mAltOrientation = altOrientation;
mPolicy.setRotationLw(mRotation);
- mWindowsFreezingScreen = true;
+ mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_ACTIVE;
mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
mH.sendEmptyMessageDelayed(H.WINDOW_FREEZE_TIMEOUT, WINDOW_FREEZE_TIMEOUT_DURATION);
mWaitingForConfig = true;
@@ -7920,6 +7926,7 @@ public class WindowManagerService extends IWindowManager.Stub
// TODO(multidisplay): Can non-default displays rotate?
synchronized (mWindowMap) {
Slog.w(TAG, "Window freeze timeout expired.");
+ mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_TIMEOUT;
final WindowList windows = getDefaultWindowListLocked();
int i = windows.size();
while (i > 0) {
@@ -7991,6 +7998,7 @@ public class WindowManagerService extends IWindowManager.Stub
case APP_FREEZE_TIMEOUT: {
synchronized (mWindowMap) {
Slog.w(TAG, "App freeze timeout expired.");
+ mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_TIMEOUT;
final int numStacks = mStackIdToStack.size();
for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
final TaskStack stack = mStackIdToStack.valueAt(stackNdx);
@@ -9076,13 +9084,13 @@ public class WindowManagerService extends IWindowManager.Stub
// If the screen is currently frozen or off, then keep
// it frozen/off until this window draws at its new
// orientation.
- if (!okToDisplay()) {
+ if (!okToDisplay() && mWindowsFreezingScreen != WINDOWS_FREEZING_SCREENS_TIMEOUT) {
if (DEBUG_ORIENTATION) Slog.v(TAG, "Changing surface while display frozen: " + w);
w.mOrientationChanging = true;
w.mLastFreezeDuration = 0;
mInnerFields.mOrientationChangeComplete = false;
- if (!mWindowsFreezingScreen) {
- mWindowsFreezingScreen = true;
+ if (mWindowsFreezingScreen == WINDOWS_FREEZING_SCREENS_NONE) {
+ mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_ACTIVE;
// XXX should probably keep timeout from
// when we first froze the display.
mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
@@ -10107,8 +10115,8 @@ public class WindowManagerService extends IWindowManager.Stub
"With display frozen, orientationChangeComplete="
+ mInnerFields.mOrientationChangeComplete);
if (mInnerFields.mOrientationChangeComplete) {
- if (mWindowsFreezingScreen) {
- mWindowsFreezingScreen = false;
+ if (mWindowsFreezingScreen != WINDOWS_FREEZING_SCREENS_NONE) {
+ mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_NONE;
mLastFinishedFreezeSource = mInnerFields.mLastWindowFreezeSource;
mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
}
@@ -10394,7 +10402,7 @@ public class WindowManagerService extends IWindowManager.Stub
} else {
mInnerFields.mOrientationChangeComplete = true;
mInnerFields.mLastWindowFreezeSource = mAnimator.mLastWindowFreezeSource;
- if (mWindowsFreezingScreen) {
+ if (mWindowsFreezingScreen != WINDOWS_FREEZING_SCREENS_NONE) {
doRequest = true;
}
}
@@ -10739,7 +10747,8 @@ public class WindowManagerService extends IWindowManager.Stub
return;
}
- if (mWaitingForConfig || mAppsFreezingScreen > 0 || mWindowsFreezingScreen
+ if (mWaitingForConfig || mAppsFreezingScreen > 0
+ || mWindowsFreezingScreen == WINDOWS_FREEZING_SCREENS_ACTIVE
|| mClientFreezingScreen || !mOpeningApps.isEmpty()) {
if (DEBUG_ORIENTATION) Slog.d(TAG,
"stopFreezingDisplayLocked: Returning mWaitingForConfig=" + mWaitingForConfig
diff --git a/tools/aapt/Android.mk b/tools/aapt/Android.mk
index c5495a5..9956bd7 100644
--- a/tools/aapt/Android.mk
+++ b/tools/aapt/Android.mk
@@ -67,7 +67,7 @@ aaptHostStaticLibs := \
libziparchive-host
aaptCFlags := -DAAPT_VERSION=\"$(BUILD_NUMBER)\"
-aaptCFLAGS += -Wall -Werror
+aaptCFlags += -Wall -Werror
ifeq ($(HOST_OS),linux)
aaptHostLdLibs += -lrt -ldl -lpthread
diff --git a/tools/aapt/Images.cpp b/tools/aapt/Images.cpp
index 063b4e6..e4738f5 100644
--- a/tools/aapt/Images.cpp
+++ b/tools/aapt/Images.cpp
@@ -412,7 +412,6 @@ static void find_max_opacity(png_byte** rows,
int startX, int startY, int endX, int endY, int dX, int dY,
int* out_inset)
{
- bool opaque_within_inset = true;
uint8_t max_opacity = 0;
int inset = 0;
*out_inset = 0;
diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp
index 38d10cf..beb94fd 100644
--- a/tools/aapt/Resource.cpp
+++ b/tools/aapt/Resource.cpp
@@ -3056,7 +3056,6 @@ writeProguardForLayouts(ProguardKeepSet* keep, const sp<AaptAssets>& assets)
const sp<AaptDir>& d = dirs.itemAt(k);
const String8& dirName = d->getLeaf();
Vector<String8> startTags;
- const char* startTag = NULL;
const KeyedVector<String8, Vector<NamespaceAttributePair> >* tagAttrPairs = NULL;
if ((dirName == String8("layout")) || (strncmp(dirName.string(), "layout-", 7) == 0)) {
tagAttrPairs = &kLayoutTagAttrPairs;
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index 24f8168..c5fccbf 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -3167,7 +3167,7 @@ status_t ResourceTable::flatten(Bundle* bundle, const sp<const ResourceFilter>&
if (!validResources[i]) {
sp<ConfigList> c = t->getOrderedConfigs().itemAt(i);
if (c != NULL) {
- fprintf(stderr, "%s: no entries written for %s/%s (0x%08x)\n", log_prefix,
+ fprintf(stderr, "%s: no entries written for %s/%s (0x%08zx)\n", log_prefix,
String8(typeName).string(), String8(c->getName()).string(),
Res_MAKEID(p->getAssignedId() - 1, ti, i));
}
@@ -4526,7 +4526,6 @@ status_t ResourceTable::modifyForCompat(const Bundle* bundle) {
const KeyedVector<String16, Item>& bag = e->getBag();
const size_t bagCount = bag.size();
for (size_t bi = 0; bi < bagCount; bi++) {
- const Item& item = bag.valueAt(bi);
const uint32_t attrId = getResId(bag.keyAt(bi), &attr16);
const int sdkLevel = getPublicAttributeSdkLevel(attrId);
if (sdkLevel > 1 && sdkLevel > config.sdkVersion && sdkLevel > minSdk) {