Commit 523539ae authored by Peter Kotwicz's avatar Peter Kotwicz Committed by Commit Bot

[Android WebAPK] Clear cached data when identity service selects different host

This CL fixes IdentityService#getRuntimeHostBrowserPackageName(). In some
scenarios (like the default browser supporting WebAPKs for an unbound WebAPK),
calling HostBrowserUtils#getHostBrowserPackageName() updates the host browser
in shared preferences. This CL changes the call so that when the
IdentityService changes the host browser in Shared Preferences the identity
service also clears that WebAPK's shared preferences and data directory.

This CL:
- Splits HostBrowserUtils#getHostBrowserPackageName() into 2 functions:
  HostBrowserUtils#getCachedHostBrowserPackage()
    which returns the host browser cached in shared preferences if it is still
    installed. HostBrowserUtils#getCachedHostBrowserPackage() does not update any
    state.
  HostBrowserUtils#computeHostBrowserPackageClearCachedDataOnChange()
    which computes the new host browser. If the computed host browser is
    different than the cached host browser in shared preferences, the WebAPK's
    shared preferences and data directory are cleared.
- Reduces the number of functions with hidden calls to
  HostBrowserUtils#getHostBrowserPackageName().
  HostBrowserUtils#getHostBrowserContext() and
  HostBrowserUtils#getHostBrowserUid() are changed to take a package name
  parameter and are moved to WebApkUtils.

BUG=900464
TEST=HostBrowserUtilsTest.*

