Commit 7cdb5539 authored by Peter Kotwicz's avatar Peter Kotwicz Committed by Commit Bot

[Android WebAPK Refactor] Make WebAPK validity logic in WebappLauncherActivity more correct 10/X

A WebAPK is valid if all the requirements below are true:
Requirement#1: The APK is correctly signed (WebApkValidator#isValidWebApk())
Requirement#2: The APK handles the URL in the intent (WebApkValidator#canWebApkHandleUrl())
Requirement#3: The APK has <meta-data> in a format that Chrome can read.
  (WebApkInfo#create() returns non-null)

This CL changes the logic in WebappLauncherActivity to make Requirement#3 clearer. This CL:
- Introduces WebappInfo#isForWebApk() and makes WebappLauncherActivity use this instead
  of the return value of WebappLauncherActivity#isValidWebApk() which did not check
  Requirement #3.
- Changes WebApkValidator#canWebApkHandleUrl() to no longer check whether the passed in
  APK package is a valid WebAPK. This reduces the number of extras read directly in
  WebappLauncherActivity (outside of WebApkInfo#create/WebappInfo#create)

BUG=901954

Change-Id: I51ef612c641d9d7c2e9535db33f0baee17694edb
Reviewed-on: https://chromium-review.googlesource.com/c/1351456
Commit-Queue: Peter Kotwicz <pkotwicz@chromium.org>
Reviewed-by: default avatarDominick Ng <dominickn@chromium.org>
Cr-Commit-Position: refs/heads/master@{#611346}
parent b5c8517a
...@@ -310,6 +310,11 @@ public class WebApkInfo extends WebappInfo { ...@@ -310,6 +310,11 @@ public class WebApkInfo extends WebappInfo {
return mSerializedShareTarget; return mSerializedShareTarget;
} }
@Override
public boolean isForWebApk() {
return true;
}
@Override @Override
public String webApkPackageName() { public String webApkPackageName() {
return mApkPackageName; return mApkPackageName;
......
...@@ -5,7 +5,6 @@ ...@@ -5,7 +5,6 @@
package org.chromium.chrome.browser.webapps; package org.chromium.chrome.browser.webapps;
import android.content.Intent; import android.content.Intent;
import android.text.TextUtils;
import org.chromium.base.ContextUtils; import org.chromium.base.ContextUtils;
import org.chromium.chrome.browser.ShortcutHelper; import org.chromium.chrome.browser.ShortcutHelper;
...@@ -42,10 +41,10 @@ public class WebappDelegateFactory extends TabDelegateFactory { ...@@ -42,10 +41,10 @@ public class WebappDelegateFactory extends TabDelegateFactory {
// compatibility we relaunch it the hard way. // compatibility we relaunch it the hard way.
String startUrl = mActivity.getWebappInfo().uri().toString(); String startUrl = mActivity.getWebappInfo().uri().toString();
String webApkPackageName = mActivity.getWebappInfo().webApkPackageName(); WebappInfo webappInfo = mActivity.getWebappInfo();
if (!TextUtils.isEmpty(webApkPackageName)) { if (webappInfo.isForWebApk()) {
Intent intent = WebApkNavigationClient.createLaunchWebApkIntent( Intent intent = WebApkNavigationClient.createLaunchWebApkIntent(
webApkPackageName, startUrl, false /* forceNavigation */); webappInfo.webApkPackageName(), startUrl, false /* forceNavigation */);
IntentUtils.safeStartActivity(ContextUtils.getApplicationContext(), intent); IntentUtils.safeStartActivity(ContextUtils.getApplicationContext(), intent);
return; return;
} }
......
...@@ -274,6 +274,10 @@ public class WebappInfo { ...@@ -274,6 +274,10 @@ public class WebappInfo {
return mDisplayMode; return mDisplayMode;
} }
public boolean isForWebApk() {
return false;
}
public String webApkPackageName() { public String webApkPackageName() {
return null; return null;
} }
......
...@@ -71,14 +71,7 @@ public class WebappLauncherActivity extends Activity { ...@@ -71,14 +71,7 @@ public class WebappLauncherActivity extends Activity {
Intent intent = getIntent(); Intent intent = getIntent();
ChromeWebApkHost.init(); ChromeWebApkHost.init();
boolean validWebApk = isValidWebApk(intent); WebappInfo webappInfo = tryCreateWebappInfo(intent);
WebappInfo webappInfo;
if (validWebApk) {
webappInfo = WebApkInfo.create(intent);
} else {
webappInfo = WebappInfo.create(intent);
}
// {@link WebApkInfo#create()} and {@link WebappInfo#create()} return null if the intent // {@link WebApkInfo#create()} and {@link WebappInfo#create()} return null if the intent
// does not specify required values such as the uri. // does not specify required values such as the uri.
...@@ -95,14 +88,14 @@ public class WebappLauncherActivity extends Activity { ...@@ -95,14 +88,14 @@ public class WebappLauncherActivity extends Activity {
// - the request was for a WebAPK that is valid; // - the request was for a WebAPK that is valid;
// - the MAC is present and valid for the homescreen shortcut to be opened; // - the MAC is present and valid for the homescreen shortcut to be opened;
// - the intent was sent by Chrome. // - the intent was sent by Chrome.
if (validWebApk || isValidMacForUrl(webappUrl, webappMac) if (webappInfo.isForWebApk() || isValidMacForUrl(webappUrl, webappMac)
|| wasIntentFromChrome(intent)) { || wasIntentFromChrome(intent)) {
int source = webappSource; int source = webappSource;
// Retrieves the source of the WebAPK from WebappDataStorage if it is unknown. The // Retrieves the source of the WebAPK from WebappDataStorage if it is unknown. The
// {@link webappSource} will not be unknown in the case of an external intent or a // {@link webappSource} will not be unknown in the case of an external intent or a
// notification that launches a WebAPK. Otherwise, it's not trustworthy and we must read // notification that launches a WebAPK. Otherwise, it's not trustworthy and we must read
// the SharedPreference to get the installation source. // the SharedPreference to get the installation source.
if (validWebApk && (webappSource == ShortcutSource.UNKNOWN)) { if (webappInfo.isForWebApk() && (webappSource == ShortcutSource.UNKNOWN)) {
source = getWebApkSource(webappInfo); source = getWebApkSource(webappInfo);
} }
LaunchMetrics.recordHomeScreenLaunchIntoStandaloneActivity( LaunchMetrics.recordHomeScreenLaunchIntoStandaloneActivity(
...@@ -113,7 +106,7 @@ public class WebappLauncherActivity extends Activity { ...@@ -113,7 +106,7 @@ public class WebappLauncherActivity extends Activity {
// WebappActivity and the user selects the WebappActivity from "Android Recents" the // WebappActivity and the user selects the WebappActivity from "Android Recents" the
// WebappActivity is launched without going through WebappLauncherActivity first. // WebappActivity is launched without going through WebappLauncherActivity first.
WebappActivity.addWebappInfo(webappInfo.id(), webappInfo); WebappActivity.addWebappInfo(webappInfo.id(), webappInfo);
Intent launchIntent = createWebappLaunchIntent(webappInfo, validWebApk); Intent launchIntent = createWebappLaunchIntent(webappInfo);
IntentHandler.addTimestampToIntent(launchIntent, mCreateTime); IntentHandler.addTimestampToIntent(launchIntent, mCreateTime);
// Pass through WebAPK shell launch timestamp to the new intent. // Pass through WebAPK shell launch timestamp to the new intent.
long shellLaunchTimestamp = long shellLaunchTimestamp =
...@@ -184,17 +177,16 @@ public class WebappLauncherActivity extends Activity { ...@@ -184,17 +177,16 @@ public class WebappLauncherActivity extends Activity {
/** /**
* Creates an Intent to launch the web app. * Creates an Intent to launch the web app.
* @param info Information about the web app. * @param info Information about the web app.
* @param isWebApk If true, launch the app as a WebApkActivity. If false, launch the app as
* a WebappActivity.
*/ */
public static Intent createWebappLaunchIntent(WebappInfo info, boolean isWebApk) { private static Intent createWebappLaunchIntent(WebappInfo info) {
String activityName = isWebApk ? WebApkActivity.class.getName() String activityName = info.isForWebApk() ? WebApkActivity.class.getName()
: WebappActivity.class.getName(); : WebappActivity.class.getName();
boolean newTask = true; boolean newTask = true;
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
// Specifically assign the app to a particular WebappActivity instance. // Specifically assign the app to a particular WebappActivity instance.
int namespace = isWebApk ? ActivityAssigner.ActivityAssignerNamespace.WEBAPK_NAMESPACE int namespace = info.isForWebApk()
: ActivityAssigner.ActivityAssignerNamespace.WEBAPP_NAMESPACE; ? ActivityAssigner.ActivityAssignerNamespace.WEBAPK_NAMESPACE
: ActivityAssigner.ActivityAssignerNamespace.WEBAPP_NAMESPACE;
int activityIndex = ActivityAssigner.instance(namespace).assign(info.id()); int activityIndex = ActivityAssigner.instance(namespace).assign(info.id());
activityName += String.valueOf(activityIndex); activityName += String.valueOf(activityIndex);
...@@ -213,7 +205,7 @@ public class WebappLauncherActivity extends Activity { ...@@ -213,7 +205,7 @@ public class WebappLauncherActivity extends Activity {
break; break;
} }
} else { } else {
if (isWebApk && info.useTransparentSplash()) { if (info.isForWebApk() && info.useTransparentSplash()) {
activityName = TransparentSplashWebApkActivity.class.getName(); activityName = TransparentSplashWebApkActivity.class.getName();
newTask = false; newTask = false;
} }
...@@ -280,25 +272,20 @@ public class WebappLauncherActivity extends Activity { ...@@ -280,25 +272,20 @@ public class WebappLauncherActivity extends Activity {
return false; return false;
} }
/** /** Tries to create WebappInfo/WebApkInfo for the intent. */
* Checks whether the WebAPK package specified in the intent is a valid WebAPK and whether the private WebappInfo tryCreateWebappInfo(Intent intent) {
* url specified in the intent can be fulfilled by the WebAPK. // Builds WebApkInfo for the intent if the WebAPK package specified in the intent is a valid
* // WebAPK and the URL specified in the intent can be fulfilled by the WebAPK.
* @param intent The intent
* @return true iff all validation criteria are met.
*/
private boolean isValidWebApk(Intent intent) {
String webApkPackage = String webApkPackage =
IntentUtils.safeGetStringExtra(intent, WebApkConstants.EXTRA_WEBAPK_PACKAGE_NAME); IntentUtils.safeGetStringExtra(intent, WebApkConstants.EXTRA_WEBAPK_PACKAGE_NAME);
if (TextUtils.isEmpty(webApkPackage)) return false;
String url = IntentUtils.safeGetStringExtra(intent, ShortcutHelper.EXTRA_URL); String url = IntentUtils.safeGetStringExtra(intent, ShortcutHelper.EXTRA_URL);
if (TextUtils.isEmpty(url)) return false; if (!TextUtils.isEmpty(webApkPackage) && !TextUtils.isEmpty(url)
&& WebApkValidator.canWebApkHandleUrl(this, webApkPackage, url)) {
if (!WebApkValidator.canWebApkHandleUrl(this, webApkPackage, url)) { return WebApkInfo.create(intent);
Log.d(TAG, "%s is not within scope of %s WebAPK", url, webApkPackage);
return false;
} }
return true;
Log.d(TAG, "%s is either not a WebAPK or %s is not within the WebAPK's scope",
webApkPackage, url);
return WebappInfo.create(intent);
} }
} }
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