Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Remove support for downloading dynamic patches on Android #8663

Merged
merged 1 commit into from
Apr 22, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion ci/licenses_golden/licenses_flutter
Original file line number Diff line number Diff line change
Expand Up @@ -547,7 +547,6 @@ FILE: ../../../flutter/shell/platform/android/io/flutter/view/FlutterView.java
FILE: ../../../flutter/shell/platform/android/io/flutter/view/ResourceCleaner.java
FILE: ../../../flutter/shell/platform/android/io/flutter/view/ResourceExtractor.java
FILE: ../../../flutter/shell/platform/android/io/flutter/view/ResourcePaths.java
FILE: ../../../flutter/shell/platform/android/io/flutter/view/ResourceUpdater.java
FILE: ../../../flutter/shell/platform/android/io/flutter/view/TextureRegistry.java
FILE: ../../../flutter/shell/platform/android/io/flutter/view/VsyncWaiter.java
FILE: ../../../flutter/shell/platform/android/library_loader.cc
Expand Down
1 change: 0 additions & 1 deletion shell/platform/android/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,6 @@ java_library("flutter_shell_java") {
"io/flutter/view/ResourceCleaner.java",
"io/flutter/view/ResourceExtractor.java",
"io/flutter/view/ResourcePaths.java",
"io/flutter/view/ResourceUpdater.java",
"io/flutter/view/TextureRegistry.java",
"io/flutter/view/VsyncWaiter.java",
]
Expand Down
10 changes: 0 additions & 10 deletions shell/platform/android/io/flutter/app/FlutterActivityDelegate.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
import io.flutter.view.FlutterNativeView;
import io.flutter.view.FlutterRunArguments;
import io.flutter.view.FlutterView;
import io.flutter.view.ResourceUpdater;
import org.json.JSONObject;

