From d979589b1b8616991061a15524dd65b1cecf0f8e Mon Sep 17 00:00:00 2001 From: Stanislav Baranov Date: Mon, 7 Jan 2019 18:38:07 -0800 Subject: [PATCH] Refactor dynamic patching to use clearer naming and structure. This is a no-op change, except for fixing a bug where download task reference wasn't cleared after download was completed. This change also removes call to output stream flush(), which is not necessary according to Java spec. The rest of the change deals with requiring the code to work directly with ResourceUpdater object instead of having FlutterMain be a facade that forwards some of ResourceUpdater's methods. This simplifies the other (more essential) upcoming changes that will be landing in the followings few PRs. --- .../flutter/app/FlutterActivityDelegate.java | 6 ++- .../android/io/flutter/view/FlutterMain.java | 9 ++++- .../io/flutter/view/ResourceExtractor.java | 31 ++++++---------- .../io/flutter/view/ResourceUpdater.java | 37 +++++++++---------- 4 files changed, 41 insertions(+), 42 deletions(-) diff --git a/shell/platform/android/io/flutter/app/FlutterActivityDelegate.java b/shell/platform/android/io/flutter/app/FlutterActivityDelegate.java index 2a4c924c50d9d..429f43ad8ae77 100644 --- a/shell/platform/android/io/flutter/app/FlutterActivityDelegate.java +++ b/shell/platform/android/io/flutter/app/FlutterActivityDelegate.java @@ -33,6 +33,7 @@ import io.flutter.view.FlutterRunArguments; import io.flutter.view.FlutterView; +import java.io.File; import java.util.ArrayList; /** @@ -343,8 +344,9 @@ private void runBundle(String appBundlePath) { if (!flutterView.getFlutterNativeView().isApplicationRunning()) { FlutterRunArguments args = new FlutterRunArguments(); ArrayList bundlePaths = new ArrayList<>(); - if (FlutterMain.getUpdateInstallationPath() != null) { - bundlePaths.add(FlutterMain.getUpdateInstallationPath()); + if (FlutterMain.getResourceUpdater() != null) { + File patchFile = FlutterMain.getResourceUpdater().getPatch(); + bundlePaths.add(patchFile.getPath()); } bundlePaths.add(appBundlePath); args.bundlePaths = bundlePaths.toArray(new String[0]); diff --git a/shell/platform/android/io/flutter/view/FlutterMain.java b/shell/platform/android/io/flutter/view/FlutterMain.java index 16d1c0ec3e2d0..9b0edbeed0b9f 100644 --- a/shell/platform/android/io/flutter/view/FlutterMain.java +++ b/shell/platform/android/io/flutter/view/FlutterMain.java @@ -360,8 +360,13 @@ public static String findAppBundlePath(Context applicationContext) { return appBundle.exists() ? appBundle.getPath() : null; } - public static String getUpdateInstallationPath() { - return sResourceUpdater == null ? null : sResourceUpdater.getUpdateInstallationPath(); + /** + * Returns the main internal interface for the dynamic patching subsystem. + * + * If this is null, it means that dynamic patching is disabled in this app. + */ + public static ResourceUpdater getResourceUpdater() { + return sResourceUpdater; } /** diff --git a/shell/platform/android/io/flutter/view/ResourceExtractor.java b/shell/platform/android/io/flutter/view/ResourceExtractor.java index c28749b9e92d1..cfcae096678ba 100644 --- a/shell/platform/android/io/flutter/view/ResourceExtractor.java +++ b/shell/platform/android/io/flutter/view/ResourceExtractor.java @@ -123,17 +123,6 @@ void waitForCompletion() { } } - boolean filesMatch() { - JSONObject updateManifest = readUpdateManifest(); - if (!validateUpdateManifest(updateManifest)) { - updateManifest = null; - } - - final File dataDir = new File(PathUtils.getDataDirectory(mContext)); - final String timestamp = checkTimestamp(dataDir, updateManifest); - return (timestamp == null); - } - private String[] getExistingTimestamps(File dataDir) { return dataDir.list(new FilenameFilter() { @Override @@ -160,7 +149,6 @@ private void deleteFiles() { } } - /// Returns true if successfully unpacked APK resources, /// otherwise deletes all resources and returns false. private boolean extractAPK(File dataDir) { @@ -208,11 +196,12 @@ private boolean extractAPK(File dataDir) { /// Returns true if successfully unpacked update resources or if there is no update, /// otherwise deletes all resources and returns false. private boolean extractUpdate(File dataDir) { - if (FlutterMain.getUpdateInstallationPath() == null) { + ResourceUpdater resourceUpdater = FlutterMain.getResourceUpdater(); + if (resourceUpdater == null) { return true; } - final File updateFile = new File(FlutterMain.getUpdateInstallationPath()); + File updateFile = resourceUpdater.getPatch(); if (!updateFile.exists()) { return true; } @@ -298,11 +287,14 @@ private String checkTimestamp(File dataDir, JSONObject updateManifest) { if (!buildNumber.equals(Long.toString(getVersionCode(packageInfo)))) { Log.w(TAG, "Outdated update file for " + getVersionCode(packageInfo)); } else { - final File updateFile = new File(FlutterMain.getUpdateInstallationPath()); + ResourceUpdater resourceUpdater = FlutterMain.getResourceUpdater(); + assert resourceUpdater != null; + File patchFile = resourceUpdater.getPatch(); + assert patchFile.exists(); if (patchNumber != null) { - expectedTimestamp += "-" + patchNumber + "-" + updateFile.lastModified(); + expectedTimestamp += "-" + patchNumber + "-" + patchFile.lastModified(); } else { - expectedTimestamp += "-" + updateFile.lastModified(); + expectedTimestamp += "-" + patchFile.lastModified(); } } } @@ -365,11 +357,12 @@ private boolean validateUpdateManifest(JSONObject updateManifest) { /// Returns null if no update manifest is found. private JSONObject readUpdateManifest() { - if (FlutterMain.getUpdateInstallationPath() == null) { + ResourceUpdater resourceUpdater = FlutterMain.getResourceUpdater(); + if (resourceUpdater == null) { return null; } - File updateFile = new File(FlutterMain.getUpdateInstallationPath()); + File updateFile = resourceUpdater.getPatch(); if (!updateFile.exists()) { return null; } diff --git a/shell/platform/android/io/flutter/view/ResourceUpdater.java b/shell/platform/android/io/flutter/view/ResourceUpdater.java index 203ae18d052f7..5fef38f66f111 100644 --- a/shell/platform/android/io/flutter/view/ResourceUpdater.java +++ b/shell/platform/android/io/flutter/view/ResourceUpdater.java @@ -58,12 +58,12 @@ enum InstallMode { IMMEDIATE } - private static class DownloadTask extends AsyncTask { + private class DownloadTask extends AsyncTask { @Override - protected Void doInBackground(String... args) { + protected Void doInBackground(String... unused) { try { - URL unresolvedURL = new URL(args[0]); - File localFile = new File(args[1]); + URL unresolvedURL = new URL(buildUpdateDownloadURL()); + File localFile = getPatch(); long startMillis = new Date().getTime(); Log.i(TAG, "Checking for updates at " + unresolvedURL); @@ -71,10 +71,10 @@ protected Void doInBackground(String... args) { HttpURLConnection connection = (HttpURLConnection)unresolvedURL.openConnection(); - long lastModified = localFile.lastModified(); - if (lastModified != 0) { - Log.i(TAG, "Active update timestamp " + lastModified); - connection.setIfModifiedSince(lastModified); + long lastDownloadTime = localFile.lastModified(); + if (lastDownloadTime != 0) { + Log.i(TAG, "Active update timestamp " + lastDownloadTime); + connection.setIfModifiedSince(lastDownloadTime); } try (InputStream input = connection.getInputStream()) { @@ -108,7 +108,6 @@ protected Void doInBackground(String... args) { long totalMillis = new Date().getTime() - startMillis; Log.i(TAG, "Update downloaded in " + totalMillis / 100 / 10. + "s"); - output.flush(); return null; } } @@ -127,7 +126,7 @@ public ResourceUpdater(Context context) { this.context = context; } - public String getAPKVersion() { + private String getAPKVersion() { try { PackageManager packageManager = context.getPackageManager(); PackageInfo packageInfo = packageManager.getPackageInfo(context.getPackageName(), 0); @@ -138,11 +137,11 @@ public String getAPKVersion() { } } - public String getUpdateInstallationPath() { - return context.getFilesDir().toString() + "/patch.zip"; + public File getPatch() { + return new File(context.getFilesDir().toString() + "/patch.zip"); } - public String buildUpdateDownloadURL() { + private String buildUpdateDownloadURL() { Bundle metaData; try { metaData = context.getPackageManager().getApplicationInfo( @@ -168,7 +167,7 @@ public String buildUpdateDownloadURL() { return uri.normalize().toString(); } - public DownloadMode getDownloadMode() { + DownloadMode getDownloadMode() { Bundle metaData; try { metaData = context.getPackageManager().getApplicationInfo( @@ -195,7 +194,7 @@ public DownloadMode getDownloadMode() { } } - public InstallMode getInstallMode() { + InstallMode getInstallMode() { Bundle metaData; try { metaData = context.getPackageManager().getApplicationInfo( @@ -222,21 +221,21 @@ public InstallMode getInstallMode() { } } - public void startUpdateDownloadOnce() { + void startUpdateDownloadOnce() { if (downloadTask != null ) { return; } downloadTask = new DownloadTask(); - downloadTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, - buildUpdateDownloadURL(), getUpdateInstallationPath()); + downloadTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } - public void waitForDownloadCompletion() { + void waitForDownloadCompletion() { if (downloadTask == null) { return; } try { downloadTask.get(); + downloadTask = null; } catch (CancellationException e) { Log.w(TAG, "Download cancelled: " + e.getMessage()); return;