Change-Id: Ie6dea7de5eaca770d8a1261c2742308bc1165419
Reviewed-on: https://chromium-review.googlesource.com/c/1310569
Commit-Queue: Peter Kotwicz <pkotwicz@chromium.org>
Reviewed-by: default avatarXi Han <hanxi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#608834}
parent 88bd1378
......@@ -12,4 +12,4 @@
# //chrome/android/webapk/shell_apk:webapk is changed. This includes
# Java files, Android resource files and AndroidManifest.xml. Does not affect
# Chrome.apk
current_shell_apk_version = 74
current_shell_apk_version = 75
......@@ -37,9 +37,10 @@ public class HostBrowserClassLoader {
* @param canaryClassname Class to load to check that ClassLoader is valid.
* @return The ClassLoader.
*/
public static ClassLoader getClassLoaderInstance(Context context, String canaryClassName) {
public static ClassLoader getClassLoaderInstance(
Context context, String hostBrowserPackage, String canaryClassName) {
assertRunningOnUiThread();
Context remoteContext = HostBrowserUtils.getHostBrowserContext(context);
Context remoteContext = WebApkUtils.fetchRemoteContext(context, hostBrowserPackage);
if (remoteContext == null) {
Log.w(TAG, "Failed to get remote context.");
return null;
......
......@@ -7,10 +7,8 @@ package org.chromium.webapk.shell_apk;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.text.TextUtils;
......@@ -55,57 +53,45 @@ public class HostBrowserUtils {
}
/**
* Returns a Context for the host browser that was specified when building the WebAPK.
* @param context A context.
* @return The remote context. Returns null on an error.
* Returns the cached package name of the host browser to launch the WebAPK. Returns null if the
* cached package name is no longer installed.
*/
public static Context getHostBrowserContext(Context context) {
try {
String hostPackage = getHostBrowserPackageName(context);
return context.getApplicationContext().createPackageContext(hostPackage, 0);
} catch (NameNotFoundException e) {
e.printStackTrace();
public static String getCachedHostBrowserPackage(Context context) {
PackageManager packageManager = context.getPackageManager();
if (WebApkUtils.isInstalled(packageManager, sHostPackage)) {
return sHostPackage;
}
return null;
}
/**
* Returns the package name of the host browser to launch the WebAPK. Also caches the package
* name in the SharedPreference if it is not null.
* @param context A context.
* @return The package name. Returns null on an error.
*/
public static String getHostBrowserPackageName(Context context) {
if (sHostPackage == null
|| !WebApkUtils.isInstalled(context.getPackageManager(), sHostPackage)) {
sHostPackage = getHostBrowserPackageNameInternal(context);
if (sHostPackage != null) {
writeHostBrowserToSharedPref(context, sHostPackage);
}
String hostPackage = getHostBrowserFromSharedPreference(context);
if (!WebApkUtils.isInstalled(packageManager, hostPackage)) {
hostPackage = null;
}
return sHostPackage;
return hostPackage;
}
/**
* Returns the uid for the host browser that was specified when building the WebAPK.
* @param context A context.
* @return The application uid. Returns -1 on an error.
* Computes and returns the package name of the best host browser to launch the WebAPK. Returns
* null if there is either no host browsers which support WebAPKs or if the user needs to
* confirm the host browser selection. If the best host browser has changed, clears all of the
* WebAPK's cached data.
*/
public static int getHostBrowserUid(Context context) {
String hostPackageName = getHostBrowserPackageName(context);
if (hostPackageName == null) {
return -1;
public static String computeHostBrowserPackageClearCachedDataOnChange(Context context) {
PackageManager packageManager = context.getPackageManager();
if (WebApkUtils.isInstalled(packageManager, sHostPackage)) {
return sHostPackage;
}
try {
PackageManager packageManager = context.getPackageManager();
ApplicationInfo appInfo = packageManager.getApplicationInfo(
hostPackageName, PackageManager.GET_META_DATA);
return appInfo.uid;
} catch (NameNotFoundException e) {
e.printStackTrace();
String hostInPreferences = getHostBrowserFromSharedPreference(context);
sHostPackage = computeHostBrowserPackageNameInternal(context);
if (!TextUtils.equals(sHostPackage, hostInPreferences)) {
if (!TextUtils.isEmpty(hostInPreferences)) {
deleteSharedPref(context);
deleteInternalStorage(context);
}
writeHostBrowserToSharedPref(context, sHostPackage);
}
return -1;
return sHostPackage;
}
/**
......@@ -160,7 +146,7 @@ public class HostBrowserUtils {
* Returns the package name of the host browser to launch the WebAPK, or null if we did not find
* one.
*/
private static String getHostBrowserPackageNameInternal(Context context) {
private static String computeHostBrowserPackageNameInternal(Context context) {
PackageManager packageManager = context.getPackageManager();
// Gets the package name of the host browser if it is stored in the SharedPreference.
......@@ -220,4 +206,19 @@ public class HostBrowserUtils {
return resolveInfo.activityInfo.packageName;
}
/** Deletes the SharedPreferences for the given context. */
private static void deleteSharedPref(Context context) {
SharedPreferences.Editor editor = WebApkSharedPreferences.getPrefs(context).edit();
editor.clear();
editor.apply();
}
/** Deletes the internal storage for the given context. */
private static void deleteInternalStorage(Context context) {
DexLoader.deletePath(context.getCacheDir());
DexLoader.deletePath(context.getFilesDir());
DexLoader.deletePath(
context.getDir(HostBrowserClassLoader.DEX_DIR_NAME, Context.MODE_PRIVATE));
}
}
......@@ -18,7 +18,8 @@ public class IdentityService extends Service {
public String getRuntimeHostBrowserPackageName() {
StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
try {
return HostBrowserUtils.getHostBrowserPackageName(getApplicationContext());
return HostBrowserUtils.computeHostBrowserPackageClearCachedDataOnChange(
getApplicationContext());
} finally {
StrictMode.setThreadPolicy(oldPolicy);
}
......
......@@ -8,14 +8,12 @@ import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import org.chromium.webapk.lib.common.WebApkConstants;
import org.chromium.webapk.lib.common.WebApkMetaDataKeys;
import java.util.List;
......@@ -72,15 +70,8 @@ public class LaunchHostBrowserSelector {
String packageName = mContext.getPackageName();
Log.v(TAG, "Package name of the WebAPK:" + packageName);
String runtimeHostInPreferences =
HostBrowserUtils.getHostBrowserFromSharedPreference(mContext);
String runtimeHost = HostBrowserUtils.getHostBrowserPackageName(mContext);
if (!TextUtils.isEmpty(runtimeHostInPreferences)
&& !runtimeHostInPreferences.equals(runtimeHost)) {
deleteSharedPref();
deleteInternalStorage();
}
String runtimeHost =
HostBrowserUtils.computeHostBrowserPackageClearCachedDataOnChange(mContext);
if (!TextUtils.isEmpty(runtimeHost)) {
selectCallback.onBrowserSelected(runtimeHost, false /* dialogShown */);
return;
......@@ -95,23 +86,6 @@ public class LaunchHostBrowserSelector {
}
}
/** Deletes the SharedPreferences. */
private void deleteSharedPref() {
SharedPreferences sharedPref =
mContext.getSharedPreferences(WebApkConstants.PREF_PACKAGE, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPref.edit();
editor.clear();
editor.apply();
}
/** Deletes the internal storage. */
private void deleteInternalStorage() {
DexLoader.deletePath(mContext.getCacheDir());
DexLoader.deletePath(mContext.getFilesDir());
DexLoader.deletePath(
mContext.getDir(HostBrowserClassLoader.DEX_DIR_NAME, Context.MODE_PRIVATE));
}
/**
* Launches the Play Store with the host browser's page.
*/
......
......@@ -38,8 +38,9 @@ public class WebApkServiceFactory extends Service {
@Override
public IBinder onBind(Intent intent) {
ClassLoader webApkClassLoader =
HostBrowserClassLoader.getClassLoaderInstance(this, WEBAPK_SERVICE_IMPL_CLASS_NAME);
final String hostBrowserPackage = HostBrowserUtils.getCachedHostBrowserPackage(this);
ClassLoader webApkClassLoader = HostBrowserClassLoader.getClassLoaderInstance(
this, hostBrowserPackage, WEBAPK_SERVICE_IMPL_CLASS_NAME);
if (webApkClassLoader == null) {
Log.w(TAG, "Unable to create ClassLoader.");
return null;
......@@ -50,7 +51,7 @@ public class WebApkServiceFactory extends Service {
webApkClassLoader.loadClass(WEBAPK_SERVICE_IMPL_CLASS_NAME);
Constructor<?> webApkServiceImplConstructor =
webApkServiceImplClass.getConstructor(Context.class, Bundle.class);
int hostBrowserUid = HostBrowserUtils.getHostBrowserUid(this);
int hostBrowserUid = WebApkUtils.getRemotePackageUid(this, hostBrowserPackage);
Bundle bundle = new Bundle();
bundle.putInt(KEY_SMALL_ICON_ID, R.drawable.notification_badge);
bundle.putInt(KEY_HOST_BROWSER_UID, hostBrowserUid);
......
......@@ -114,6 +114,32 @@ public class WebApkUtils {
return result;
}
/** Builds a context for the passed in remote package name. */
public static Context fetchRemoteContext(Context context, String remotePackageName) {
try {
return context.getApplicationContext().createPackageContext(remotePackageName, 0);
} catch (NameNotFoundException e) {
e.printStackTrace();
}
return null;
}
/** Returns the uid for the passed in remote package name. */
public static int getRemotePackageUid(Context context, String remotePackageName) {
if (remotePackageName == null) {
return -1;
}
try {
PackageManager packageManager = context.getPackageManager();
ApplicationInfo appInfo = packageManager.getApplicationInfo(
remotePackageName, PackageManager.GET_META_DATA);
return appInfo.uid;
} catch (NameNotFoundException e) {
e.printStackTrace();
}
return -1;
}
/**
* Android uses padding_left under API level 17 and uses padding_start after that.
* If we set the padding in resource file, android will create duplicated resource xml
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment