/* * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.view.displayhash; import android.annotation.CurrentTimeMillisLong; 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.AnnotationValidations; /** * The DisplayHash used to validate information about what was present on screen. */ public final class DisplayHash implements Parcelable { /** * The timestamp when the hash was generated. */ @CurrentTimeMillisLong private final long mTimeMillis; /** * The bounds of the requested area to generate the hash. This is in window space passed in * by the client. */ @NonNull private final Rect mBoundsInWindow; /** * The selected hash algorithm that generated the image hash. */ @NonNull private final String mHashAlgorithm; /** * The image hash generated when creating the DisplayHash. */ @NonNull private final byte[] mImageHash; /** * The hmac generated by the system and used to verify whether this token was generated by * the system. */ @NonNull private final byte[] mHmac; /** * Creates a new DisplayHash. * * @param timeMillis The timestamp when the hash was generated. * @param boundsInWindow The bounds of the requested area to generate the hash. This is * in window space passed in by the client. * @param hashAlgorithm The selected hash algorithm that generated the image hash. * @param imageHash The image hash generated when creating the DisplayHash. * @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. * @hide */ @SystemApi public DisplayHash(@CurrentTimeMillisLong long timeMillis, @NonNull Rect boundsInWindow, @NonNull String hashAlgorithm, @NonNull byte[] imageHash, @NonNull byte[] hmac) { mTimeMillis = timeMillis; mBoundsInWindow = boundsInWindow; AnnotationValidations.validate(NonNull.class, null, mBoundsInWindow); mHashAlgorithm = hashAlgorithm; AnnotationValidations.validate(NonNull.class, null, mHashAlgorithm); mImageHash = imageHash; AnnotationValidations.validate(NonNull.class, null, mImageHash); mHmac = hmac; AnnotationValidations.validate(NonNull.class, null, mHmac); } /** * The timestamp when the hash was generated. * * @hide */ @SystemApi @CurrentTimeMillisLong public long getTimeMillis() { return mTimeMillis; } /** * The bounds of the requested area to to generate the hash. This is in window space passed in * by the client. * * @hide */ @SystemApi @NonNull public Rect getBoundsInWindow() { return mBoundsInWindow; } /** * The selected hash algorithm that generated the image hash. * * @hide */ @SystemApi @NonNull public String getHashAlgorithm() { return mHashAlgorithm; } /** * The image hash generated when creating the DisplayHash. * * @hide */ @SystemApi @NonNull public byte[] getImageHash() { return 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. * * @hide */ @SystemApi @NonNull public byte[] getHmac() { return mHmac; } /** @hide **/ @Override public String toString() { return "DisplayHash { " + "timeMillis = " + mTimeMillis + ", " + "boundsInWindow = " + mBoundsInWindow + ", " + "hashAlgorithm = " + mHashAlgorithm + ", " + "imageHash = " + byteArrayToString(mImageHash) + ", " + "hmac = " + byteArrayToString(mHmac) + " }"; } private String byteArrayToString(byte[] byteArray) { if (byteArray == null) { return "null"; } int iMax = byteArray.length - 1; if (iMax == -1) { return "[]"; } StringBuilder b = new StringBuilder(); b.append('['); for (int i = 0; ; i++) { String formatted = String.format("%02X", byteArray[i] & 0xFF); b.append(formatted); if (i == iMax) { return b.append(']').toString(); } b.append(", "); } } /** @hide **/ @SystemApi @Override public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeLong(mTimeMillis); dest.writeTypedObject(mBoundsInWindow, flags); dest.writeString(mHashAlgorithm); dest.writeByteArray(mImageHash); dest.writeByteArray(mHmac); } /** @hide **/ @SystemApi @Override public int describeContents() { return 0; } private DisplayHash(@NonNull Parcel in) { mTimeMillis = in.readLong(); Rect boundsInWindow = in.readTypedObject(Rect.CREATOR); String hashAlgorithm = in.readString(); byte[] imageHash = in.createByteArray(); byte[] hmac = in.createByteArray(); mBoundsInWindow = boundsInWindow; AnnotationValidations.validate(NonNull.class, null, mBoundsInWindow); mHashAlgorithm = hashAlgorithm; AnnotationValidations.validate(NonNull.class, null, mHashAlgorithm); mImageHash = imageHash; AnnotationValidations.validate(NonNull.class, null, mImageHash); mHmac = hmac; AnnotationValidations.validate(NonNull.class, null, mHmac); } @NonNull public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { @Override public DisplayHash[] newArray(int size) { return new DisplayHash[size]; } @Override public DisplayHash createFromParcel(@NonNull Parcel in) { return new DisplayHash(in); } }; }