// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.webapps;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.SharedPreferences;
import org.chromium.base.CommandLine;
import org.chromium.base.ContextUtils;
import org.chromium.base.FileUtils;
import org.chromium.base.ThreadUtils;
import org.chromium.chrome.browser.ChromeSwitches;
import org.chromium.webapk.lib.client.DexOptimizer;
import org.chromium.webapk.lib.client.WebApkVersion;
import org.chromium.webapk.lib.common.WebApkVersionUtils;
import java.io.File;
/**
* Updates installed WebAPKs after a Chrome update.
*/
public class WebApkVersionManager {
/**
* Name of the shared preference for the version number of the dynamically loaded dex.
*/
private static final String EXTRACTED_DEX_VERSION_PREF =
"org.chromium.chrome.browser.webapps.extracted_dex_version";
/**
* Tries to extract the WebAPK runtime dex from the Chrome APK if it has not tried already.
* Should not be called on UI thread.
*/
// TODO(crbug.com/635567): Fix this properly.
@SuppressLint("SetWorldReadable")
public static void updateWebApksIfNeeded() {
assert !ThreadUtils.runningOnUiThread();
// TODO(pkotwicz|hanxi): Detect whether the manifest of installed APKs needs to be updated.
// (crbug.com/604513)
SharedPreferences preferences = ContextUtils.getAppSharedPreferences();
int extractedDexVersion = preferences.getInt(EXTRACTED_DEX_VERSION_PREF, -1);
if (!CommandLine.getInstance().hasSwitch(
ChromeSwitches.ALWAYS_EXTRACT_WEBAPK_RUNTIME_DEX_ON_STARTUP)
&& extractedDexVersion == WebApkVersion.CURRENT_RUNTIME_DEX_VERSION) {
return;
}
SharedPreferences.Editor editor = preferences.edit();
editor.putInt(EXTRACTED_DEX_VERSION_PREF, WebApkVersion.CURRENT_RUNTIME_DEX_VERSION);
editor.apply();
Context context = ContextUtils.getApplicationContext();
File dexDir = context.getDir("dex", Context.MODE_PRIVATE);
FileUtils.recursivelyDeleteFile(dexDir);
// Recreate world-executable directory using {@link Context#getDir}.
dexDir = context.getDir("dex", Context.MODE_PRIVATE);
String dexName =
WebApkVersionUtils.getRuntimeDexName(WebApkVersion.CURRENT_RUNTIME_DEX_VERSION);
File dexFile = new File(dexDir, dexName);
if (!FileUtils.extractAsset(context, dexName, dexFile) || !DexOptimizer.optimize(dexFile)) {
return;
}
// Make dex file world-readable so that WebAPK can use it.
dexFile.setReadable(true, false);
}
}