| Index: base/android/java/src/org/chromium/base/ResourceExtractor.java
|
| diff --git a/base/android/java/src/org/chromium/base/ResourceExtractor.java b/base/android/java/src/org/chromium/base/ResourceExtractor.java
|
| index 458e266b48c98f15e8d4d559058ec9312a663e2d..78c85de3c05676ca5cea0a9b6432d05b58bdee38 100644
|
| --- a/base/android/java/src/org/chromium/base/ResourceExtractor.java
|
| +++ b/base/android/java/src/org/chromium/base/ResourceExtractor.java
|
| @@ -6,6 +6,7 @@ package org.chromium.base;
|
|
|
| import android.annotation.TargetApi;
|
| import android.content.Context;
|
| +import android.content.SharedPreferences;
|
| import android.content.pm.PackageInfo;
|
| import android.content.pm.PackageManager;
|
| import android.os.AsyncTask;
|
| @@ -13,12 +14,12 @@ import android.os.Build;
|
| import android.os.Handler;
|
| import android.os.Looper;
|
| import android.os.Trace;
|
| +import android.preference.PreferenceManager;
|
|
|
| import org.chromium.base.annotations.SuppressFBWarnings;
|
|
|
| import java.io.File;
|
| import java.io.FileOutputStream;
|
| -import java.io.FilenameFilter;
|
| import java.io.IOException;
|
| import java.io.InputStream;
|
| import java.io.OutputStream;
|
| @@ -26,6 +27,8 @@ import java.util.ArrayList;
|
| import java.util.List;
|
| import java.util.concurrent.CancellationException;
|
| import java.util.concurrent.ExecutionException;
|
| +import java.util.zip.ZipEntry;
|
| +import java.util.zip.ZipFile;
|
|
|
| /**
|
| * Handles extracting the necessary resources bundled in an APK and moving them to a location on
|
| @@ -37,6 +40,7 @@ public class ResourceExtractor {
|
| private static final String ICU_DATA_FILENAME = "icudtl.dat";
|
| private static final String V8_NATIVES_DATA_FILENAME = "natives_blob.bin";
|
| private static final String V8_SNAPSHOT_DATA_FILENAME = "snapshot_blob.bin";
|
| + private static final String APP_VERSION_PREF = "org.chromium.base.ResourceExtractor.Version";
|
|
|
| private static ResourceEntry[] sResourcesToExtract = new ResourceEntry[0];
|
|
|
| @@ -71,21 +75,15 @@ public class ResourceExtractor {
|
| while ((count = is.read(buffer, 0, BUFFER_SIZE)) != -1) {
|
| os.write(buffer, 0, count);
|
| }
|
| - os.flush();
|
| -
|
| - // Ensure something reasonable was written.
|
| - if (outFile.length() == 0) {
|
| - throw new IOException(outFile + " extracted with 0 length!");
|
| - }
|
| } finally {
|
| try {
|
| - if (is != null) {
|
| - is.close();
|
| - }
|
| - } finally {
|
| if (os != null) {
|
| os.close();
|
| }
|
| + } finally {
|
| + if (is != null) {
|
| + is.close();
|
| + }
|
| }
|
| }
|
| }
|
| @@ -97,24 +95,30 @@ public class ResourceExtractor {
|
| return;
|
| }
|
|
|
| - String timestampFile = null;
|
| beginTraceSection("checkPakTimeStamp");
|
| - try {
|
| - timestampFile = checkPakTimestamp(outputDir);
|
| - } finally {
|
| - endTraceSection();
|
| - }
|
| - if (timestampFile != null) {
|
| + long curAppVersion = getApplicationVersion();
|
| + SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(
|
| + mContext.getApplicationContext());
|
| + long prevAppVersion = sharedPrefs.getLong(APP_VERSION_PREF, 0);
|
| + boolean versionChanged = curAppVersion != prevAppVersion;
|
| + endTraceSection();
|
| +
|
| + if (versionChanged) {
|
| deleteFiles();
|
| + // Use the version only to see if files should be deleted, not to skip extraction.
|
| + // We've seen files be corrupted, so always attempt extraction.
|
| + // http://crbug.com/606413
|
| + sharedPrefs.edit().putLong(APP_VERSION_PREF, curAppVersion).apply();
|
| }
|
|
|
| beginTraceSection("WalkAssets");
|
| byte[] buffer = new byte[BUFFER_SIZE];
|
| try {
|
| - // Extract all files that don't already exist.
|
| for (ResourceEntry entry : sResourcesToExtract) {
|
| File output = new File(outputDir, entry.extractedFileName);
|
| - if (output.exists()) {
|
| + // TODO(agrieve): It would be better to check that .length == expectedLength.
|
| + // http://crbug.com/606413
|
| + if (output.length() != 0) {
|
| continue;
|
| }
|
| beginTraceSection("ExtractResource");
|
| @@ -137,17 +141,6 @@ public class ResourceExtractor {
|
| } finally {
|
| endTraceSection(); // WalkAssets
|
| }
|
| -
|
| - // Finished, write out a timestamp file if we need to.
|
| - if (timestampFile != null) {
|
| - try {
|
| - new File(outputDir, timestampFile).createNewFile();
|
| - } catch (IOException e) {
|
| - // Worst case we don't write a timestamp, so we'll re-extract the resource
|
| - // paks next start up.
|
| - Log.w(TAG, "Failed to write resource pak timestamp!");
|
| - }
|
| - }
|
| }
|
|
|
| @Override
|
| @@ -189,42 +182,25 @@ public class ResourceExtractor {
|
| // Note that we do this to avoid adding a BroadcastReceiver on
|
| // android.content.Intent#ACTION_PACKAGE_CHANGED as that causes process churn
|
| // on (re)installation of *all* APK files.
|
| - private String checkPakTimestamp(File outputDir) {
|
| - final String timestampPrefix = "pak_timestamp-";
|
| + private long getApplicationVersion() {
|
| PackageManager pm = mContext.getPackageManager();
|
| - PackageInfo pi = null;
|
| -
|
| try {
|
| - pi = pm.getPackageInfo(mContext.getPackageName(), 0);
|
| - } catch (PackageManager.NameNotFoundException e) {
|
| - return timestampPrefix;
|
| - }
|
| -
|
| - if (pi == null) {
|
| - return timestampPrefix;
|
| - }
|
| -
|
| - String expectedTimestamp = timestampPrefix + pi.versionCode + "-" + pi.lastUpdateTime;
|
| -
|
| - String[] timestamps = outputDir.list(new FilenameFilter() {
|
| - @Override
|
| - public boolean accept(File dir, String name) {
|
| - return name.startsWith(timestampPrefix);
|
| + PackageInfo pi = pm.getPackageInfo(mContext.getPackageName(), 0);
|
| + if (pi != null && pi.versionCode > 1) {
|
| + return pi.versionCode;
|
| }
|
| - });
|
| -
|
| - if (timestamps == null || timestamps.length != 1) {
|
| - // If there's no timestamp, nuke to be safe as we can't tell the age of the files.
|
| - // If there's multiple timestamps, something's gone wrong so nuke.
|
| - return expectedTimestamp;
|
| + } catch (PackageManager.NameNotFoundException e) {
|
| + throw new RuntimeException(e);
|
| }
|
| -
|
| - if (!expectedTimestamp.equals(timestamps[0])) {
|
| - return expectedTimestamp;
|
| + // For dev builds, use the APK's CRC-32.
|
| + try {
|
| + ZipFile apk = new ZipFile(mContext.getApplicationInfo().sourceDir);
|
| + ZipEntry manifestEntry = apk.getEntry("META-INF/MANIFEST.MF");
|
| + apk.close();
|
| + return manifestEntry.getCrc();
|
| + } catch (IOException e) {
|
| + throw new RuntimeException(e);
|
| }
|
| -
|
| - // timestamp file is already up-to date.
|
| - return null;
|
| }
|
|
|
| @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
|
|
|