import java.io.File;
Expand Down Expand Up @@ -213,7 +212,6 @@ public void onStart() {
@Override
public void onResume() {
Application app = (Application) activity.getApplicationContext();
FlutterMain.onResume(app);
if (app instanceof FlutterApplication) {
FlutterApplication flutterApp = (FlutterApplication) app;
flutterApp.setCurrentActivity(activity);
Expand Down Expand Up @@ -354,14 +352,6 @@ private void runBundle(String appBundlePath) {
if (!flutterView.getFlutterNativeView().isApplicationRunning()) {
FlutterRunArguments args = new FlutterRunArguments();
ArrayList<String> bundlePaths = new ArrayList<>();
ResourceUpdater resourceUpdater = FlutterMain.getResourceUpdater();
if (resourceUpdater != null) {
File patchFile = resourceUpdater.getInstalledPatch();
JSONObject manifest = resourceUpdater.readManifest(patchFile);
if (resourceUpdater.validateManifest(manifest)) {
bundlePaths.add(patchFile.getPath());
}
}
bundlePaths.add(appBundlePath);
args.bundlePaths = bundlePaths.toArray(new String[0]);
args.entrypoint = "main";
Expand Down
50 changes: 1 addition & 49 deletions shell/platform/android/io/flutter/view/FlutterMain.java
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,6 @@ private static String fromFlutterAssets(String filePath) {
private static String sFlutterAssetsDir = DEFAULT_FLUTTER_ASSETS_DIR;

private static boolean sInitialized = false;
private static ResourceUpdater sResourceUpdater;
private static ResourceExtractor sResourceExtractor;
private static boolean sIsPrecompiledAsBlobs;
private static boolean sIsPrecompiledAsSharedLibrary;
Expand Down Expand Up @@ -157,17 +156,7 @@ public static void startInitialization(Context applicationContext, Settings sett
initAot(applicationContext);
initResources(applicationContext);

if (sResourceUpdater == null) {
System.loadLibrary("flutter");
} else {
sResourceExtractor.waitForCompletion();
File lib = new File(PathUtils.getDataDirectory(applicationContext), DEFAULT_LIBRARY);
if (lib.exists()) {
System.load(lib.getAbsolutePath());
} else {
System.loadLibrary("flutter");
}
}
System.loadLibrary("flutter");

// We record the initialization time using SystemClock because at the start of the
// initialization we have not yet loaded the native library to call into dart_tools_api.h.
Expand Down Expand Up @@ -316,21 +305,6 @@ private static void initResources(Context applicationContext) {
Log.e(TAG, "Unable to read application info", e);
}

if (metaData != null && metaData.getBoolean("DynamicPatching")) {
sResourceUpdater = new ResourceUpdater(context);
// Also checking for ON_RESUME here since it's more efficient than waiting for actual
// onResume. Even though actual onResume is imminent when the app has just restarted,
// it's better to start downloading now, in parallel with the rest of initialization,
// and avoid a second application restart a bit later when actual onResume happens.
if (sResourceUpdater.getDownloadMode() == ResourceUpdater.DownloadMode.ON_RESTART ||
sResourceUpdater.getDownloadMode() == ResourceUpdater.DownloadMode.ON_RESUME) {
sResourceUpdater.startUpdateDownloadOnce();
if (sResourceUpdater.getInstallMode() == ResourceUpdater.InstallMode.IMMEDIATE) {
sResourceUpdater.waitForDownloadCompletion();
}
}
}

sResourceExtractor = new ResourceExtractor(context);

sResourceExtractor
Expand All @@ -353,22 +327,9 @@ private static void initResources(Context applicationContext) {
.addResource(sAotIsolateSnapshotInstr);
}

if (sResourceUpdater != null) {
sResourceExtractor
.addResource(DEFAULT_LIBRARY);
}

sResourceExtractor.start();
}

public static void onResume(Context context) {
if (sResourceUpdater != null) {
if (sResourceUpdater.getDownloadMode() == ResourceUpdater.DownloadMode.ON_RESUME) {
sResourceUpdater.startUpdateDownloadOnce();
}
}
}

/**
* Returns a list of the file names at the root of the application's asset
* path.
Expand Down Expand Up @@ -410,15 +371,6 @@ public static String findAppBundlePath(Context applicationContext) {
return appBundle.exists() ? appBundle.getPath() : null;
}

/**
* 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;
}

/**
* Returns the file name for the given asset.
* The returned file name can be used to access the asset in the APK
Expand Down
207 changes: 14 additions & 193 deletions shell/platform/android/io/flutter/view/ResourceExtractor.java
Original file line number Diff line number Diff line change
Expand Up @@ -52,64 +52,26 @@ private class ExtractTask extends AsyncTask<Void, Void, Void> {
protected Void doInBackground(Void... unused) {
final File dataDir = new File(PathUtils.getDataDirectory(mContext));

ResourceUpdater resourceUpdater = FlutterMain.getResourceUpdater();
if (resourceUpdater != null) {
// Protect patch file from being overwritten by downloader while
// it's being extracted since downloading happens asynchronously.
resourceUpdater.getInstallationLock().lock();
final String timestamp = checkTimestamp(dataDir);
if (timestamp == null) {
return null;
}

try {
if (resourceUpdater != null) {
File updateFile = resourceUpdater.getDownloadedPatch();
File activeFile = resourceUpdater.getInstalledPatch();

if (updateFile.exists()) {
JSONObject manifest = resourceUpdater.readManifest(updateFile);
if (resourceUpdater.validateManifest(manifest)) {
// Graduate patch file as active for asset manager.
if (activeFile.exists() && !activeFile.delete()) {
Log.w(TAG, "Could not delete file " + activeFile);
return null;
}
if (!updateFile.renameTo(activeFile)) {
Log.w(TAG, "Could not create file " + activeFile);
return null;
}
}
}
}

final String timestamp = checkTimestamp(dataDir);
if (timestamp == null) {
return null;
}

deleteFiles();

if (!extractUpdate(dataDir)) {
return null;
}
deleteFiles();

if (!extractAPK(dataDir)) {
return null;
}
if (!extractAPK(dataDir)) {
return null;
}

if (timestamp != null) {
try {
new File(dataDir, timestamp).createNewFile();
} catch (IOException e) {
Log.w(TAG, "Failed to write resource timestamp");
}
if (timestamp != null) {
try {
new File(dataDir, timestamp).createNewFile();
} catch (IOException e) {
Log.w(TAG, "Failed to write resource timestamp");
}
}

return null;

} finally {
if (resourceUpdater != null) {
resourceUpdater.getInstallationLock().unlock();
}
}
return null;
}
}

Expand Down Expand Up @@ -213,133 +175,6 @@ private boolean extractAPK(File dataDir) {
return true;
}

/// 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) {
final AssetManager manager = mContext.getResources().getAssets();

ResourceUpdater resourceUpdater = FlutterMain.getResourceUpdater();
if (resourceUpdater == null) {
return true;
}

File updateFile = resourceUpdater.getInstalledPatch();
if (!updateFile.exists()) {
return true;
}

JSONObject manifest = resourceUpdater.readManifest(updateFile);
if (!resourceUpdater.validateManifest(manifest)) {
// Obsolete patch file, nothing to install.
return true;
}

ZipFile zipFile;
try {
zipFile = new ZipFile(updateFile);

} catch (IOException e) {
Log.w(TAG, "Exception unpacking resources: " + e.getMessage());
deleteFiles();
return false;
}

for (String asset : mResources) {
String resource = null;
ZipEntry entry = null;
if (asset.endsWith(".so")) {
// Replicate library lookup logic.
for (String abi : SUPPORTED_ABIS) {
resource = "lib/" + abi + "/" + asset;
entry = zipFile.getEntry(resource);
if (entry == null) {
entry = zipFile.getEntry(resource + ".bzdiff40");
if (entry == null) {
continue;
}
}

// Stop after the first match.
break;
}
}

if (entry == null) {
resource = "assets/" + asset;
entry = zipFile.getEntry(resource);
if (entry == null) {
entry = zipFile.getEntry(resource + ".bzdiff40");
if (entry == null) {
continue;
}
}
}

final File output = new File(dataDir, asset);
if (output.exists()) {
continue;
}
if (output.getParentFile() != null) {
output.getParentFile().mkdirs();
}

try {
if (entry.getName().endsWith(".bzdiff40")) {
ByteArrayOutputStream diff = new ByteArrayOutputStream();
try (InputStream is = zipFile.getInputStream(entry)) {
copy(is, diff);
}

ByteArrayOutputStream orig = new ByteArrayOutputStream();
if (asset.endsWith(".so")) {
ZipFile apkFile = new ZipFile(getAPKPath());
if (apkFile == null) {
throw new IOException("Could not find APK");
}

ZipEntry origEntry = apkFile.getEntry(resource);
if (origEntry == null) {
throw new IOException("Could not find APK resource " + resource);
}

try (InputStream is = apkFile.getInputStream(origEntry)) {
copy(is, orig);
}

} else {
try (InputStream is = manager.open(asset)) {
copy(is, orig);
} catch (FileNotFoundException e) {
throw new IOException("Could not find APK resource " + resource);
}
}

try (OutputStream os = new FileOutputStream(output)) {
os.write(BSDiff.bspatch(orig.toByteArray(), diff.toByteArray()));
}

} else {
try (InputStream is = zipFile.getInputStream(entry);
OutputStream os = new FileOutputStream(output)) {
copy(is, os);
}
}

Log.i(TAG, "Extracted override resource " + entry.getName());

} catch (FileNotFoundException fnfe) {
continue;

} catch (IOException ioe) {
Log.w(TAG, "Exception unpacking resources: " + ioe.getMessage());
deleteFiles();
return false;
}
}

return true;
}

// Returns null if extracted resources are found and match the current APK version
// and update version if any, otherwise returns the current APK and update version.
private String checkTimestamp(File dataDir) {
Expand All @@ -359,20 +194,6 @@ private String checkTimestamp(File dataDir) {
String expectedTimestamp =
TIMESTAMP_PREFIX + getVersionCode(packageInfo) + "-" + packageInfo.lastUpdateTime;

ResourceUpdater resourceUpdater = FlutterMain.getResourceUpdater();
if (resourceUpdater != null) {
File patchFile = resourceUpdater.getInstalledPatch();
JSONObject manifest = resourceUpdater.readManifest(patchFile);
if (resourceUpdater.validateManifest(manifest)) {
String patchNumber = manifest.optString("patchNumber", null);
if (patchNumber != null) {
expectedTimestamp += "-" + patchNumber + "-" + patchFile.lastModified();
} else {
expectedTimestamp += "-" + patchFile.lastModified();
}
}
}

final String[] existingTimestamps = getExistingTimestamps(dataDir);

if (existingTimestamps == null) {
Expand Down
Loading