Commit 71943ac0 authored by Peter Kotwicz's avatar Peter Kotwicz Committed by Commit Bot

[Android WebAPK] Add UKM metric for WebAPK launches

This CL:
- Adds recording for the WebAPK.Visit UKM metric
- Changes LaunchMetrics#recordHomeScreenLaunchIntoStandaloneActivity()
to take WebappInfo as a parameter

Privacy doc: https://docs.google.com/document/d/10m4NwkTFVjQ7uboJP9rUQM0Yh7ULD6dVvGlL3eQtD3g/edit?usp=sharing

BUG=982362
TEST=None

Change-Id: I93900c9c448d491540b3f857cc4643f23f25cafd
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1783709Reviewed-by: default avatarYaron Friedman <yfriedman@chromium.org>
Reviewed-by: default avatarDominick Ng <dominickn@chromium.org>
Reviewed-by: default avatarRobert Kaplow <rkaplow@chromium.org>
Commit-Queue: Peter Kotwicz <pkotwicz@chromium.org>
Cr-Commit-Position: refs/heads/master@{#695019}
parent 7de27e55
......@@ -4,9 +4,16 @@
package org.chromium.chrome.browser.metrics;
import org.chromium.base.StrictModeContext;
import org.chromium.base.annotations.JNINamespace;
import org.chromium.base.metrics.CachedMetrics;
import org.chromium.blink_public.platform.WebDisplayMode;
import org.chromium.chrome.browser.ShortcutSource;
import org.chromium.chrome.browser.webapps.WebApkInfo;
import org.chromium.chrome.browser.webapps.WebApkUkmRecorder;
import org.chromium.chrome.browser.webapps.WebappDataStorage;
import org.chromium.chrome.browser.webapps.WebappInfo;
import org.chromium.chrome.browser.webapps.WebappRegistry;
import org.chromium.content_public.browser.WebContents;
import java.util.ArrayList;
......@@ -24,15 +31,13 @@ public class LaunchMetrics {
public final boolean mIsShortcut;
// Corresponds to C++ ShortcutInfo::Source
public final int mSource;
@WebDisplayMode
public final int mDisplayMode;
public final WebappInfo mWebappInfo;
public HomeScreenLaunch(
String url, boolean isShortcut, int source, @WebDisplayMode int displayMode) {
public HomeScreenLaunch(String url, boolean isShortcut, int source, WebappInfo webappInfo) {
mUrl = url;
mIsShortcut = isShortcut;
mSource = source;
mDisplayMode = displayMode;
mWebappInfo = webappInfo;
}
}
......@@ -41,13 +46,21 @@ public class LaunchMetrics {
/**
* Records the launch of a standalone Activity for a URL (i.e. a WebappActivity)
* added from a specific source.
* @param url URL that kicked off the Activity's creation.
* @param source integer id of the source from where the URL was added.
* @param displayMode integer id of the {@link WebDisplayMode} of the web app.
* @param webappInfo WebappInfo for launched activity.
*/
public static void recordHomeScreenLaunchIntoStandaloneActivity(
String url, int source, @WebDisplayMode int displayMode) {
sHomeScreenLaunches.add(new HomeScreenLaunch(url, false, source, displayMode));
public static void recordHomeScreenLaunchIntoStandaloneActivity(WebappInfo webappInfo) {
int source = webappInfo.source();
if (webappInfo.isForWebApk() && source == ShortcutSource.UNKNOWN) {
// WebApkInfo#source() identifies how the WebAPK was launched (e.g. via deep link).
// When the WebAPK is launched from the app list (ShortcutSource#UNKNOWN), query
// WebappDataStorage to determine how the WebAPK was installed (SOURCE_APP_BANNER_WEBAPK
// vs SOURCE_ADD_TO_HOMESCREEN_PWA). WebAPKs set WebappDataStorage#getSource() at
// install time.
source = getSourceForWebApkFromWebappDataStorage(webappInfo);
}
sHomeScreenLaunches.add(new HomeScreenLaunch(webappInfo.url(), false, source, webappInfo));
}
/**
......@@ -56,7 +69,7 @@ public class LaunchMetrics {
* @param source integer id of the source from where the URL was added.
*/
public static void recordHomeScreenLaunchIntoTab(String url, int source) {
sHomeScreenLaunches.add(new HomeScreenLaunch(url, true, source, WebDisplayMode.UNDEFINED));
sHomeScreenLaunches.add(new HomeScreenLaunch(url, true, source, null));
}
/**
......@@ -67,8 +80,17 @@ public class LaunchMetrics {
*/
public static void commitLaunchMetrics(WebContents webContents) {
for (HomeScreenLaunch launch : sHomeScreenLaunches) {
nativeRecordLaunch(launch.mIsShortcut, launch.mUrl, launch.mSource, launch.mDisplayMode,
webContents);
WebappInfo webappInfo = launch.mWebappInfo;
@WebDisplayMode
int displayMode =
(webappInfo == null) ? WebDisplayMode.UNDEFINED : webappInfo.displayMode();
nativeRecordLaunch(
launch.mIsShortcut, launch.mUrl, launch.mSource, displayMode, webContents);
if (webappInfo != null && webappInfo.isForWebApk()) {
WebApkInfo webApkInfo = (WebApkInfo) webappInfo;
WebApkUkmRecorder.recordWebApkLaunch(webApkInfo.manifestUrl(),
webApkInfo.distributor(), webApkInfo.webApkVersionCode(), launch.mSource);
}
}
sHomeScreenLaunches.clear();
......@@ -91,6 +113,26 @@ public class LaunchMetrics {
nativeRecordHomePageLaunchMetrics(showHomeButton, homepageIsNtp, homepageUrl);
}
/**
* Returns the source from the WebappDataStorage if the source has been stored before. Returns
* {@link ShortcutSource.WEBAPK_UNKNOWN} otherwise.
*/
private static int getSourceForWebApkFromWebappDataStorage(WebappInfo webappInfo) {
WebappDataStorage storage = null;
try (StrictModeContext ignored = StrictModeContext.allowDiskReads()) {
WebappRegistry.warmUpSharedPrefsForId(webappInfo.id());
storage = WebappRegistry.getInstance().getWebappDataStorage(webappInfo.id());
}
if (storage == null) {
return ShortcutSource.WEBAPK_UNKNOWN;
}
int source = storage.getSource();
return (source == ShortcutSource.UNKNOWN) ? ShortcutSource.WEBAPK_UNKNOWN : source;
}
private static native void nativeRecordLaunch(boolean isShortcut, String url, int source,
@WebDisplayMode int displayMode, WebContents webContents);
private static native void nativeRecordHomePageLaunchMetrics(
......
......@@ -18,6 +18,16 @@ public class WebApkUkmRecorder {
nativeRecordSessionDuration(manifestUrl, distributor, versionCode, duration);
}
/**
* Records that WebAPK was launched and the reason for the launch.
*/
public static void recordWebApkLaunch(
String manifestUrl, @WebApkDistributor int distributor, int versionCode, int source) {
nativeRecordVisit(manifestUrl, distributor, versionCode, source);
}
private static native void nativeRecordSessionDuration(
String manifestUrl, int distributor, int versionCode, long duration);
private static native void nativeRecordVisit(
String manifestUrl, int distributor, int versionCode, int source);
}
......@@ -12,7 +12,6 @@ import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.StrictMode;
import android.os.SystemClock;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
......@@ -178,18 +177,7 @@ public class WebappLauncherActivity extends Activity {
private static void launchWebapp(Activity launchingActivity, Intent intent,
@NonNull WebappInfo webappInfo, long createTimestamp) {
String webappUrl = webappInfo.url();
int webappSource = webappInfo.source();
// Retrieves the source of the WebAPK from WebappDataStorage if it is unknown. The
// {@link webappSource} is only known in the cases of an external intent or a
// notification that launches a WebAPK. Otherwise, it's not trustworthy and we must read
// the SharedPreference to get the installation source.
if (webappInfo.isForWebApk() && webappSource == ShortcutSource.UNKNOWN) {
webappSource = getWebApkSource(webappInfo);
}
LaunchMetrics.recordHomeScreenLaunchIntoStandaloneActivity(
webappUrl, webappSource, webappInfo.displayMode());
LaunchMetrics.recordHomeScreenLaunchIntoStandaloneActivity(webappInfo);
// Add all information needed to launch WebappActivity without {@link
// WebappActivity#sWebappInfoMap} to launch intent. When the Android OS has killed a
......@@ -207,27 +195,6 @@ public class WebappLauncherActivity extends Activity {
}
}
// Gets the source of a WebAPK from the WebappDataStorage if the source has been stored before.
private static int getWebApkSource(WebappInfo webappInfo) {
WebappDataStorage storage = null;
StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
try {
WebappRegistry.warmUpSharedPrefsForId(webappInfo.id());
storage = WebappRegistry.getInstance().getWebappDataStorage(webappInfo.id());
} finally {
StrictMode.setThreadPolicy(oldPolicy);
}
if (storage != null) {
int source = storage.getSource();
if (source != ShortcutSource.UNKNOWN) {
return source;
}
}
return ShortcutSource.WEBAPK_UNKNOWN;
}
/**
* Returns whether {@link sourceIntent} was sent by a WebAPK to relaunch itself.
*
......
......@@ -15,6 +15,18 @@
using base::android::JavaParamRef;
namespace {
// Converts Java string to GURL. Returns an empty GURL if the Java string is
// null.
GURL ConvertNullableJavaStringToGURL(JNIEnv* env,
const JavaParamRef<jstring>& java_url) {
return java_url ? GURL(base::android::ConvertJavaStringToUTF8(env, java_url))
: GURL();
}
} // namespace
// static
void WebApkUkmRecorder::RecordInstall(const GURL& manifest_url,
int version_code) {
......@@ -52,6 +64,25 @@ void WebApkUkmRecorder::RecordSessionDuration(const GURL& manifest_url,
.Record(ukm_recorder);
}
// static
void WebApkUkmRecorder::RecordVisit(const GURL& manifest_url,
int64_t distributor,
int64_t version_code,
int source) {
if (!manifest_url.is_valid())
return;
ukm::SourceId source_id = ukm::UkmRecorder::GetNewSourceID();
ukm::UkmRecorder* ukm_recorder = ukm::UkmRecorder::Get();
ukm_recorder->UpdateSourceURL(source_id, manifest_url);
ukm::builders::WebAPK_Visit(source_id)
.SetDistributor(distributor)
.SetAppVersion(version_code)
.SetLaunchSource(source)
.SetLaunch(true)
.Record(ukm_recorder);
}
// Called by the Java counterpart to record the Session Duration UKM metric.
void JNI_WebApkUkmRecorder_RecordSessionDuration(
JNIEnv* env,
......@@ -59,10 +90,19 @@ void JNI_WebApkUkmRecorder_RecordSessionDuration(
jint distributor,
jint version_code,
jlong duration) {
if (!manifest_url)
return;
WebApkUkmRecorder::RecordSessionDuration(
GURL(base::android::ConvertJavaStringToUTF8(env, manifest_url)),
distributor, version_code, duration);
ConvertNullableJavaStringToGURL(env, manifest_url), distributor,
version_code, duration);
}
// Called by the Java counterpart to record the Visit UKM metric.
void JNI_WebApkUkmRecorder_RecordVisit(
JNIEnv* env,
const JavaParamRef<jstring>& manifest_url,
jint distributor,
jint version_code,
jint source) {
WebApkUkmRecorder::RecordVisit(
ConvertNullableJavaStringToGURL(env, manifest_url), distributor,
version_code, source);
}
......@@ -26,6 +26,11 @@ class WebApkUkmRecorder {
int64_t version_code,
int64_t duration);
static void RecordVisit(const GURL& manifest_url,
int64_t distributor,
int64_t version_code,
int source);
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(WebApkUkmRecorder);
};
......
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