| Index: mojo/runner/android/apk/src/org/chromium/mojo/shell/FileHelper.java
|
| diff --git a/mojo/runner/android/apk/src/org/chromium/mojo/shell/FileHelper.java b/mojo/runner/android/apk/src/org/chromium/mojo/shell/FileHelper.java
|
| index 08455528fde18f59ebc3ef2162d4ba34f56f957e..c41f24f164cc568aa675e4b19175f1cae226bf11 100644
|
| --- a/mojo/runner/android/apk/src/org/chromium/mojo/shell/FileHelper.java
|
| +++ b/mojo/runner/android/apk/src/org/chromium/mojo/shell/FileHelper.java
|
| @@ -7,7 +7,8 @@ package org.chromium.mojo.shell;
|
| import android.content.Context;
|
| import android.content.pm.PackageInfo;
|
| import android.content.pm.PackageManager;
|
| -import android.util.Log;
|
| +
|
| +import org.chromium.base.Log;
|
|
|
| import java.io.BufferedInputStream;
|
| import java.io.BufferedOutputStream;
|
| @@ -15,7 +16,6 @@ import java.io.File;
|
| import java.io.FileInputStream;
|
| import java.io.FileNotFoundException;
|
| import java.io.FileOutputStream;
|
| -import java.io.FilenameFilter;
|
| import java.io.IOException;
|
| import java.io.InputStream;
|
| import java.io.OutputStream;
|
| @@ -36,62 +36,87 @@ class FileHelper {
|
| private static final String TIMESTAMP_PREFIX = "asset_timestamp-";
|
|
|
| /**
|
| + * Used to indicate the type of destination file that should be created.
|
| + */
|
| + public enum FileType {
|
| + TEMPORARY,
|
| + PERMANENT,
|
| + }
|
| +
|
| + public enum ArchiveType {
|
| + /**
|
| + * The archive was created for a content handler (contains the mojo escape sequence).
|
| + */
|
| + CONTENT_HANDLER,
|
| + NORMAL,
|
| + }
|
| +
|
| + /**
|
| * Looks for a timestamp file on disk that indicates the version of the APK that the resource
|
| * assets were extracted from. Returns null if a timestamp was found and it indicates that the
|
| - * resources match the current APK. Otherwise returns a String that represents the filename of a
|
| - * timestamp to create.
|
| + * resources match the current APK. Otherwise returns the file to create.
|
| */
|
| - private static String checkAssetTimestamp(Context context, File outputDir) {
|
| + private static File findAssetTimestamp(Context context, File outputDir) {
|
| PackageManager pm = context.getPackageManager();
|
| PackageInfo pi = null;
|
|
|
| try {
|
| pi = pm.getPackageInfo(context.getPackageName(), 0);
|
| } catch (PackageManager.NameNotFoundException e) {
|
| - return TIMESTAMP_PREFIX;
|
| }
|
|
|
| if (pi == null) {
|
| - return TIMESTAMP_PREFIX;
|
| + return new File(outputDir, TIMESTAMP_PREFIX);
|
| }
|
|
|
| - String expectedTimestamp = TIMESTAMP_PREFIX + pi.versionCode + "-" + pi.lastUpdateTime;
|
| -
|
| - String[] timestamps = outputDir.list(new FilenameFilter() {
|
| - @Override
|
| - public boolean accept(File dir, String name) {
|
| - return name.startsWith(TIMESTAMP_PREFIX);
|
| - }
|
| - });
|
| + final File expectedTimestamp =
|
| + new File(outputDir, TIMESTAMP_PREFIX + pi.versionCode + "-" + pi.lastUpdateTime);
|
| + return expectedTimestamp.exists() ? null : expectedTimestamp;
|
| + }
|
|
|
| - if (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;
|
| + /**
|
| + * Invoke prior to extracting any assets into {@code directory}. If necessary deletes all the
|
| + * files in the specified directory. The return value must be supplied to {@link
|
| + *createTimestampIfNecessary}.
|
| + *
|
| + * @param directory directory assets will be extracted to
|
| + * @return non-null if a file with the specified name needs to be created after assets have
|
| + * been extracted.
|
| + */
|
| + public static File prepareDirectoryForAssets(Context context, File directory) {
|
| + final File timestamp = findAssetTimestamp(context, directory);
|
| + if (timestamp == null) {
|
| + return null;
|
| }
|
| -
|
| - if (!expectedTimestamp.equals(timestamps[0])) {
|
| - return expectedTimestamp;
|
| + for (File child : directory.listFiles()) {
|
| + deleteRecursively(child);
|
| }
|
| -
|
| - // Timestamp file is already up-to date.
|
| - return null;
|
| + return timestamp;
|
| }
|
|
|
| - public static File extractFromAssets(Context context, String assetName, File outputDirectory,
|
| - boolean useTempFile) throws IOException, FileNotFoundException {
|
| - String timestampToCreate = null;
|
| - if (!useTempFile) {
|
| - timestampToCreate = checkAssetTimestamp(context, outputDirectory);
|
| - if (timestampToCreate != null) {
|
| - for (File child : outputDirectory.listFiles()) {
|
| - deleteRecursively(child);
|
| - }
|
| - }
|
| + /**
|
| + * Creates a file used as a timestamp. The supplied file comes from {@link
|
| + *prepareDirectoryForAssets}.
|
| + *
|
| + * @param timestamp path of file to create, or null if a file does not need to be created
|
| + */
|
| + public static void createTimestampIfNecessary(File timestamp) {
|
| + if (timestamp == null) {
|
| + return;
|
| + }
|
| + try {
|
| + timestamp.createNewFile();
|
| + } catch (IOException e) {
|
| + // In the worst case we don't write a timestamp, so we'll re-extract the asset next
|
| + // time.
|
| + Log.w(TAG, "Failed to write asset timestamp!");
|
| }
|
| + }
|
|
|
| + public static File extractFromAssets(Context context, String assetName, File outputDirectory,
|
| + FileType fileType) throws IOException, FileNotFoundException {
|
| File outputFile;
|
| - if (useTempFile) {
|
| + if (fileType == FileType.TEMPORARY) {
|
| // Make the original filename part of the temp file name.
|
| // TODO(ppi): do we need to sanitize the suffix?
|
| String suffix = "-" + assetName;
|
| @@ -111,36 +136,48 @@ class FileHelper {
|
| } finally {
|
| inputStream.close();
|
| }
|
| -
|
| - if (timestampToCreate != null) {
|
| - try {
|
| - new File(outputDirectory, timestampToCreate).createNewFile();
|
| - } catch (IOException e) {
|
| - // In the worst case we don't write a timestamp, so we'll re-extract the asset next
|
| - // time.
|
| - Log.w(TAG, "Failed to write asset timestamp!");
|
| - }
|
| - }
|
| -
|
| return outputFile;
|
| }
|
|
|
| /**
|
| * Extracts the file of the given extension from the archive. Throws FileNotFoundException if no
|
| * matching file is found.
|
| + *
|
| + * @return path of extracted file
|
| */
|
| - static File extractFromArchive(File archive, String suffixToMatch,
|
| - File outputDirectory) throws IOException, FileNotFoundException {
|
| - ZipInputStream zip = new ZipInputStream(new BufferedInputStream(new FileInputStream(
|
| - archive)));
|
| + static File extractFromArchive(File archive, String suffixToMatch, File outputDirectory,
|
| + FileType fileType, ArchiveType archiveType) throws IOException, FileNotFoundException {
|
| + if (!outputDirectory.exists() && !outputDirectory.mkdirs()) {
|
| + Log.e(TAG, "extractFromArchive unable to create directory "
|
| + + outputDirectory.getAbsolutePath());
|
| + throw new FileNotFoundException();
|
| + }
|
| +
|
| + BufferedInputStream inputStream = new BufferedInputStream(new FileInputStream(archive));
|
| + if (archiveType == ArchiveType.CONTENT_HANDLER) {
|
| + int currentChar;
|
| + do {
|
| + currentChar = inputStream.read();
|
| + } while (currentChar != -1 && currentChar != '\n');
|
| + if (currentChar == -1) {
|
| + throw new FileNotFoundException();
|
| + }
|
| + inputStream = new BufferedInputStream(inputStream);
|
| + }
|
| + ZipInputStream zip = new ZipInputStream(inputStream);
|
| ZipEntry entry;
|
| while ((entry = zip.getNextEntry()) != null) {
|
| if (entry.getName().endsWith(suffixToMatch)) {
|
| + // TODO(sky): sanitize name.
|
| + final String name = new File(entry.getName()).getName();
|
| + File extractedFile;
|
| // Make the original filename part of the temp file name.
|
| - // TODO(ppi): do we need to sanitize the suffix?
|
| - String suffix = "-" + new File(entry.getName()).getName();
|
| - File extractedFile = File.createTempFile(TEMP_FILE_PREFIX, suffix,
|
| - outputDirectory);
|
| + if (fileType == FileType.TEMPORARY) {
|
| + final String suffix = "-" + name;
|
| + extractedFile = File.createTempFile(TEMP_FILE_PREFIX, suffix, outputDirectory);
|
| + } else {
|
| + extractedFile = new File(outputDirectory, name);
|
| + }
|
| writeStreamToFile(zip, extractedFile);
|
| zip.close();
|
| return extractedFile;
|
|
|