Loading core/java/android/security/keystore/KeyDerivationParameters.aidl→core/java/android/security/keystore/KeyDerivationParams.aidl +1 −1 Original line number Diff line number Diff line Loading @@ -17,4 +17,4 @@ package android.security.keystore; /* @hide */ parcelable KeyDerivationParameters; parcelable KeyDerivationParams; core/java/android/security/keystore/KeyDerivationParameters.java→core/java/android/security/keystore/KeyDerivationParams.java +13 −18 Original line number Diff line number Diff line Loading @@ -28,27 +28,22 @@ import java.lang.annotation.RetentionPolicy; /** * Collection of parameters which define a key derivation function. * Supports * Currently only supports salted SHA-256 * * <ul> * <li>SHA256 * <li>Argon2id * </ul> * @hide */ public final class KeyDerivationParameters implements Parcelable { public final class KeyDerivationParams implements Parcelable { private final int mAlgorithm; private byte[] mSalt; /** @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef({ALGORITHM_SHA256, ALGORITHM_ARGON2ID}) @IntDef(prefix = {"ALGORITHM_"}, value = {ALGORITHM_SHA256, ALGORITHM_ARGON2ID}) public @interface KeyDerivationAlgorithm { } /** * Salted SHA256 * @hide */ public static final int ALGORITHM_SHA256 = 1; Loading @@ -62,11 +57,11 @@ public final class KeyDerivationParameters implements Parcelable { /** * Creates instance of the class to to derive key using salted SHA256 hash. */ public static KeyDerivationParameters createSha256Parameters(@NonNull byte[] salt) { return new KeyDerivationParameters(ALGORITHM_SHA256, salt); public static KeyDerivationParams createSha256Params(@NonNull byte[] salt) { return new KeyDerivationParams(ALGORITHM_SHA256, salt); } private KeyDerivationParameters(@KeyDerivationAlgorithm int algorithm, @NonNull byte[] salt) { private KeyDerivationParams(@KeyDerivationAlgorithm int algorithm, @NonNull byte[] salt) { mAlgorithm = algorithm; mSalt = Preconditions.checkNotNull(salt); } Loading @@ -85,14 +80,14 @@ public final class KeyDerivationParameters implements Parcelable { return mSalt; } public static final Parcelable.Creator<KeyDerivationParameters> CREATOR = new Parcelable.Creator<KeyDerivationParameters>() { public KeyDerivationParameters createFromParcel(Parcel in) { return new KeyDerivationParameters(in); public static final Parcelable.Creator<KeyDerivationParams> CREATOR = new Parcelable.Creator<KeyDerivationParams>() { public KeyDerivationParams createFromParcel(Parcel in) { return new KeyDerivationParams(in); } public KeyDerivationParameters[] newArray(int length) { return new KeyDerivationParameters[length]; public KeyDerivationParams[] newArray(int length) { return new KeyDerivationParams[length]; } }; Loading @@ -108,7 +103,7 @@ public final class KeyDerivationParameters implements Parcelable { /** * @hide */ protected KeyDerivationParameters(Parcel in) { protected KeyDerivationParams(Parcel in) { mAlgorithm = in.readInt(); mSalt = in.createByteArray(); } Loading core/java/android/security/keystore/RecoveryData.java +1 −2 Original line number Diff line number Diff line Loading @@ -38,7 +38,7 @@ import java.util.List; * @hide */ public final class RecoveryData implements Parcelable { private Integer mSnapshotVersion; private int mSnapshotVersion; private List<RecoveryMetadata> mRecoveryMetadata; private List<EntryRecoveryData> mEntryRecoveryData; private byte[] mEncryptedRecoveryKeyBlob; Loading Loading @@ -163,7 +163,6 @@ public final class RecoveryData implements Parcelable { * @throws NullPointerException if some required fields were not set. */ public @NonNull RecoveryData build() { Preconditions.checkNotNull(mInstance.mSnapshotVersion); Preconditions.checkCollectionElementsNotNull(mInstance.mRecoveryMetadata, "recoveryMetadata"); Preconditions.checkCollectionElementsNotNull(mInstance.mEntryRecoveryData, Loading core/java/android/security/keystore/RecoveryManager.java +8 −112 Original line number Diff line number Diff line Loading @@ -23,8 +23,6 @@ import android.content.pm.PackageManager.NameNotFoundException; import android.os.RemoteException; import android.os.ServiceManager; import android.os.ServiceSpecificException; import android.security.KeyStore; import android.util.AndroidException; import com.android.internal.widget.ILockSettings; Loading @@ -39,64 +37,6 @@ import java.util.Map; */ public class RecoveryManager { public static final int NO_ERROR = KeyStore.NO_ERROR; public static final int SYSTEM_ERROR = KeyStore.SYSTEM_ERROR; /** * Failed because the loader has not been initialized with a recovery public key yet. */ public static final int ERROR_UNINITIALIZED_RECOVERY_PUBLIC_KEY = 20; /** * Failed because no snapshot is yet pending to be synced for the user. */ public static final int ERROR_NO_SNAPSHOT_PENDING = 21; /** * Failed due to an error internal to AndroidKeyStore. */ public static final int ERROR_KEYSTORE_INTERNAL_ERROR = 22; /** * Failed because the user does not have a lock screen set. */ public static final int ERROR_INSECURE_USER = 24; /** * Failed because of an internal database error. */ public static final int ERROR_DATABASE_ERROR = 25; /** * Failed because the provided certificate was not a valid X509 certificate. */ public static final int ERROR_BAD_X509_CERTIFICATE = 26; /** * Should never be thrown - some algorithm that all AOSP implementations must support is * not available. */ public static final int ERROR_UNEXPECTED_MISSING_ALGORITHM = 27; /** * The caller is attempting to perform an operation that is not yet fully supported in the API. */ public static final int ERROR_NOT_YET_SUPPORTED = 28; /** * Error thrown if decryption failed. This might be because the tag is wrong, the key is wrong, * the data has become corrupted, the data has been tampered with, etc. */ public static final int ERROR_DECRYPTION_FAILED = 29; /** * Rate limit is enforced to prevent using too many trusted remote devices, since each device * can have its own number of user secret guesses allowed. * * @hide */ public static final int ERROR_RATE_LIMIT_EXCEEDED = 30; /** Key has been successfully synced. */ public static final int RECOVERY_STATUS_SYNCED = 0; /** Waiting for recovery agent to sync the key. */ Loading @@ -121,47 +61,6 @@ public class RecoveryManager { return new RecoveryManager(lockSettings); } /** * Exceptions returned by {@link RecoveryManager}. */ public static class RecoveryManagerException extends AndroidException { private int mErrorCode; /** * Creates new {@link #RecoveryManagerException} instance from the error code. * * @param errorCode An error code, as listed at the top of this file. * @param message The associated error message. * @hide */ public static RecoveryManagerException fromErrorCode( int errorCode, String message) { return new RecoveryManagerException(errorCode, message); } /** * Creates new {@link #RecoveryManagerException} from {@link * ServiceSpecificException}. * * @param e exception thrown on service side. * @hide */ static RecoveryManagerException fromServiceSpecificException( ServiceSpecificException e) throws RecoveryManagerException { throw RecoveryManagerException.fromErrorCode(e.errorCode, e.getMessage()); } private RecoveryManagerException(int errorCode, String message) { super(message); mErrorCode = errorCode; } /** Returns errorCode. */ public int getErrorCode() { return mErrorCode; } } /** * Initializes key recovery service for the calling application. RecoveryManager * randomly chooses one of the keys from the list and keeps it to use for future key export Loading Loading @@ -260,15 +159,14 @@ public class RecoveryManager { * {@code RecoveryData.getEncryptedRecoveryKeyBlob()}. The same value must be included * in vaultParams {@link #startRecoverySession} * * @param serverParameters included in recovery key blob. * @param serverParams included in recovery key blob. * @see #getRecoveryData * @throws RecoveryManagerException If parameters rotation is rate limited. * @hide */ public void setServerParameters(long serverParameters) throws RecoveryManagerException { public void setServerParams(byte[] serverParams) throws RecoveryManagerException { try { mBinder.setServerParameters(serverParameters); mBinder.setServerParams(serverParams); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } catch (ServiceSpecificException e) { Loading Loading @@ -309,20 +207,17 @@ public class RecoveryManager { * <li>{@link #RECOVERY_STATUS_PERMANENT_FAILURE} * </ul> * * @param packageName Application whose recoverable keys' statuses are to be retrieved. if * {@code null} caller's package will be used. * @return {@code Map} from KeyStore alias to recovery status. * @see #setRecoveryStatus * @hide */ public Map<String, Integer> getRecoveryStatus(@Nullable String packageName) public Map<String, Integer> getRecoveryStatus() throws RecoveryManagerException { try { // IPC doesn't support generic Maps. @SuppressWarnings("unchecked") Map<String, Integer> result = (Map<String, Integer>) mBinder.getRecoveryStatus(packageName); (Map<String, Integer>) mBinder.getRecoveryStatus(/*packageName=*/ null); return result; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); Loading Loading @@ -414,8 +309,9 @@ public class RecoveryManager { * return recovery key. * * @param sessionId ID for recovery session. * @param verifierPublicKey Certificate with Public key used to create the recovery blob on the * source device. Keystore will verify the certificate using root of trust. * @param verifierPublicKey Encoded {@code java.security.cert.X509Certificate} with Public key * used to create the recovery blob on the source device. * Keystore will verify the certificate using root of trust. * @param vaultParams Must match the parameters in the corresponding field in the recovery blob. * Used to limit number of guesses. * @param vaultChallenge Data passed from server for this recovery session and used to prevent Loading core/java/android/security/keystore/RecoveryManagerException.java 0 → 100644 +111 −0 Original line number Diff line number Diff line /* * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.security.keystore; import android.os.ServiceSpecificException; /** * Exception thrown by {@link RecoveryManager} methods. * * @hide */ public class RecoveryManagerException extends Exception { /** * Failed because the loader has not been initialized with a recovery public key yet. */ public static final int ERROR_UNINITIALIZED_RECOVERY_PUBLIC_KEY = 20; /** * Failed because no snapshot is yet pending to be synced for the user. */ public static final int ERROR_NO_SNAPSHOT_PENDING = 21; /** * Failed due to an error internal to AndroidKeyStore. */ public static final int ERROR_KEYSTORE_INTERNAL_ERROR = 22; /** * Failed because the user does not have a lock screen set. */ public static final int ERROR_INSECURE_USER = 24; /** * Failed because of an internal database error. */ public static final int ERROR_DATABASE_ERROR = 25; /** * Failed because the provided certificate was not a valid X509 certificate. */ public static final int ERROR_BAD_X509_CERTIFICATE = 26; /** * Should never be thrown - some algorithm that all AOSP implementations must support is * not available. */ public static final int ERROR_UNEXPECTED_MISSING_ALGORITHM = 27; /** * Error thrown if decryption failed. This might be because the tag is wrong, the key is wrong, * the data has become corrupted, the data has been tampered with, etc. */ public static final int ERROR_DECRYPTION_FAILED = 28; /** * Rate limit is enforced to prevent using too many trusted remote devices, since each device * can have its own number of user secret guesses allowed. * * @hide */ public static final int ERROR_RATE_LIMIT_EXCEEDED = 29; private int mErrorCode; /** * Creates new {@link #RecoveryManagerException} instance from the error code. * * @param errorCode An error code, as listed at the top of this file. * @param message The associated error message. * @hide */ public static RecoveryManagerException fromErrorCode( int errorCode, String message) { return new RecoveryManagerException(errorCode, message); } /** * Creates new {@link #RecoveryManagerException} from {@link * ServiceSpecificException}. * * @param e exception thrown on service side. * @hide */ static RecoveryManagerException fromServiceSpecificException( ServiceSpecificException e) throws RecoveryManagerException { throw RecoveryManagerException.fromErrorCode(e.errorCode, e.getMessage()); } private RecoveryManagerException(int errorCode, String message) { super(message); mErrorCode = errorCode; } /** Returns errorCode. */ public int getErrorCode() { return mErrorCode; } } Loading
core/java/android/security/keystore/KeyDerivationParameters.aidl→core/java/android/security/keystore/KeyDerivationParams.aidl +1 −1 Original line number Diff line number Diff line Loading @@ -17,4 +17,4 @@ package android.security.keystore; /* @hide */ parcelable KeyDerivationParameters; parcelable KeyDerivationParams;
core/java/android/security/keystore/KeyDerivationParameters.java→core/java/android/security/keystore/KeyDerivationParams.java +13 −18 Original line number Diff line number Diff line Loading @@ -28,27 +28,22 @@ import java.lang.annotation.RetentionPolicy; /** * Collection of parameters which define a key derivation function. * Supports * Currently only supports salted SHA-256 * * <ul> * <li>SHA256 * <li>Argon2id * </ul> * @hide */ public final class KeyDerivationParameters implements Parcelable { public final class KeyDerivationParams implements Parcelable { private final int mAlgorithm; private byte[] mSalt; /** @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef({ALGORITHM_SHA256, ALGORITHM_ARGON2ID}) @IntDef(prefix = {"ALGORITHM_"}, value = {ALGORITHM_SHA256, ALGORITHM_ARGON2ID}) public @interface KeyDerivationAlgorithm { } /** * Salted SHA256 * @hide */ public static final int ALGORITHM_SHA256 = 1; Loading @@ -62,11 +57,11 @@ public final class KeyDerivationParameters implements Parcelable { /** * Creates instance of the class to to derive key using salted SHA256 hash. */ public static KeyDerivationParameters createSha256Parameters(@NonNull byte[] salt) { return new KeyDerivationParameters(ALGORITHM_SHA256, salt); public static KeyDerivationParams createSha256Params(@NonNull byte[] salt) { return new KeyDerivationParams(ALGORITHM_SHA256, salt); } private KeyDerivationParameters(@KeyDerivationAlgorithm int algorithm, @NonNull byte[] salt) { private KeyDerivationParams(@KeyDerivationAlgorithm int algorithm, @NonNull byte[] salt) { mAlgorithm = algorithm; mSalt = Preconditions.checkNotNull(salt); } Loading @@ -85,14 +80,14 @@ public final class KeyDerivationParameters implements Parcelable { return mSalt; } public static final Parcelable.Creator<KeyDerivationParameters> CREATOR = new Parcelable.Creator<KeyDerivationParameters>() { public KeyDerivationParameters createFromParcel(Parcel in) { return new KeyDerivationParameters(in); public static final Parcelable.Creator<KeyDerivationParams> CREATOR = new Parcelable.Creator<KeyDerivationParams>() { public KeyDerivationParams createFromParcel(Parcel in) { return new KeyDerivationParams(in); } public KeyDerivationParameters[] newArray(int length) { return new KeyDerivationParameters[length]; public KeyDerivationParams[] newArray(int length) { return new KeyDerivationParams[length]; } }; Loading @@ -108,7 +103,7 @@ public final class KeyDerivationParameters implements Parcelable { /** * @hide */ protected KeyDerivationParameters(Parcel in) { protected KeyDerivationParams(Parcel in) { mAlgorithm = in.readInt(); mSalt = in.createByteArray(); } Loading
core/java/android/security/keystore/RecoveryData.java +1 −2 Original line number Diff line number Diff line Loading @@ -38,7 +38,7 @@ import java.util.List; * @hide */ public final class RecoveryData implements Parcelable { private Integer mSnapshotVersion; private int mSnapshotVersion; private List<RecoveryMetadata> mRecoveryMetadata; private List<EntryRecoveryData> mEntryRecoveryData; private byte[] mEncryptedRecoveryKeyBlob; Loading Loading @@ -163,7 +163,6 @@ public final class RecoveryData implements Parcelable { * @throws NullPointerException if some required fields were not set. */ public @NonNull RecoveryData build() { Preconditions.checkNotNull(mInstance.mSnapshotVersion); Preconditions.checkCollectionElementsNotNull(mInstance.mRecoveryMetadata, "recoveryMetadata"); Preconditions.checkCollectionElementsNotNull(mInstance.mEntryRecoveryData, Loading
core/java/android/security/keystore/RecoveryManager.java +8 −112 Original line number Diff line number Diff line Loading @@ -23,8 +23,6 @@ import android.content.pm.PackageManager.NameNotFoundException; import android.os.RemoteException; import android.os.ServiceManager; import android.os.ServiceSpecificException; import android.security.KeyStore; import android.util.AndroidException; import com.android.internal.widget.ILockSettings; Loading @@ -39,64 +37,6 @@ import java.util.Map; */ public class RecoveryManager { public static final int NO_ERROR = KeyStore.NO_ERROR; public static final int SYSTEM_ERROR = KeyStore.SYSTEM_ERROR; /** * Failed because the loader has not been initialized with a recovery public key yet. */ public static final int ERROR_UNINITIALIZED_RECOVERY_PUBLIC_KEY = 20; /** * Failed because no snapshot is yet pending to be synced for the user. */ public static final int ERROR_NO_SNAPSHOT_PENDING = 21; /** * Failed due to an error internal to AndroidKeyStore. */ public static final int ERROR_KEYSTORE_INTERNAL_ERROR = 22; /** * Failed because the user does not have a lock screen set. */ public static final int ERROR_INSECURE_USER = 24; /** * Failed because of an internal database error. */ public static final int ERROR_DATABASE_ERROR = 25; /** * Failed because the provided certificate was not a valid X509 certificate. */ public static final int ERROR_BAD_X509_CERTIFICATE = 26; /** * Should never be thrown - some algorithm that all AOSP implementations must support is * not available. */ public static final int ERROR_UNEXPECTED_MISSING_ALGORITHM = 27; /** * The caller is attempting to perform an operation that is not yet fully supported in the API. */ public static final int ERROR_NOT_YET_SUPPORTED = 28; /** * Error thrown if decryption failed. This might be because the tag is wrong, the key is wrong, * the data has become corrupted, the data has been tampered with, etc. */ public static final int ERROR_DECRYPTION_FAILED = 29; /** * Rate limit is enforced to prevent using too many trusted remote devices, since each device * can have its own number of user secret guesses allowed. * * @hide */ public static final int ERROR_RATE_LIMIT_EXCEEDED = 30; /** Key has been successfully synced. */ public static final int RECOVERY_STATUS_SYNCED = 0; /** Waiting for recovery agent to sync the key. */ Loading @@ -121,47 +61,6 @@ public class RecoveryManager { return new RecoveryManager(lockSettings); } /** * Exceptions returned by {@link RecoveryManager}. */ public static class RecoveryManagerException extends AndroidException { private int mErrorCode; /** * Creates new {@link #RecoveryManagerException} instance from the error code. * * @param errorCode An error code, as listed at the top of this file. * @param message The associated error message. * @hide */ public static RecoveryManagerException fromErrorCode( int errorCode, String message) { return new RecoveryManagerException(errorCode, message); } /** * Creates new {@link #RecoveryManagerException} from {@link * ServiceSpecificException}. * * @param e exception thrown on service side. * @hide */ static RecoveryManagerException fromServiceSpecificException( ServiceSpecificException e) throws RecoveryManagerException { throw RecoveryManagerException.fromErrorCode(e.errorCode, e.getMessage()); } private RecoveryManagerException(int errorCode, String message) { super(message); mErrorCode = errorCode; } /** Returns errorCode. */ public int getErrorCode() { return mErrorCode; } } /** * Initializes key recovery service for the calling application. RecoveryManager * randomly chooses one of the keys from the list and keeps it to use for future key export Loading Loading @@ -260,15 +159,14 @@ public class RecoveryManager { * {@code RecoveryData.getEncryptedRecoveryKeyBlob()}. The same value must be included * in vaultParams {@link #startRecoverySession} * * @param serverParameters included in recovery key blob. * @param serverParams included in recovery key blob. * @see #getRecoveryData * @throws RecoveryManagerException If parameters rotation is rate limited. * @hide */ public void setServerParameters(long serverParameters) throws RecoveryManagerException { public void setServerParams(byte[] serverParams) throws RecoveryManagerException { try { mBinder.setServerParameters(serverParameters); mBinder.setServerParams(serverParams); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } catch (ServiceSpecificException e) { Loading Loading @@ -309,20 +207,17 @@ public class RecoveryManager { * <li>{@link #RECOVERY_STATUS_PERMANENT_FAILURE} * </ul> * * @param packageName Application whose recoverable keys' statuses are to be retrieved. if * {@code null} caller's package will be used. * @return {@code Map} from KeyStore alias to recovery status. * @see #setRecoveryStatus * @hide */ public Map<String, Integer> getRecoveryStatus(@Nullable String packageName) public Map<String, Integer> getRecoveryStatus() throws RecoveryManagerException { try { // IPC doesn't support generic Maps. @SuppressWarnings("unchecked") Map<String, Integer> result = (Map<String, Integer>) mBinder.getRecoveryStatus(packageName); (Map<String, Integer>) mBinder.getRecoveryStatus(/*packageName=*/ null); return result; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); Loading Loading @@ -414,8 +309,9 @@ public class RecoveryManager { * return recovery key. * * @param sessionId ID for recovery session. * @param verifierPublicKey Certificate with Public key used to create the recovery blob on the * source device. Keystore will verify the certificate using root of trust. * @param verifierPublicKey Encoded {@code java.security.cert.X509Certificate} with Public key * used to create the recovery blob on the source device. * Keystore will verify the certificate using root of trust. * @param vaultParams Must match the parameters in the corresponding field in the recovery blob. * Used to limit number of guesses. * @param vaultChallenge Data passed from server for this recovery session and used to prevent Loading
core/java/android/security/keystore/RecoveryManagerException.java 0 → 100644 +111 −0 Original line number Diff line number Diff line /* * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.security.keystore; import android.os.ServiceSpecificException; /** * Exception thrown by {@link RecoveryManager} methods. * * @hide */ public class RecoveryManagerException extends Exception { /** * Failed because the loader has not been initialized with a recovery public key yet. */ public static final int ERROR_UNINITIALIZED_RECOVERY_PUBLIC_KEY = 20; /** * Failed because no snapshot is yet pending to be synced for the user. */ public static final int ERROR_NO_SNAPSHOT_PENDING = 21; /** * Failed due to an error internal to AndroidKeyStore. */ public static final int ERROR_KEYSTORE_INTERNAL_ERROR = 22; /** * Failed because the user does not have a lock screen set. */ public static final int ERROR_INSECURE_USER = 24; /** * Failed because of an internal database error. */ public static final int ERROR_DATABASE_ERROR = 25; /** * Failed because the provided certificate was not a valid X509 certificate. */ public static final int ERROR_BAD_X509_CERTIFICATE = 26; /** * Should never be thrown - some algorithm that all AOSP implementations must support is * not available. */ public static final int ERROR_UNEXPECTED_MISSING_ALGORITHM = 27; /** * Error thrown if decryption failed. This might be because the tag is wrong, the key is wrong, * the data has become corrupted, the data has been tampered with, etc. */ public static final int ERROR_DECRYPTION_FAILED = 28; /** * Rate limit is enforced to prevent using too many trusted remote devices, since each device * can have its own number of user secret guesses allowed. * * @hide */ public static final int ERROR_RATE_LIMIT_EXCEEDED = 29; private int mErrorCode; /** * Creates new {@link #RecoveryManagerException} instance from the error code. * * @param errorCode An error code, as listed at the top of this file. * @param message The associated error message. * @hide */ public static RecoveryManagerException fromErrorCode( int errorCode, String message) { return new RecoveryManagerException(errorCode, message); } /** * Creates new {@link #RecoveryManagerException} from {@link * ServiceSpecificException}. * * @param e exception thrown on service side. * @hide */ static RecoveryManagerException fromServiceSpecificException( ServiceSpecificException e) throws RecoveryManagerException { throw RecoveryManagerException.fromErrorCode(e.errorCode, e.getMessage()); } private RecoveryManagerException(int errorCode, String message) { super(message); mErrorCode = errorCode; } /** Returns errorCode. */ public int getErrorCode() { return mErrorCode; } }