diff options
| author | 2020-10-28 10:33:04 -0700 | |
|---|---|---|
| committer | 2020-11-04 17:44:19 -0800 | |
| commit | 4ecd43d5ce825673e0594d0761808745d863344e (patch) | |
| tree | ab533249473b2d4569360d59d02135221a5554bc | |
| parent | c0850b8e6d6e5f14c5775d885a04ebef02b5f9aa (diff) | |
Initial commit for ImpressionAttestationService
Created an ImpressionAttesationService AIDL interface and implemented
the methods that are needed for the ExtServices module.
Test: Builds
Bug: 155825630
CTS-Coverage-Bug: 171926232
Change-Id: Id4b359d3daa72cf0548d8254cacae313f34ac763
| -rw-r--r-- | api/system-current.txt | 26 | ||||
| -rw-r--r-- | core/api/system-current.txt | 26 | ||||
| -rw-r--r-- | core/java/android/service/attestation/IImpressionAttestationService.aidl | 52 | ||||
| -rw-r--r-- | core/java/android/service/attestation/ImpressionAttestationService.java | 152 | ||||
| -rw-r--r-- | core/java/android/service/attestation/ImpressionToken.aidl | 19 | ||||
| -rw-r--r-- | core/java/android/service/attestation/ImpressionToken.java | 250 | ||||
| -rw-r--r-- | core/res/AndroidManifest.xml | 7 |
7 files changed, 532 insertions, 0 deletions
diff --git a/api/system-current.txt b/api/system-current.txt index 87f3f4c65520..f8d5a19d64b7 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -10025,6 +10025,32 @@ package android.service.attention { } +package android.service.attestation { + + public abstract class ImpressionAttestationService extends android.app.Service { + ctor public ImpressionAttestationService(); + method @NonNull public final android.os.IBinder onBind(@NonNull android.content.Intent); + method @Nullable public abstract android.service.attestation.ImpressionToken onGenerateImpressionToken(@NonNull android.hardware.HardwareBuffer, @NonNull android.graphics.Rect, @NonNull String); + method public abstract int onVerifyImpressionToken(@NonNull android.service.attestation.ImpressionToken); + field public static final int VERIFICATION_STATUS_APP_DECLARED = 2; // 0x2 + field public static final int VERIFICATION_STATUS_OS_VERIFIED = 1; // 0x1 + field public static final int VERIFICATION_STATUS_UNKNOWN = 0; // 0x0 + } + + public final class ImpressionToken implements android.os.Parcelable { + ctor public ImpressionToken(long, @NonNull android.graphics.Rect, @NonNull String, @NonNull byte[], @NonNull byte[]); + method public int describeContents(); + method @NonNull public android.graphics.Rect getBoundsInWindow(); + method @NonNull public String getHashingAlgorithm(); + method @NonNull public byte[] getHmac(); + method @NonNull public byte[] getImageHash(); + method public long getScreenshotTimeMillis(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.service.attestation.ImpressionToken> CREATOR; + } + +} + package android.service.autofill { public abstract class AutofillFieldClassificationService extends android.app.Service { diff --git a/core/api/system-current.txt b/core/api/system-current.txt index eea50be6da1d..7aafd4165569 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -8872,6 +8872,32 @@ package android.service.attention { } +package android.service.attestation { + + public abstract class ImpressionAttestationService extends android.app.Service { + ctor public ImpressionAttestationService(); + method @NonNull public final android.os.IBinder onBind(@NonNull android.content.Intent); + method @Nullable public abstract android.service.attestation.ImpressionToken onGenerateImpressionToken(@NonNull android.hardware.HardwareBuffer, @NonNull android.graphics.Rect, @NonNull String); + method public abstract int onVerifyImpressionToken(@NonNull android.service.attestation.ImpressionToken); + field public static final int VERIFICATION_STATUS_APP_DECLARED = 2; // 0x2 + field public static final int VERIFICATION_STATUS_OS_VERIFIED = 1; // 0x1 + field public static final int VERIFICATION_STATUS_UNKNOWN = 0; // 0x0 + } + + public final class ImpressionToken implements android.os.Parcelable { + ctor public ImpressionToken(long, @NonNull android.graphics.Rect, @NonNull String, @NonNull byte[], @NonNull byte[]); + method public int describeContents(); + method @NonNull public android.graphics.Rect getBoundsInWindow(); + method @NonNull public String getHashingAlgorithm(); + method @NonNull public byte[] getHmac(); + method @NonNull public byte[] getImageHash(); + method public long getScreenshotTimeMillis(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.service.attestation.ImpressionToken> CREATOR; + } + +} + package android.service.autofill { public abstract class AutofillFieldClassificationService extends android.app.Service { diff --git a/core/java/android/service/attestation/IImpressionAttestationService.aidl b/core/java/android/service/attestation/IImpressionAttestationService.aidl new file mode 100644 index 000000000000..8e858b8aea77 --- /dev/null +++ b/core/java/android/service/attestation/IImpressionAttestationService.aidl @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2020 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.service.attestation; + +import android.graphics.Rect; +import android.hardware.HardwareBuffer; +import android.service.attestation.ImpressionToken; +import android.os.RemoteCallback; + +/** + * Service used to handle impression attestation requests. + * + * @hide + */ +oneway interface IImpressionAttestationService { + /** + * Generates the impression token that can be used to validate that the system generated the + * token. + * + * @param screenshot The token for the window where the view is shown. + * @param bounds The size and position of the content being attested in the window. + * @param hashAlgorithm The String for the hashing algorithm to use based on values in + * {@link #SERVICE_META_DATA_KEY_AVAILABLE_ALGORITHMS}. + * @param Callback The callback invoked to send back the impression token. + */ + void generateImpressionToken(in HardwareBuffer screenshot, in Rect bounds, + in String hashAlgorithm, in RemoteCallback callback); + + /** + * Call to verify that the impressionToken passed in was generated by the system. The result + * will be sent in the callback as an integer with the key {@link #EXTRA_VERIFICATION_STATUS} + * and will be one of the values in {@link VerificationStatus}. + * + * @param impressionToken The token to verify that it was generated by the system. + * @param callback The callback invoked to send back the verification status. + */ + void verifyImpressionToken(in ImpressionToken impressionToken, in RemoteCallback callback); +} diff --git a/core/java/android/service/attestation/ImpressionAttestationService.java b/core/java/android/service/attestation/ImpressionAttestationService.java new file mode 100644 index 000000000000..4919f5d8856f --- /dev/null +++ b/core/java/android/service/attestation/ImpressionAttestationService.java @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2020 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.service.attestation; + +import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.app.Service; +import android.content.Intent; +import android.graphics.Rect; +import android.hardware.HardwareBuffer; +import android.os.Bundle; +import android.os.Handler; +import android.os.IBinder; +import android.os.Looper; +import android.os.RemoteCallback; + +/** + * A service that handles generating and verify ImpressionTokens. + * + * The service will generate an ImpressionToken based on arguments passed in. Then later that same + * ImpressionToken can be verified to determine that it was created by the system. + * + * @hide + */ +@SystemApi +public abstract class ImpressionAttestationService extends Service { + /** @hide **/ + public static final String EXTRA_IMPRESSION_TOKEN = + "android.service.attestation.extra.IMPRESSION_TOKEN"; + + /** @hide **/ + public static final String EXTRA_VERIFICATION_STATUS = + "android.service.attestation.extra.VERIFICATION_STATUS"; + + /** @hide */ + @IntDef(prefix = {"VERIFICATION_STATUS_"}, value = { + VERIFICATION_STATUS_UNKNOWN, + VERIFICATION_STATUS_OS_VERIFIED, + VERIFICATION_STATUS_APP_DECLARED + }) + public @interface VerificationStatus { + } + + public static final int VERIFICATION_STATUS_UNKNOWN = 0; + public static final int VERIFICATION_STATUS_OS_VERIFIED = 1; + public static final int VERIFICATION_STATUS_APP_DECLARED = 2; + + /** + * Manifest metadata key for the resource string array containing the names of all impression + * attestation algorithms provided by the service. + * @hide + */ + public static final String SERVICE_META_DATA_KEY_AVAILABLE_ALGORITHMS = + "android.attestation.available_algorithms"; + + private ImpressionAttestationServiceWrapper mWrapper; + private Handler mHandler; + + public ImpressionAttestationService() { + } + + @Override + public void onCreate() { + super.onCreate(); + mWrapper = new ImpressionAttestationServiceWrapper(); + mHandler = new Handler(Looper.getMainLooper(), null, true); + } + + @NonNull + @Override + public final IBinder onBind(@NonNull Intent intent) { + return mWrapper; + } + + /** + * Generates the impression token that can be used to validate that the system + * generated the token. + * + * @param screenshot The screenshot buffer for the content to attest. + * @param bounds The size and position of the content being attested in the window. + * @param hashAlgorithm The String for the hashing algorithm to use based values in + * {@link #SERVICE_META_DATA_KEY_AVAILABLE_ALGORITHMS)}. + * @return An impression token that can be used to validate information about the content. + * Returns null when the arguments sent are invalid. + */ + @Nullable + public abstract ImpressionToken onGenerateImpressionToken(@NonNull HardwareBuffer screenshot, + @NonNull Rect bounds, @NonNull String hashAlgorithm); + + /** + * Call to verify that the impressionToken passed in was generated by the system. + * + * @param impressionToken The token to verify that it was generated by the system. + * @return A {@link VerificationStatus} about whether the token was generated by the system. + */ + public abstract @VerificationStatus int onVerifyImpressionToken( + @NonNull ImpressionToken impressionToken); + + private void generateImpressionToken(HardwareBuffer screenshot, Rect bounds, + String hashAlgorithm, RemoteCallback callback) { + ImpressionToken impressionToken = onGenerateImpressionToken(screenshot, bounds, + hashAlgorithm); + final Bundle data = new Bundle(); + data.putParcelable(EXTRA_IMPRESSION_TOKEN, impressionToken); + callback.sendResult(data); + } + + private void verifyImpressionToken(ImpressionToken impressionToken, + RemoteCallback callback) { + @VerificationStatus int verificationStatus = onVerifyImpressionToken(impressionToken); + final Bundle data = new Bundle(); + data.putInt(EXTRA_VERIFICATION_STATUS, verificationStatus); + callback.sendResult(data); + } + + private final class ImpressionAttestationServiceWrapper extends + IImpressionAttestationService.Stub { + @Override + public void generateImpressionToken(HardwareBuffer screenshot, Rect bounds, + String hashAlgorithm, RemoteCallback callback) { + mHandler.sendMessage( + obtainMessage(ImpressionAttestationService::generateImpressionToken, + ImpressionAttestationService.this, screenshot, bounds, hashAlgorithm, + callback)); + } + + @Override + public void verifyImpressionToken(ImpressionToken impressionToken, + RemoteCallback callback) { + mHandler.sendMessage(obtainMessage(ImpressionAttestationService::verifyImpressionToken, + ImpressionAttestationService.this, impressionToken, callback)); + } + } +} diff --git a/core/java/android/service/attestation/ImpressionToken.aidl b/core/java/android/service/attestation/ImpressionToken.aidl new file mode 100644 index 000000000000..284a4ba68a06 --- /dev/null +++ b/core/java/android/service/attestation/ImpressionToken.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2020 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.service.attestation; + +parcelable ImpressionToken;
\ No newline at end of file diff --git a/core/java/android/service/attestation/ImpressionToken.java b/core/java/android/service/attestation/ImpressionToken.java new file mode 100644 index 000000000000..4355dc04462a --- /dev/null +++ b/core/java/android/service/attestation/ImpressionToken.java @@ -0,0 +1,250 @@ +/* + * Copyright (C) 2020 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.service.attestation; + +import android.annotation.NonNull; +import android.annotation.SystemApi; +import android.graphics.Rect; +import android.os.Parcel; +import android.os.Parcelable; + +import com.android.internal.util.DataClass; + +/** + * The ads impression token used to validate information about what was present on screen. + * @hide + * + * TODO: Remove hide and SystemAPI since this will be a public class + */ +@SystemApi +@DataClass(genToString = true, genAidl = true) +public final class ImpressionToken implements Parcelable { + /** + * The timestamp when the screenshot was generated. + */ + private final long mScreenshotTimeMillis; + + /** + * The bounds of the requested area to take the screenshot. This is in window space passed in + * by the client. + */ + private @NonNull final Rect mBoundsInWindow; + + /** + * The selected hashing algorithm that generated the image hash. + */ + private @NonNull final String mHashingAlgorithm; + + /** + * The image hash generated when creating the impression token from the screenshot taken. + */ + private @NonNull final byte[] mImageHash; + + /** + * The hmac generated by the system and used to verify whether this token was generated by + * the system. This should only be accessed by a system process. + */ + private @NonNull final byte[] mHmac; + + /** + * The hmac generated by the system and used to verify whether this token was generated by + * the system. This should only be accessed by a system process. + * + * @hide + */ + @SystemApi + public @NonNull byte[] getHmac() { + return mHmac; + } + + + + // Code below generated by codegen v1.0.18. + // + // DO NOT MODIFY! + // CHECKSTYLE:OFF Generated code + // + // To regenerate run: + // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/service/attestation/ImpressionToken.java + // + // To exclude the generated code from IntelliJ auto-formatting enable (one-time): + // Settings > Editor > Code Style > Formatter Control + //@formatter:off + + + /** + * Creates a new ImpressionToken. + * + * @param screenshotTimeMillis + * The timestamp when the screenshot was generated. + * @param boundsInWindow + * The bounds of the requested area to take the screenshot. This is in window space passed in + * by the client. + * @param hashingAlgorithm + * The selected hashing algorithm that generated the image hash. + * @param imageHash + * The image hash generated when creating the impression token from the screenshot taken. + * @param hmac + * The hmac generated by the system and used to verify whether this token was generated by + * the system. This should only be accessed by a system process. + */ + @DataClass.Generated.Member + public ImpressionToken( + long screenshotTimeMillis, + @NonNull Rect boundsInWindow, + @NonNull String hashingAlgorithm, + @NonNull byte[] imageHash, + @NonNull byte[] hmac) { + this.mScreenshotTimeMillis = screenshotTimeMillis; + this.mBoundsInWindow = boundsInWindow; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mBoundsInWindow); + this.mHashingAlgorithm = hashingAlgorithm; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mHashingAlgorithm); + this.mImageHash = imageHash; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mImageHash); + this.mHmac = hmac; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mHmac); + + // onConstructed(); // You can define this method to get a callback + } + + /** + * The timestamp when the screenshot was generated. + */ + @DataClass.Generated.Member + public long getScreenshotTimeMillis() { + return mScreenshotTimeMillis; + } + + /** + * The bounds of the requested area to take the screenshot. This is in window space passed in + * by the client. + */ + @DataClass.Generated.Member + public @NonNull Rect getBoundsInWindow() { + return mBoundsInWindow; + } + + /** + * The selected hashing algorithm that generated the image hash. + */ + @DataClass.Generated.Member + public @NonNull String getHashingAlgorithm() { + return mHashingAlgorithm; + } + + /** + * The image hash generated when creating the impression token from the screenshot taken. + */ + @DataClass.Generated.Member + public @NonNull byte[] getImageHash() { + return mImageHash; + } + + @Override + @DataClass.Generated.Member + public String toString() { + // You can override field toString logic by defining methods like: + // String fieldNameToString() { ... } + + return "ImpressionToken { " + + "screenshotTimeMillis = " + mScreenshotTimeMillis + ", " + + "boundsInWindow = " + mBoundsInWindow + ", " + + "hashingAlgorithm = " + mHashingAlgorithm + ", " + + "imageHash = " + java.util.Arrays.toString(mImageHash) + ", " + + "hmac = " + java.util.Arrays.toString(mHmac) + + " }"; + } + + @Override + @DataClass.Generated.Member + public void writeToParcel(@NonNull Parcel dest, int flags) { + // You can override field parcelling by defining methods like: + // void parcelFieldName(Parcel dest, int flags) { ... } + + dest.writeLong(mScreenshotTimeMillis); + dest.writeTypedObject(mBoundsInWindow, flags); + dest.writeString(mHashingAlgorithm); + dest.writeByteArray(mImageHash); + dest.writeByteArray(mHmac); + } + + @Override + @DataClass.Generated.Member + public int describeContents() { return 0; } + + /** @hide */ + @SuppressWarnings({"unchecked", "RedundantCast"}) + @DataClass.Generated.Member + /* package-private */ ImpressionToken(@NonNull Parcel in) { + // You can override field unparcelling by defining methods like: + // static FieldType unparcelFieldName(Parcel in) { ... } + + long screenshotTimeMillis = in.readLong(); + Rect boundsInWindow = (Rect) in.readTypedObject(Rect.CREATOR); + String hashingAlgorithm = in.readString(); + byte[] imageHash = in.createByteArray(); + byte[] hmac = in.createByteArray(); + + this.mScreenshotTimeMillis = screenshotTimeMillis; + this.mBoundsInWindow = boundsInWindow; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mBoundsInWindow); + this.mHashingAlgorithm = hashingAlgorithm; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mHashingAlgorithm); + this.mImageHash = imageHash; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mImageHash); + this.mHmac = hmac; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mHmac); + + // onConstructed(); // You can define this method to get a callback + } + + @DataClass.Generated.Member + public static final @NonNull Parcelable.Creator<ImpressionToken> CREATOR + = new Parcelable.Creator<ImpressionToken>() { + @Override + public ImpressionToken[] newArray(int size) { + return new ImpressionToken[size]; + } + + @Override + public ImpressionToken createFromParcel(@NonNull Parcel in) { + return new ImpressionToken(in); + } + }; + + @DataClass.Generated( + time = 1604539951959L, + codegenVersion = "1.0.18", + sourceFile = "frameworks/base/core/java/android/service/attestation/ImpressionToken.java", + inputSignatures = "private final long mScreenshotTimeMillis\nprivate final @android.annotation.NonNull android.graphics.Rect mBoundsInWindow\nprivate final @android.annotation.NonNull java.lang.String mHashingAlgorithm\nprivate final @android.annotation.NonNull byte[] mImageHash\nprivate final @android.annotation.NonNull byte[] mHmac\npublic @android.annotation.SystemApi @android.annotation.NonNull byte[] getHmac()\nclass ImpressionToken extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genAidl=true)") + @Deprecated + private void __metadata() {} + + + //@formatter:on + // End of generated code + +} diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 4df7d589d707..7f8526e97a13 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -5167,6 +5167,13 @@ <permission android:name="android.permission.CONTROL_DEVICE_STATE" android:protectionLevel="signature" /> + <!-- Must be required by an {@link android.service.attestation.ImpressionAttestationService} + to ensure that only the system can bind to it. + @hide This is not a third-party API (intended for OEMs and system apps). + --> + <permission android:name="android.permission.BIND_IMPRESSION_ATTESTATION_SERVICE" + android:protectionLevel="signature" /> + <!-- Attribution for Geofencing service. --> <attribution android:tag="GeofencingService" android:label="@string/geofencing_service"/> <!-- Attribution for Country Detector. --> |