summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Klyubin <klyubin@google.com>2013-10-10 11:33:00 -0700
committerAlex Klyubin <klyubin@google.com>2013-10-18 13:38:21 -0700
commit2e4190fa43186b69e08d2fcc138cfd99686ae10a (patch)
tree96fa360e663317570f439a984f193c870c007231
parent37f3823699812908485a4d9a63828e6c09276bf1 (diff)
downloadandroid_packages_apps_PackageInstaller-2e4190fa43186b69e08d2fcc138cfd99686ae10a.zip
android_packages_apps_PackageInstaller-2e4190fa43186b69e08d2fcc138cfd99686ae10a.tar.gz
android_packages_apps_PackageInstaller-2e4190fa43186b69e08d2fcc138cfd99686ae10a.tar.bz2
Log APK hash for package install attempts in the Event Log.
This CL adds a package_digest field to the install_package_attempt event. The field is populated with the SHA-256 digest of the contents of the APK iff the user has consented to app verification and app verification is enabled. Bug: 11275004 Bug: 10605940 (cherry picked from commit 8fca480bee00578c1529b1f32ab30af096db82dd) Change-Id: I9773925f7e397ada26efac022349dc8e4af01208
-rw-r--r--src/com/android/packageinstaller/EventLogTags.logtags2
-rwxr-xr-xsrc/com/android/packageinstaller/InstallAppProgress.java1
-rw-r--r--src/com/android/packageinstaller/InstallFlowAnalytics.java124
-rw-r--r--src/com/android/packageinstaller/PackageInstallerActivity.java4
4 files changed, 119 insertions, 12 deletions
diff --git a/src/com/android/packageinstaller/EventLogTags.logtags b/src/com/android/packageinstaller/EventLogTags.logtags
index 0183148..8cbb1cc 100644
--- a/src/com/android/packageinstaller/EventLogTags.logtags
+++ b/src/com/android/packageinstaller/EventLogTags.logtags
@@ -3,4 +3,4 @@
option java_package com.android.packageinstaller
# APK install attempt via PackageInstaller (see InstallFlowAnalytics for format)
-90300 install_package_attempt (result_and_flags|1),(total_time|1|3),(time_till_pkg_info_obtained|1|3),(time_till_install_clicked|1|3)
+90300 install_package_attempt (result_and_flags|1),(total_time|1|3),(time_till_pkg_info_obtained|1|3),(time_till_install_clicked|1|3),(package_digest|3)
diff --git a/src/com/android/packageinstaller/InstallAppProgress.java b/src/com/android/packageinstaller/InstallAppProgress.java
index 83e4aa7..c8e4133 100755
--- a/src/com/android/packageinstaller/InstallAppProgress.java
+++ b/src/com/android/packageinstaller/InstallAppProgress.java
@@ -169,6 +169,7 @@ public class InstallAppProgress extends Activity implements View.OnClickListener
Intent intent = getIntent();
mAppInfo = intent.getParcelableExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO);
mInstallFlowAnalytics = intent.getParcelableExtra(EXTRA_INSTALL_FLOW_ANALYTICS);
+ mInstallFlowAnalytics.setContext(this);
mPackageURI = intent.getData();
final String scheme = mPackageURI.getScheme();
diff --git a/src/com/android/packageinstaller/InstallFlowAnalytics.java b/src/com/android/packageinstaller/InstallFlowAnalytics.java
index ac8e53a..2fc6db3 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
diff --git a/src/com/android/packageinstaller/PackageInstallerActivity.java b/src/com/android/packageinstaller/PackageInstallerActivity.java
index a08e792..a11e11e 100644
--- a/src/com/android/packageinstaller/PackageInstallerActivity.java
+++ b/src/com/android/packageinstaller/PackageInstallerActivity.java
@@ -39,7 +39,6 @@ import android.os.Bundle;
import android.os.SystemClock;
import android.provider.Settings;
import android.support.v4.view.ViewPager;
-import android.util.EventLog;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
@@ -51,7 +50,6 @@ import android.widget.TabHost;
import android.widget.TextView;
import java.io.File;
-import java.io.Serializable;
import java.util.List;
/*
@@ -422,12 +420,14 @@ public class PackageInstallerActivity extends Activity implements OnCancelListen
boolean requestFromUnknownSource = isInstallRequestFromUnknownSource(intent);
mInstallFlowAnalytics = new InstallFlowAnalytics();
+ mInstallFlowAnalytics.setContext(this);
mInstallFlowAnalytics.setStartTimestampMillis(SystemClock.elapsedRealtime());
mInstallFlowAnalytics.setInstallsFromUnknownSourcesPermitted(
isInstallingUnknownAppsAllowed());
mInstallFlowAnalytics.setInstallRequestFromUnknownSource(requestFromUnknownSource);
mInstallFlowAnalytics.setVerifyAppsEnabled(isVerifyAppsEnabled());
mInstallFlowAnalytics.setAppVerifierInstalled(isAppVerifierInstalled());
+ mInstallFlowAnalytics.setPackageUri(mPackageURI.toString());
final String scheme = mPackageURI.getScheme();
if (scheme != null && !"file".equals(scheme) && !"package".equals(scheme)) {