diff options
Diffstat (limited to 'src/com/android/packageinstaller/InstallFlowAnalytics.java')
-rw-r--r-- | src/com/android/packageinstaller/InstallFlowAnalytics.java | 124 |
1 files changed, 115 insertions, 9 deletions
diff --git a/src/com/android/packageinstaller/InstallFlowAnalytics.java b/src/com/android/packageinstaller/InstallFlowAnalytics.java index ac8e53ac..2fc6db37 100644 --- a/src/com/android/packageinstaller/InstallFlowAnalytics.java +++ b/src/com/android/packageinstaller/InstallFlowAnalytics.java @@ -16,13 +16,27 @@ */ package com.android.packageinstaller; +import android.content.Context; import android.content.pm.PackageManager; +import android.net.Uri; +import android.os.AsyncTask; import android.os.Parcel; import android.os.Parcelable; import android.os.SystemClock; +import android.provider.Settings; import android.util.EventLog; import android.util.Log; +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +import libcore.io.IoUtils; + /** * Analytics about an attempt to install a package via {@link PackageInstallerActivity}. * @@ -125,9 +139,14 @@ public class InstallFlowAnalytics implements Parcelable { */ private long mEndTimestampMillis; + /** URI of the package being installed. */ + private String mPackageUri; + /** Whether this attempt has been logged to the Event Log. */ private boolean mLogged; + private Context mContext; + public static final Parcelable.Creator<InstallFlowAnalytics> CREATOR = new Parcelable.Creator<InstallFlowAnalytics>() { @Override @@ -151,6 +170,7 @@ public class InstallFlowAnalytics implements Parcelable { mPackageInfoObtainedTimestampMillis = in.readLong(); mInstallButtonClickTimestampMillis = in.readLong(); mEndTimestampMillis = in.readLong(); + mPackageUri = in.readString(); mLogged = readBoolean(in); } @@ -163,6 +183,7 @@ public class InstallFlowAnalytics implements Parcelable { dest.writeLong(mPackageInfoObtainedTimestampMillis); dest.writeLong(mInstallButtonClickTimestampMillis); dest.writeLong(mEndTimestampMillis); + dest.writeString(mPackageUri); writeBoolean(dest, mLogged); } @@ -179,6 +200,10 @@ public class InstallFlowAnalytics implements Parcelable { return 0; } + void setContext(Context context) { + mContext = context; + } + /** Sets whether the Unknown Sources setting is checked. */ void setInstallsFromUnknownSourcesPermitted(boolean permitted) { setFlagState(FLAG_INSTALLS_FROM_UNKNOWN_SOURCES_PERMITTED, permitted); @@ -230,6 +255,13 @@ public class InstallFlowAnalytics implements Parcelable { } /** + * Sets the URI of the package being installed. + */ + void setPackageUri(String packageUri) { + mPackageUri = packageUri; + } + + /** * Gets whether an APK file is being installed. * * @return {@code true} if an APK file is being installed, {@code false} if an already @@ -393,33 +425,65 @@ public class InstallFlowAnalytics implements Parcelable { -mPackageManagerInstallResult); } - int resultAndFlags = (mResult & 0xff) + final int resultAndFlags = (mResult & 0xff) | ((packageManagerInstallResultByte & 0xff) << 8) | ((mFlags & 0xffff) << 16); // Total elapsed time from start to end, in milliseconds. - int totalElapsedTime = + final int totalElapsedTime = clipUnsignedLongToUnsignedInt(mEndTimestampMillis - mStartTimestampMillis); // Total elapsed time from start till information about the package being installed was // obtained, in milliseconds. - int elapsedTimeTillPackageInfoObtained = (isPackageInfoObtained()) + final int elapsedTimeTillPackageInfoObtained = (isPackageInfoObtained()) ? clipUnsignedLongToUnsignedInt( mPackageInfoObtainedTimestampMillis - mStartTimestampMillis) : 0; // Total elapsed time from start till Install button clicked, in milliseconds // milliseconds. - int elapsedTimeTillInstallButtonClick = (isInstallButtonClicked()) + final int elapsedTimeTillInstallButtonClick = (isInstallButtonClicked()) ? clipUnsignedLongToUnsignedInt( mInstallButtonClickTimestampMillis - mStartTimestampMillis) : 0; - EventLogTags.writeInstallPackageAttempt( - resultAndFlags, - totalElapsedTime, - elapsedTimeTillPackageInfoObtained, - elapsedTimeTillInstallButtonClick); + // If this user has consented to app verification, augment the logged event with the hash of + // the contents of the APK. + if (((mFlags & FLAG_FILE_URI) != 0) + && ((mFlags & FLAG_VERIFY_APPS_ENABLED) != 0) + && (isUserConsentToVerifyAppsGranted())) { + // Log the hash of the APK's contents. + // Reading the APK may take a while -- perform in background. + AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() { + @Override + public void run() { + byte[] digest = null; + try { + digest = getPackageContentsDigest(); + } catch (IOException e) { + Log.w(TAG, "Failed to hash APK contents", e); + } finally { + String digestHex = (digest != null) + ? IntegralToString.bytesToHexString(digest, false) + : ""; + EventLogTags.writeInstallPackageAttempt( + resultAndFlags, + totalElapsedTime, + elapsedTimeTillPackageInfoObtained, + elapsedTimeTillInstallButtonClick, + digestHex); + } + } + }); + } else { + // Do not log the hash of the APK's contents + EventLogTags.writeInstallPackageAttempt( + resultAndFlags, + totalElapsedTime, + elapsedTimeTillPackageInfoObtained, + elapsedTimeTillInstallButtonClick, + ""); + } mLogged = true; if (Log.isLoggable(TAG, Log.VERBOSE)) { @@ -494,4 +558,46 @@ public class InstallFlowAnalytics implements Parcelable { private boolean isFlagSet(int flag) { return (mFlags & flag) == flag; } + + /** + * Checks whether the user has consented to app verification. + */ + private boolean isUserConsentToVerifyAppsGranted() { + return Settings.Secure.getInt( + mContext.getContentResolver(), + Settings.Secure.PACKAGE_VERIFIER_USER_CONSENT, 0) != 0; + } + + /** + * Gets the digest of the contents of the package being installed. + */ + private byte[] getPackageContentsDigest() throws IOException { + File file = new File(Uri.parse(mPackageUri).getPath()); + return getSha256ContentsDigest(file); + } + + /** + * Gets the SHA-256 digest of the contents of the specified file. + */ + private static byte[] getSha256ContentsDigest(File file) throws IOException { + MessageDigest digest; + try { + digest = MessageDigest.getInstance("SHA-256"); + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException("SHA-256 not available", e); + } + + byte[] buf = new byte[8192]; + InputStream in = null; + try { + in = new BufferedInputStream(new FileInputStream(file), buf.length); + int chunkSize; + while ((chunkSize = in.read(buf)) != -1) { + digest.update(buf, 0, chunkSize); + } + } finally { + IoUtils.closeQuietly(in); + } + return digest.digest(); + } }
\ No newline at end of file |