blob: eb3db773595a2b40dd772861802b1bf57441fdcf [file] [log] [blame]
// 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 android.os.Build;
import org.chromium.base.CommandLine;
import org.chromium.base.ContextUtils;
import org.chromium.base.FileUtils;
import org.chromium.base.StrictModeContext;
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.WebApkCommonUtils;
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";
/**
* Name of the shared preference for the Android OS version at the time that the dex was last
* extracted from Chrome's assets and optimized.
*/
private static final String LAST_SDK_VERSION_PREF =
"org.chromium.chrome.browser.webapps.last_sdk_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();
SharedPreferences preferences = ContextUtils.getAppSharedPreferences();
int extractedDexVersion = preferences.getInt(EXTRACTED_DEX_VERSION_PREF, -1);
int lastSdkVersion = preferences.getInt(LAST_SDK_VERSION_PREF, -1);
if (!CommandLine.getInstance().hasSwitch(
ChromeSwitches.ALWAYS_EXTRACT_WEBAPK_RUNTIME_DEX_ON_STARTUP)
&& extractedDexVersion == WebApkVersion.CURRENT_RUNTIME_DEX_VERSION
&& lastSdkVersion == Build.VERSION.SDK_INT) {
return;
}
SharedPreferences.Editor editor = preferences.edit();
editor.putInt(EXTRACTED_DEX_VERSION_PREF, WebApkVersion.CURRENT_RUNTIME_DEX_VERSION);
editor.putInt(LAST_SDK_VERSION_PREF, Build.VERSION.SDK_INT);
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 =
WebApkCommonUtils.getRuntimeDexName(WebApkVersion.CURRENT_RUNTIME_DEX_VERSION);
File dexFile = new File(dexDir, dexName);
if (!FileUtils.extractAsset(context, dexName, dexFile)) {
return;
}
// Disable VM detectLeakedClosableObjects due to Android SDK bug: https://crbug.com/750196
try (StrictModeContext ignored = StrictModeContext.allowAllVmPolicies()) {
if (!DexOptimizer.optimize(dexFile)) {
return;
}
}
// Make dex file world-readable so that WebAPK can use it.
dexFile.setReadable(true, false);
}
}