diff options
Diffstat (limited to 'chromium/components/embedder_support')
21 files changed, 531 insertions, 65 deletions
diff --git a/chromium/components/embedder_support/BUILD.gn b/chromium/components/embedder_support/BUILD.gn index 3a042f43d70..647bd364620 100644 --- a/chromium/components/embedder_support/BUILD.gn +++ b/chromium/components/embedder_support/BUILD.gn @@ -17,6 +17,7 @@ source_set("unit_tests") { deps = [ "//base", + "//base/test:test_support", "//components/embedder_support", "//components/embedder_support/origin_trials", "//testing/gtest", diff --git a/chromium/components/embedder_support/android/BUILD.gn b/chromium/components/embedder_support/android/BUILD.gn index 49f264a0791..182b461b42b 100644 --- a/chromium/components/embedder_support/android/BUILD.gn +++ b/chromium/components/embedder_support/android/BUILD.gn @@ -242,7 +242,7 @@ android_library("junit_test_support") { sources = [ "junit/src/org/chromium/components/embedder_support/util/ShadowUrlUtilities.java" ] deps = [ ":util_java", - "//third_party/robolectric:robolectric_all_java", + "//third_party/android_deps:robolectric_all_java", ] } @@ -256,6 +256,8 @@ java_library("components_embedder_support_junit_tests") { deps = [ ":util_java", "//base:base_junit_test_support", + "//third_party/android_deps:robolectric_all_java", + "//third_party/junit", ] } diff --git a/chromium/components/embedder_support/android/browser_context/browser_context_handle.cc b/chromium/components/embedder_support/android/browser_context/browser_context_handle.cc index af9a43dacd4..77ddc0cf804 100644 --- a/chromium/components/embedder_support/android/browser_context/browser_context_handle.cc +++ b/chromium/components/embedder_support/android/browser_context/browser_context_handle.cc @@ -15,6 +15,9 @@ namespace browser_context { content::BrowserContext* BrowserContextFromJavaHandle( const JavaRef<jobject>& jhandle) { + if (!jhandle) + return nullptr; + return reinterpret_cast<content::BrowserContext*>( Java_BrowserContextHandle_getNativeBrowserContextPointer( AttachCurrentThread(), jhandle)); diff --git a/chromium/components/embedder_support/android/delegate/web_contents_delegate_android.cc b/chromium/components/embedder_support/android/delegate/web_contents_delegate_android.cc index c7adaddc988..ff394138e01 100644 --- a/chromium/components/embedder_support/android/delegate/web_contents_delegate_android.cc +++ b/chromium/components/embedder_support/android/delegate/web_contents_delegate_android.cc @@ -313,8 +313,7 @@ bool WebContentsDelegateAndroid::ShouldBlockMediaRequest(const GURL& url) { } void WebContentsDelegateAndroid::EnterFullscreenModeForTab( - WebContents* web_contents, - const GURL& origin, + content::RenderFrameHost* requesting_frame, const blink::mojom::FullscreenOptions& options) { JNIEnv* env = AttachCurrentThread(); ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env); diff --git a/chromium/components/embedder_support/android/delegate/web_contents_delegate_android.h b/chromium/components/embedder_support/android/delegate/web_contents_delegate_android.h index c8d8af79a16..56706c7f610 100644 --- a/chromium/components/embedder_support/android/delegate/web_contents_delegate_android.h +++ b/chromium/components/embedder_support/android/delegate/web_contents_delegate_android.h @@ -96,8 +96,7 @@ class WebContentsDelegateAndroid : public content::WebContentsDelegate { void ShowRepostFormWarningDialog(content::WebContents* source) override; bool ShouldBlockMediaRequest(const GURL& url) override; void EnterFullscreenModeForTab( - content::WebContents* web_contents, - const GURL& origin, + content::RenderFrameHost* requesting_frame, const blink::mojom::FullscreenOptions& options) override; void ExitFullscreenModeForTab(content::WebContents* web_contents) override; bool IsFullscreenForTabOrPending( diff --git a/chromium/components/embedder_support/android/java/src/org/chromium/components/embedder_support/delegate/ColorPickerDialogRenderTest.java b/chromium/components/embedder_support/android/java/src/org/chromium/components/embedder_support/delegate/ColorPickerDialogRenderTest.java index 6a162f600dd..f5d2b05baa0 100644 --- a/chromium/components/embedder_support/android/java/src/org/chromium/components/embedder_support/delegate/ColorPickerDialogRenderTest.java +++ b/chromium/components/embedder_support/android/java/src/org/chromium/components/embedder_support/delegate/ColorPickerDialogRenderTest.java @@ -43,8 +43,7 @@ public class ColorPickerDialogRenderTest extends DummyUiActivityTestCase { new NightModeTestUtils.NightModeParams().getParameters(); @Rule - public RenderTestRule mRenderTestRule = - new RenderTestRule("chrome/test/data/android/render_tests"); + public RenderTestRule mRenderTestRule = new RenderTestRule(); private View mView; diff --git a/chromium/components/embedder_support/android/java/src/org/chromium/components/embedder_support/view/ContentView.java b/chromium/components/embedder_support/android/java/src/org/chromium/components/embedder_support/view/ContentView.java index 251ee9ea516..33465886b25 100644 --- a/chromium/components/embedder_support/android/java/src/org/chromium/components/embedder_support/view/ContentView.java +++ b/chromium/components/embedder_support/android/java/src/org/chromium/components/embedder_support/view/ContentView.java @@ -34,10 +34,16 @@ import org.chromium.content_public.browser.ViewEventSink; import org.chromium.content_public.browser.WebContents; import org.chromium.content_public.browser.WebContentsAccessibility; import org.chromium.ui.base.EventForwarder; +import org.chromium.ui.base.EventOffsetHandler; /** * The containing view for {@link WebContents} that exists in the Android UI hierarchy and exposes * the various {@link View} functionality to it. + * + * While ContentView is a ViewGroup, the only place that should add children is ViewAndroidDelegate, + * and only for cases that WebContentsAccessibility handles (such as anchoring popups). This is + * because the accessibility support provided by WebContentsAccessibility ignores all child views. + * In other words, any children added to this are *not* accessible. */ public class ContentView extends FrameLayout implements ViewEventSink.InternalAccessDelegate, SmartClipProvider, @@ -48,7 +54,9 @@ public class ContentView extends FrameLayout public static final int DEFAULT_MEASURE_SPEC = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); - private final WebContents mWebContents; + @Nullable + private WebContents mWebContents; + private boolean mIsObscuredForAccessibility; private final ObserverList<OnHierarchyChangeListener> mHierarchyChangeListeners = new ObserverList<>(); private final ObserverList<OnSystemUiVisibilityChangeListener> mSystemUiChangeListeners = @@ -62,6 +70,9 @@ public class ContentView extends FrameLayout private int mDesiredWidthMeasureSpec = DEFAULT_MEASURE_SPEC; private int mDesiredHeightMeasureSpec = DEFAULT_MEASURE_SPEC; + @Nullable + private final EventOffsetHandler mEventOffsetHandler; + /** * Constructs a new ContentView for the appropriate Android version. * @param context The Context the view is running in, through which it can @@ -69,11 +80,12 @@ public class ContentView extends FrameLayout * @param webContents The WebContents managing this content view. * @return an instance of a ContentView. */ - public static ContentView createContentView(Context context, WebContents webContents) { + public static ContentView createContentView(Context context, + @Nullable EventOffsetHandler eventOffsetHandler, @Nullable WebContents webContents) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - return new ContentViewApi23(context, webContents); + return new ContentViewApi23(context, eventOffsetHandler, webContents); } - return new ContentView(context, webContents); + return new ContentView(context, eventOffsetHandler, webContents); } /** @@ -82,7 +94,7 @@ public class ContentView extends FrameLayout * access the current theme, resources, etc. * @param webContents A pointer to the WebContents managing this content view. */ - ContentView(Context context, WebContents webContents) { + ContentView(Context context, EventOffsetHandler eventOffsetHandler, WebContents webContents) { super(context, null, android.R.attr.webViewStyle); if (getScrollBarStyle() == View.SCROLLBARS_INSIDE_OVERLAY) { @@ -91,6 +103,7 @@ public class ContentView extends FrameLayout } mWebContents = webContents; + mEventOffsetHandler = eventOffsetHandler; setFocusable(true); setFocusableInTouchMode(true); @@ -103,13 +116,41 @@ public class ContentView extends FrameLayout setOnSystemUiVisibilityChangeListener(this); } + protected WebContentsAccessibility getWebContentsAccessibility() { + return hasValidWebContents() ? WebContentsAccessibility.fromWebContents(mWebContents) + : null; + } + public WebContents getWebContents() { return mWebContents; } - protected WebContentsAccessibility getWebContentsAccessibility() { - return !mWebContents.isDestroyed() ? WebContentsAccessibility.fromWebContents(mWebContents) - : null; + public void setWebContents(WebContents webContents) { + boolean wasFocused = isFocused(); + boolean wasWindowFocused = hasWindowFocus(); + boolean wasAttached = isAttachedToWindow(); + boolean wasObscured = mIsObscuredForAccessibility; + if (wasFocused) onFocusChanged(false, View.FOCUS_FORWARD, null); + if (wasWindowFocused) onWindowFocusChanged(false); + if (wasAttached) onDetachedFromWindow(); + if (wasObscured) setIsObscuredForAccessibility(false); + mWebContents = webContents; + mViewEventSink = null; + if (wasFocused) onFocusChanged(true, View.FOCUS_FORWARD, null); + if (wasWindowFocused) onWindowFocusChanged(true); + if (wasAttached) onAttachedToWindow(); + if (wasObscured) setIsObscuredForAccessibility(true); + } + + /** + * Control whether WebContentsAccessibility will respond to accessibility requests. + */ + public void setIsObscuredForAccessibility(boolean isObscured) { + if (mIsObscuredForAccessibility == isObscured) return; + mIsObscuredForAccessibility = isObscured; + WebContentsAccessibility wcax = getWebContentsAccessibility(); + if (wcax == null) return; + wcax.setObscuredByAnotherView(mIsObscuredForAccessibility); } @Override @@ -228,13 +269,13 @@ public class ContentView extends FrameLayout @Override public InputConnection onCreateInputConnection(EditorInfo outAttrs) { // Calls may come while/after WebContents is destroyed. See https://crbug.com/821750#c8. - if (mWebContents.isDestroyed()) return null; + if (!hasValidWebContents()) return null; return ImeAdapter.fromWebContents(mWebContents).onCreateInputConnection(outAttrs); } @Override public boolean onCheckIsTextEditor() { - if (mWebContents.isDestroyed()) return false; + if (!hasValidWebContents()) return false; return ImeAdapter.fromWebContents(mWebContents).onCheckIsTextEditor(); } @@ -243,8 +284,10 @@ public class ContentView extends FrameLayout try { TraceEvent.begin("ContentView.onFocusChanged"); super.onFocusChanged(gainFocus, direction, previouslyFocusedRect); - getViewEventSink().setHideKeyboardOnBlur(true); - getViewEventSink().onViewFocusChanged(gainFocus); + if (hasValidWebContents()) { + getViewEventSink().setHideKeyboardOnBlur(true); + getViewEventSink().onViewFocusChanged(gainFocus); + } } finally { TraceEvent.end("ContentView.onFocusChanged"); } @@ -253,7 +296,9 @@ public class ContentView extends FrameLayout @Override public void onWindowFocusChanged(boolean hasWindowFocus) { super.onWindowFocusChanged(hasWindowFocus); - getViewEventSink().onWindowFocusChanged(hasWindowFocus); + if (hasValidWebContents()) { + getViewEventSink().onWindowFocusChanged(hasWindowFocus); + } } @Override @@ -276,9 +321,40 @@ public class ContentView extends FrameLayout } @Override + public boolean onInterceptTouchEvent(MotionEvent e) { + boolean ret = super.onInterceptTouchEvent(e); + if (mEventOffsetHandler != null) { + mEventOffsetHandler.onInterceptTouchEvent(e); + } + return ret; + } + + @Override public boolean onTouchEvent(MotionEvent event) { EventForwarder forwarder = getEventForwarder(); - return forwarder != null ? forwarder.onTouchEvent(event) : false; + boolean ret = forwarder != null ? forwarder.onTouchEvent(event) : false; + if (mEventOffsetHandler != null) mEventOffsetHandler.onTouchEvent(event); + return ret; + } + + @Override + public boolean onInterceptHoverEvent(MotionEvent e) { + if (mEventOffsetHandler != null) { + mEventOffsetHandler.onInterceptHoverEvent(e); + } + return super.onInterceptHoverEvent(e); + } + + @Override + public boolean dispatchDragEvent(DragEvent e) { + if (mEventOffsetHandler != null) { + mEventOffsetHandler.onPreDispatchDragEvent(e.getAction()); + } + boolean ret = super.dispatchDragEvent(e); + if (mEventOffsetHandler != null) { + mEventOffsetHandler.onPostDispatchDragEvent(e.getAction()); + } + return ret; } /** @@ -307,7 +383,9 @@ public class ContentView extends FrameLayout } private ViewEventSink getViewEventSink() { - if (mViewEventSink == null) mViewEventSink = ViewEventSink.from(mWebContents); + if (mViewEventSink == null && hasValidWebContents()) { + mViewEventSink = ViewEventSink.from(mWebContents); + } return mViewEventSink; } @@ -318,7 +396,9 @@ public class ContentView extends FrameLayout @Override protected void onConfigurationChanged(Configuration newConfig) { - getViewEventSink().onConfigurationChanged(newConfig); + if (hasValidWebContents()) { + getViewEventSink().onConfigurationChanged(newConfig); + } super.onConfigurationChanged(newConfig); } @@ -342,40 +422,44 @@ public class ContentView extends FrameLayout @Override protected int computeHorizontalScrollExtent() { - RenderCoordinates rc = RenderCoordinates.fromWebContents(mWebContents); + RenderCoordinates rc = getRenderCoordinates(); return rc != null ? rc.getLastFrameViewportWidthPixInt() : 0; } @Override protected int computeHorizontalScrollOffset() { - RenderCoordinates rc = RenderCoordinates.fromWebContents(mWebContents); + RenderCoordinates rc = getRenderCoordinates(); return rc != null ? rc.getScrollXPixInt() : 0; } @Override protected int computeHorizontalScrollRange() { - RenderCoordinates rc = RenderCoordinates.fromWebContents(mWebContents); + RenderCoordinates rc = getRenderCoordinates(); return rc != null ? rc.getContentWidthPixInt() : 0; } @Override protected int computeVerticalScrollExtent() { - RenderCoordinates rc = RenderCoordinates.fromWebContents(mWebContents); + RenderCoordinates rc = getRenderCoordinates(); return rc != null ? rc.getLastFrameViewportHeightPixInt() : 0; } @Override protected int computeVerticalScrollOffset() { - RenderCoordinates rc = RenderCoordinates.fromWebContents(mWebContents); + RenderCoordinates rc = getRenderCoordinates(); return rc != null ? rc.getScrollYPixInt() : 0; } @Override protected int computeVerticalScrollRange() { - RenderCoordinates rc = RenderCoordinates.fromWebContents(mWebContents); + RenderCoordinates rc = getRenderCoordinates(); return rc != null ? rc.getContentHeightPixInt() : 0; } + private RenderCoordinates getRenderCoordinates() { + return hasValidWebContents() ? RenderCoordinates.fromWebContents(mWebContents) : null; + } + // End FrameLayout overrides. @Override @@ -390,25 +474,33 @@ public class ContentView extends FrameLayout @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); - getViewEventSink().onAttachedToWindow(); + if (hasValidWebContents()) { + getViewEventSink().onAttachedToWindow(); + } } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); - getViewEventSink().onDetachedFromWindow(); + if (hasValidWebContents()) { + getViewEventSink().onDetachedFromWindow(); + } } // Implements SmartClipProvider @Override public void extractSmartClipData(int x, int y, int width, int height) { - mWebContents.requestSmartClipExtract(x, y, width, height); + if (hasValidWebContents()) { + mWebContents.requestSmartClipExtract(x, y, width, height); + } } // Implements SmartClipProvider @Override public void setSmartClipResultHandler(final Handler resultHandler) { - mWebContents.setSmartClipResultHandler(resultHandler); + if (hasValidWebContents()) { + mWebContents.setSmartClipResultHandler(resultHandler); + } } /////////////////////////////////////////////////////////////////////////////////////////////// @@ -442,9 +534,13 @@ public class ContentView extends FrameLayout return hasValidWebContents() && mWebContents.getTopLevelNativeWindow() != null; } - private static class ContentViewApi23 extends ContentView { - public ContentViewApi23(Context context, WebContents webContents) { - super(context, webContents); + /** + * ContentView on Api23 to override onProvideVirtualStructure. + */ + public static class ContentViewApi23 extends ContentView { + protected ContentViewApi23( + Context context, EventOffsetHandler eventOffsetHandler, WebContents webContents) { + super(context, eventOffsetHandler, webContents); } @Override diff --git a/chromium/components/embedder_support/android/junit/src/org/chromium/components/embedder_support/util/OriginTest.java b/chromium/components/embedder_support/android/junit/src/org/chromium/components/embedder_support/util/OriginTest.java index 8be1437fce3..fd8cf8c8841 100644 --- a/chromium/components/embedder_support/android/junit/src/org/chromium/components/embedder_support/util/OriginTest.java +++ b/chromium/components/embedder_support/android/junit/src/org/chromium/components/embedder_support/util/OriginTest.java @@ -5,7 +5,8 @@ package org.chromium.components.embedder_support.util; import android.net.Uri; -import android.support.test.filters.SmallTest; + +import androidx.test.filters.SmallTest; import org.junit.Assert; import org.junit.Test; diff --git a/chromium/components/embedder_support/android/metrics/BUILD.gn b/chromium/components/embedder_support/android/metrics/BUILD.gn index d9641ed058c..7a0e269c738 100644 --- a/chromium/components/embedder_support/android/metrics/BUILD.gn +++ b/chromium/components/embedder_support/android/metrics/BUILD.gn @@ -21,14 +21,16 @@ static_library("metrics") { deps = [ ":jni", "//components/metrics", - "//components/metrics:gpu", + "//components/metrics:content", "//components/metrics:net", "//components/metrics:ui", "//components/prefs", + "//components/ukm", "//components/version_info", "//components/version_info/android:channel_getter", "//content/public/browser", "//services/resource_coordinator/public/cpp/memory_instrumentation:browser", + "//third_party/metrics_proto", ] } diff --git a/chromium/components/embedder_support/android/metrics/DEPS b/chromium/components/embedder_support/android/metrics/DEPS index a7e7754f1e8..a2b32b905eb 100644 --- a/chromium/components/embedder_support/android/metrics/DEPS +++ b/chromium/components/embedder_support/android/metrics/DEPS @@ -1,8 +1,11 @@ include_rules = [ "+components/metrics", "+components/prefs", + "+components/ukm", "+components/version_info", "+content/public/browser", "+content/public/test", + "+services/network/public/cpp", "+services/resource_coordinator/public/cpp/memory_instrumentation", + "+third_party/metrics_proto", ] diff --git a/chromium/components/embedder_support/android/metrics/android_metrics_log_uploader.cc b/chromium/components/embedder_support/android/metrics/android_metrics_log_uploader.cc index a737dc5bcc4..18dabdad7ae 100644 --- a/chromium/components/embedder_support/android/metrics/android_metrics_log_uploader.cc +++ b/chromium/components/embedder_support/android/metrics/android_metrics_log_uploader.cc @@ -5,8 +5,10 @@ #include "components/embedder_support/android/metrics/android_metrics_log_uploader.h" #include "base/android/jni_array.h" +#include "base/check.h" #include "components/embedder_support/android/metrics/jni/AndroidMetricsLogUploader_jni.h" #include "components/metrics/log_decoder.h" +#include "third_party/metrics_proto/chrome_user_metrics_extension.pb.h" using base::android::ScopedJavaLocalRef; using base::android::ToJavaByteArray; @@ -34,6 +36,16 @@ void AndroidMetricsLogUploader::UploadLog( return; } + // Speculative CHECKs to see why WebView UMA (and probably other embedders of + // this component) are missing system_profiles for a small fraction of + // records. TODO(https://crbug.com/1081925): downgrade these to DCHECKs or + // remove entirely when we figure out the issue. + CHECK(!log_data.empty()); + metrics::ChromeUserMetricsExtension uma_log; + bool can_parse = uma_log.ParseFromString(log_data); + CHECK(can_parse); + CHECK(uma_log.has_system_profile()); + JNIEnv* env = base::android::AttachCurrentThread(); ScopedJavaLocalRef<jbyteArray> java_data = ToJavaByteArray( env, reinterpret_cast<const uint8_t*>(log_data.data()), log_data.size()); diff --git a/chromium/components/embedder_support/android/metrics/android_metrics_service_client.cc b/chromium/components/embedder_support/android/metrics/android_metrics_service_client.cc index 32cd418ed13..a36c0a1dc54 100644 --- a/chromium/components/embedder_support/android/metrics/android_metrics_service_client.cc +++ b/chromium/components/embedder_support/android/metrics/android_metrics_service_client.cc @@ -10,32 +10,53 @@ #include "base/android/jni_android.h" #include "base/android/jni_string.h" #include "base/base_paths_android.h" +#include "base/files/file_util.h" #include "base/i18n/rtl.h" +#include "base/metrics/persistent_histogram_allocator.h" +#include "base/metrics/statistics_recorder.h" +#include "base/path_service.h" +#include "base/process/process_handle.h" +#include "base/task/task_traits.h" +#include "base/task/thread_pool.h" +#include "base/threading/thread_restrictions.h" #include "build/build_config.h" #include "components/embedder_support/android/metrics/android_metrics_log_uploader.h" #include "components/embedder_support/android/metrics/jni/AndroidMetricsServiceClient_jni.h" #include "components/metrics/android_metrics_provider.h" #include "components/metrics/call_stack_profile_metrics_provider.h" +#include "components/metrics/content/gpu_metrics_provider.h" +#include "components/metrics/content/subprocess_metrics_provider.h" #include "components/metrics/cpu_metrics_provider.h" #include "components/metrics/drive_metrics_provider.h" -#include "components/metrics/gpu/gpu_metrics_provider.h" +#include "components/metrics/file_metrics_provider.h" #include "components/metrics/metrics_pref_names.h" #include "components/metrics/metrics_service.h" #include "components/metrics/metrics_state_manager.h" #include "components/metrics/net/cellular_logic_helper.h" +#include "components/metrics/net/net_metrics_log_uploader.h" #include "components/metrics/net/network_metrics_provider.h" +#include "components/metrics/persistent_histograms.h" #include "components/metrics/stability_metrics_helper.h" #include "components/metrics/ui/screen_info_metrics_provider.h" #include "components/metrics/version_utils.h" #include "components/prefs/pref_service.h" +#include "components/ukm/field_trials_provider_helper.h" +#include "components/ukm/ukm_service.h" +#include "content/public/browser/histogram_fetcher.h" #include "content/public/browser/network_service_instance.h" #include "content/public/browser/notification_service.h" #include "content/public/browser/notification_types.h" - +#include "services/network/public/cpp/shared_url_loader_factory.h" namespace metrics { namespace { +// This specifies the amount of time to wait for all renderers to send their +// data. +const int kMaxHistogramGatheringWaitDuration = 60000; // 60 seconds. + +const int kMaxHistogramStorageKiB = 100 << 10; // 100 MiB + // Callbacks for MetricsStateManager::Create. Store/LoadClientInfo // allow Windows Chrome to back up ClientInfo. They're no-ops for // AndroidMetricsServiceClient. @@ -61,15 +82,121 @@ int UintToPerMille(uint32_t value) { return static_cast<int>(value_per_mille); } +bool IsProcessRunning(base::ProcessId pid) { + // Sending a signal value of 0 will cause error checking to be performed + // with no signal being sent. + return (kill(pid, 0) == 0 || errno != ESRCH); +} + +metrics::FileMetricsProvider::FilterAction FilterBrowserMetricsFiles( + const base::FilePath& path) { + base::ProcessId pid; + if (!base::GlobalHistogramAllocator::ParseFilePath(path, nullptr, nullptr, + &pid)) { + return metrics::FileMetricsProvider::FILTER_PROCESS_FILE; + } + + if (pid == base::GetCurrentProcId()) + return metrics::FileMetricsProvider::FILTER_ACTIVE_THIS_PID; + + if (IsProcessRunning(pid)) + return metrics::FileMetricsProvider::FILTER_TRY_LATER; + + return metrics::FileMetricsProvider::FILTER_PROCESS_FILE; +} + +// Constructs the name of a persistent metrics file from a directory and metrics +// name, and either registers that file as associated with a previous run if +// metrics reporting is enabled, or deletes it if not. +void RegisterOrRemovePreviousRunMetricsFile( + bool metrics_reporting_enabled, + const base::FilePath& dir, + base::StringPiece metrics_name, + metrics::FileMetricsProvider::SourceAssociation association, + metrics::FileMetricsProvider* file_metrics_provider) { + base::FilePath metrics_file; + base::GlobalHistogramAllocator::ConstructFilePaths( + dir, metrics_name, &metrics_file, nullptr, nullptr); + + if (metrics_reporting_enabled) { + // Enable reading any existing saved metrics. + file_metrics_provider->RegisterSource(metrics::FileMetricsProvider::Params( + metrics_file, + metrics::FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_FILE, + association, metrics_name)); + } else { + // When metrics reporting is not enabled, any existing file should be + // deleted in order to preserve user privacy. + base::ThreadPool::PostTask( + FROM_HERE, + {base::MayBlock(), base::TaskPriority::BEST_EFFORT, + base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN}, + base::BindOnce(base::GetDeleteFileCallback(), metrics_file)); + } +} + +std::unique_ptr<metrics::FileMetricsProvider> CreateFileMetricsProvider( + PrefService* pref_service, + bool metrics_reporting_enabled) { + // Create an object to monitor files of metrics and include them in reports. + std::unique_ptr<metrics::FileMetricsProvider> file_metrics_provider( + new metrics::FileMetricsProvider(pref_service)); + + base::FilePath user_data_dir; + base::PathService::Get(base::DIR_ANDROID_APP_DATA, &user_data_dir); + // Register the Crashpad metrics files. + // Register the data from the previous run if crashpad_handler didn't exit + // cleanly. + RegisterOrRemovePreviousRunMetricsFile( + metrics_reporting_enabled, user_data_dir, kCrashpadHistogramAllocatorName, + metrics::FileMetricsProvider::ASSOCIATE_INTERNAL_PROFILE_OR_PREVIOUS_RUN, + file_metrics_provider.get()); + + base::FilePath browser_metrics_upload_dir = + user_data_dir.AppendASCII(kBrowserMetricsName); + if (metrics_reporting_enabled) { + metrics::FileMetricsProvider::Params browser_metrics_params( + browser_metrics_upload_dir, + metrics::FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_DIR, + metrics::FileMetricsProvider::ASSOCIATE_INTERNAL_PROFILE, + kBrowserMetricsName); + browser_metrics_params.max_dir_kib = kMaxHistogramStorageKiB; + browser_metrics_params.filter = + base::BindRepeating(FilterBrowserMetricsFiles); + file_metrics_provider->RegisterSource(browser_metrics_params); + + base::FilePath active_path; + base::GlobalHistogramAllocator::ConstructFilePaths( + user_data_dir, kCrashpadHistogramAllocatorName, nullptr, &active_path, + nullptr); + // Register data that will be populated for the current run. "Active" + // files need an empty "prefs_key" because they update the file itself. + file_metrics_provider->RegisterSource(metrics::FileMetricsProvider::Params( + active_path, + metrics::FileMetricsProvider::SOURCE_HISTOGRAMS_ACTIVE_FILE, + metrics::FileMetricsProvider::ASSOCIATE_CURRENT_RUN)); + } + + return file_metrics_provider; +} + } // namespace +// Needs to be kept in sync with the writer in +// third_party/crashpad/crashpad/handler/handler_main.cc. +const char kCrashpadHistogramAllocatorName[] = "CrashpadMetrics"; + AndroidMetricsServiceClient::AndroidMetricsServiceClient() = default; AndroidMetricsServiceClient::~AndroidMetricsServiceClient() = default; // static void AndroidMetricsServiceClient::RegisterPrefs(PrefRegistrySimple* registry) { - MetricsService::RegisterPrefs(registry); - StabilityMetricsHelper::RegisterPrefs(registry); + metrics::MetricsService::RegisterPrefs(registry); + metrics::FileMetricsProvider::RegisterPrefs(registry, kBrowserMetricsName); + metrics::FileMetricsProvider::RegisterPrefs(registry, + kCrashpadHistogramAllocatorName); + metrics::StabilityMetricsHelper::RegisterPrefs(registry); + ukm::UkmService::RegisterPrefs(registry); } void AndroidMetricsServiceClient::Initialize(PrefService* pref_service) { @@ -95,8 +222,7 @@ void AndroidMetricsServiceClient::MaybeStartMetrics() { bool user_consent_or_flag = user_consent_ || IsMetricsReportingForceEnabled(); if (IsConsentDetermined()) { if (app_consent_ && user_consent_or_flag) { - metrics_service_ = CreateMetricsService(metrics_state_manager_.get(), - this, pref_service_); + CreateMetricsService(metrics_state_manager_.get(), this, pref_service_); // Register for notifications so we can detect when the user or app are // interacting with the embedder. We use these as signals to wake up the // MetricsService. @@ -109,6 +235,8 @@ void AndroidMetricsServiceClient::MaybeStartMetrics() { // for a matching Stop() call. metrics_service_->Start(); } + + CreateUkmService(); } else { OnMetricsNotStarted(); pref_service_->ClearPref(prefs::kMetricsClientID); @@ -116,29 +244,61 @@ void AndroidMetricsServiceClient::MaybeStartMetrics() { } } -std::unique_ptr<MetricsService> -AndroidMetricsServiceClient::CreateMetricsService( +void AndroidMetricsServiceClient::CreateMetricsService( MetricsStateManager* state_manager, AndroidMetricsServiceClient* client, PrefService* prefs) { - auto service = std::make_unique<MetricsService>(state_manager, client, prefs); - service->RegisterMetricsProvider(std::make_unique<NetworkMetricsProvider>( - content::CreateNetworkConnectionTrackerAsyncGetter())); - service->RegisterMetricsProvider(std::make_unique<CPUMetricsProvider>()); - service->RegisterMetricsProvider( + metrics_service_ = + std::make_unique<MetricsService>(state_manager, client, prefs); + metrics_service_->RegisterMetricsProvider( + std::make_unique<metrics::SubprocessMetricsProvider>()); + metrics_service_->RegisterMetricsProvider( + std::make_unique<NetworkMetricsProvider>( + content::CreateNetworkConnectionTrackerAsyncGetter())); + metrics_service_->RegisterMetricsProvider( + std::make_unique<CPUMetricsProvider>()); + metrics_service_->RegisterMetricsProvider( std::make_unique<ScreenInfoMetricsProvider>()); - service->RegisterMetricsProvider( + if (client->EnablePersistentHistograms()) { + metrics_service_->RegisterMetricsProvider(CreateFileMetricsProvider( + pref_service_, metrics_state_manager_->IsMetricsReportingEnabled())); + } + metrics_service_->RegisterMetricsProvider( std::make_unique<CallStackProfileMetricsProvider>()); - service->RegisterMetricsProvider( + metrics_service_->RegisterMetricsProvider( std::make_unique<metrics::AndroidMetricsProvider>()); - service->RegisterMetricsProvider( + metrics_service_->RegisterMetricsProvider( std::make_unique<metrics::DriveMetricsProvider>( base::DIR_ANDROID_APP_DATA)); - service->RegisterMetricsProvider( + metrics_service_->RegisterMetricsProvider( std::make_unique<metrics::GPUMetricsProvider>()); - RegisterAdditionalMetricsProviders(service.get()); - service->InitializeMetricsRecordingState(); - return service; + RegisterAdditionalMetricsProviders(metrics_service_.get()); + + // The file metrics provider makes IO. + base::ScopedAllowBlocking allow_io; + metrics_service_->InitializeMetricsRecordingState(); +} + +void AndroidMetricsServiceClient::CreateUkmService() { + ukm_service_ = std::make_unique<ukm::UkmService>( + pref_service_, this, /*demographics_provider=*/nullptr); + + ukm_service_->RegisterMetricsProvider( + std::make_unique<metrics::NetworkMetricsProvider>( + content::CreateNetworkConnectionTrackerAsyncGetter())); + + ukm_service_->RegisterMetricsProvider( + std::make_unique<metrics::GPUMetricsProvider>()); + + ukm_service_->RegisterMetricsProvider( + std::make_unique<metrics::CPUMetricsProvider>()); + + ukm_service_->RegisterMetricsProvider( + std::make_unique<metrics::ScreenInfoMetricsProvider>()); + + ukm_service_->RegisterMetricsProvider(ukm::CreateFieldTrialsProviderForUkm()); + + UpdateUkmService(); } void AndroidMetricsServiceClient::RegisterForNotifications() { @@ -179,6 +339,34 @@ AndroidMetricsServiceClient::CreateLowEntropyProvider() { return metrics_state_manager_->CreateLowEntropyProvider(); } +void AndroidMetricsServiceClient::UpdateUkm(bool must_purge) { + if (!ukm_service_) + return; + if (must_purge) { + ukm_service_->Purge(); + ukm_service_->ResetClientState(ukm::ResetReason::kOnUkmAllowedStateChanged); + } + + UpdateUkmService(); +} + +void AndroidMetricsServiceClient::UpdateUkmService() { + if (!ukm_service_) + return; + + bool consent_or_flag = IsConsentGiven() || IsMetricsReportingForceEnabled(); + bool allowed = IsUkmAllowedForAllProfiles(); + bool is_incognito = IsOffTheRecordSessionActive(); + + if (consent_or_flag && allowed && !is_incognito) { + ukm_service_->EnableRecording(/*extensions=*/false); + ukm_service_->EnableReporting(); + } else { + ukm_service_->DisableRecording(); + ukm_service_->DisableReporting(); + } +} + bool AndroidMetricsServiceClient::IsConsentDetermined() const { return init_finished_ && set_consent_finished_; } @@ -203,6 +391,10 @@ MetricsService* AndroidMetricsServiceClient::GetMetricsService() { return metrics_service_.get(); } +ukm::UkmService* AndroidMetricsServiceClient::GetUkmService() { + return ukm_service_.get(); +} + // In Chrome, UMA and Crashpad are enabled/disabled together by the same // checkbox and they share the same client ID (a.k.a. GUID). SetMetricsClientId // is intended to provide the ID to Breakpad. In AndroidMetricsServiceClients @@ -229,7 +421,20 @@ std::string AndroidMetricsServiceClient::GetVersionString() { void AndroidMetricsServiceClient::CollectFinalMetricsForLog( base::OnceClosure done_callback) { - std::move(done_callback).Run(); + // Merge histograms from metrics providers into StatisticsRecorder. + base::StatisticsRecorder::ImportProvidedHistograms(); + + base::TimeDelta timeout = + base::TimeDelta::FromMilliseconds(kMaxHistogramGatheringWaitDuration); + + // Set up the callback task to call after we receive histograms from all + // child processes. |timeout| specifies how long to wait before absolutely + // calling us back on the task. + content::FetchHistogramsAsynchronously(base::ThreadTaskRunnerHandle::Get(), + std::move(done_callback), timeout); + + if (collect_final_metrics_for_log_closure_) + std::move(collect_final_metrics_for_log_closure_).Run(); } std::unique_ptr<MetricsLogUploader> AndroidMetricsServiceClient::CreateUploader( @@ -238,6 +443,15 @@ std::unique_ptr<MetricsLogUploader> AndroidMetricsServiceClient::CreateUploader( base::StringPiece mime_type, MetricsLogUploader::MetricServiceType service_type, const MetricsLogUploader::UploadCallback& on_upload_complete) { + if (service_type == metrics::MetricsLogUploader::UKM) { + // Clearcut doesn't handle UKMs. + auto url_loader_factory = GetURLLoaderFactory(); + DCHECK(url_loader_factory); + return std::make_unique<metrics::NetMetricsLogUploader>( + url_loader_factory, server_url, insecure_server_url, mime_type, + service_type, on_upload_complete); + } + // |server_url|, |insecure_server_url|, and |mime_type| are unused because // AndroidMetricsServiceClients send metrics to the platform logging mechanism // rather than to Chrome's metrics server. @@ -261,6 +475,10 @@ base::TimeDelta AndroidMetricsServiceClient::GetStandardUploadInterval() { return metrics::GetUploadInterval(false /* use_cellular_upload_interval */); } +bool AndroidMetricsServiceClient::IsUkmAllowedForAllProfiles() { + return false; +} + bool AndroidMetricsServiceClient::ShouldStartUpFastForTesting() const { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); return fast_startup_for_testing_; @@ -284,6 +502,11 @@ void AndroidMetricsServiceClient::Observe( } } +void AndroidMetricsServiceClient::SetCollectFinalMetricsForLogClosureForTesting( + base::OnceClosure closure) { + collect_final_metrics_for_log_closure_ = std::move(closure); +} + int AndroidMetricsServiceClient::GetSampleBucketValue() { return UintToPerMille(base::PersistentHash(metrics_service_->GetClientId())); } @@ -315,6 +538,10 @@ bool AndroidMetricsServiceClient::IsInPackageNameSample() { void AndroidMetricsServiceClient::RegisterAdditionalMetricsProviders( MetricsService* service) {} +bool AndroidMetricsServiceClient::EnablePersistentHistograms() { + return false; +} + std::string AndroidMetricsServiceClient::GetAppPackageName() { if (IsInPackageNameSample() && CanRecordPackageNameForAppType()) return GetAppPackageNameInternal(); @@ -330,4 +557,13 @@ std::string AndroidMetricsServiceClient::GetAppPackageNameInternal() { return std::string(); } +bool AndroidMetricsServiceClient::IsOffTheRecordSessionActive() { + return false; +} + +scoped_refptr<network::SharedURLLoaderFactory> +AndroidMetricsServiceClient::GetURLLoaderFactory() { + return nullptr; +} + } // namespace metrics diff --git a/chromium/components/embedder_support/android/metrics/android_metrics_service_client.h b/chromium/components/embedder_support/android/metrics/android_metrics_service_client.h index eba14e98dd6..c5052d706ce 100644 --- a/chromium/components/embedder_support/android/metrics/android_metrics_service_client.h +++ b/chromium/components/embedder_support/android/metrics/android_metrics_service_client.h @@ -8,6 +8,8 @@ #include <memory> #include <string> +#include "base/callback_forward.h" +#include "base/memory/scoped_refptr.h" #include "base/metrics/field_trial.h" #include "base/sequence_checker.h" #include "base/time/time.h" @@ -22,9 +24,15 @@ class PrefRegistrySimple; class PrefService; +namespace network { +class SharedURLLoaderFactory; +} + namespace metrics { class MetricsStateManager; +extern const char kCrashpadHistogramAllocatorName[]; + // AndroidMetricsServiceClient is a singleton which manages metrics collection // intended for use by WebView & WebLayer. // @@ -99,6 +107,16 @@ class AndroidMetricsServiceClient : public MetricsServiceClient, std::unique_ptr<const base::FieldTrial::EntropyProvider> CreateLowEntropyProvider(); + // Updates the state of whether UKM is enabled or not by calling back into + // IsUkmAllowedForAllProfiles(). If |must_purge| is true then currently + // collected data will be purged. + void UpdateUkm(bool must_purge); + + // Updates the state of the UKM service if it's running. This should be called + // when a BrowserContext is created or destroyed which would change the value + // of IsOffTheRecordSessionActive(). + void UpdateUkmService(); + // Whether or not consent state has been determined, regardless of whether // it is positive or negative. bool IsConsentDetermined() const; @@ -109,6 +127,7 @@ class AndroidMetricsServiceClient : public MetricsServiceClient, // MetricsServiceClient MetricsService* GetMetricsService() override; + ukm::UkmService* GetUkmService() override; void SetMetricsClientId(const std::string& client_id) override; std::string GetApplicationLocale() override; bool GetBrand(std::string* brand_code) override; @@ -123,6 +142,7 @@ class AndroidMetricsServiceClient : public MetricsServiceClient, MetricsLogUploader::MetricServiceType service_type, const MetricsLogUploader::UploadCallback& on_upload_complete) override; base::TimeDelta GetStandardUploadInterval() override; + bool IsUkmAllowedForAllProfiles() override; bool ShouldStartUpFastForTesting() const override; // Gets the embedding app's package name if it's OK to log. Otherwise, this @@ -134,6 +154,9 @@ class AndroidMetricsServiceClient : public MetricsServiceClient, const content::NotificationSource& source, const content::NotificationDetails& details) override; + // Runs |closure| when CollectFinalMetricsForLog() is called. + void SetCollectFinalMetricsForLogClosureForTesting(base::OnceClosure closure); + metrics::MetricsStateManager* metrics_state_manager() const { return metrics_state_manager_.get(); } @@ -185,10 +208,22 @@ class AndroidMetricsServiceClient : public MetricsServiceClient, // MetricsProviders. Does nothing by default. virtual void RegisterAdditionalMetricsProviders(MetricsService* service); + // Called by CreateMetricsService if metrics should be persisted. If the + // client returns true then its + // variations::PlatformFieldTrials::SetupFieldTrials needs to also call + // InstantiatePersistentHistograms. + virtual bool EnablePersistentHistograms(); + // Returns the embedding application's package name (unconditionally). Virtual // for testing. virtual std::string GetAppPackageNameInternal(); + // Returns whether there are any OffTheRecord browsers/tabs open. + virtual bool IsOffTheRecordSessionActive(); + + // Returns a URLLoaderFactory when the system uploader isn't used. + virtual scoped_refptr<network::SharedURLLoaderFactory> GetURLLoaderFactory(); + void EnsureOnValidSequence() const { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); } @@ -199,13 +234,14 @@ class AndroidMetricsServiceClient : public MetricsServiceClient, void MaybeStartMetrics(); void RegisterForNotifications(); - std::unique_ptr<MetricsService> CreateMetricsService( - MetricsStateManager* state_manager, - AndroidMetricsServiceClient* client, - PrefService* prefs); + void CreateMetricsService(MetricsStateManager* state_manager, + AndroidMetricsServiceClient* client, + PrefService* prefs); + void CreateUkmService(); std::unique_ptr<MetricsStateManager> metrics_state_manager_; std::unique_ptr<MetricsService> metrics_service_; + std::unique_ptr<ukm::UkmService> ukm_service_; content::NotificationRegistrar registrar_; PrefService* pref_service_ = nullptr; bool init_finished_ = false; @@ -219,6 +255,8 @@ class AndroidMetricsServiceClient : public MetricsServiceClient, // GetStandardUploadInterval(). base::TimeDelta overridden_upload_interval_; + base::OnceClosure collect_final_metrics_for_log_closure_; + // MetricsServiceClient may be created before the UI thread is promoted to // BrowserThread::UI. Use |sequence_checker_| to enforce that the // MetricsServiceClient is used on a single thread. diff --git a/chromium/components/embedder_support/android/metrics/android_metrics_service_client_unittest.cc b/chromium/components/embedder_support/android/metrics/android_metrics_service_client_unittest.cc index 60c1afa6a46..ac23eda0abe 100644 --- a/chromium/components/embedder_support/android/metrics/android_metrics_service_client_unittest.cc +++ b/chromium/components/embedder_support/android/metrics/android_metrics_service_client_unittest.cc @@ -104,7 +104,7 @@ class TestClient : public AndroidMetricsServiceClient { std::unique_ptr<TestingPrefServiceSimple> CreateTestPrefs() { auto prefs = std::make_unique<TestingPrefServiceSimple>(); - metrics::MetricsService::RegisterPrefs(prefs->registry()); + AndroidMetricsServiceClient::RegisterPrefs(prefs->registry()); return prefs; } diff --git a/chromium/components/embedder_support/android/view/content_view_render_view.h b/chromium/components/embedder_support/android/view/content_view_render_view.h index fe2feffd897..f56473ddf36 100644 --- a/chromium/components/embedder_support/android/view/content_view_render_view.h +++ b/chromium/components/embedder_support/android/view/content_view_render_view.h @@ -8,7 +8,6 @@ #include <memory> #include "base/android/jni_weak_ref.h" -#include "base/logging.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "content/public/browser/android/compositor_client.h" diff --git a/chromium/components/embedder_support/origin_trials/BUILD.gn b/chromium/components/embedder_support/origin_trials/BUILD.gn index 05c82ec0843..db5d7668cd6 100644 --- a/chromium/components/embedder_support/origin_trials/BUILD.gn +++ b/chromium/components/embedder_support/origin_trials/BUILD.gn @@ -4,6 +4,8 @@ source_set("origin_trials") { sources = [ + "features.cc", + "features.h", "origin_trial_policy_impl.cc", "origin_trial_policy_impl.h", ] diff --git a/chromium/components/embedder_support/origin_trials/features.cc b/chromium/components/embedder_support/origin_trials/features.cc new file mode 100644 index 00000000000..4dba61a0203 --- /dev/null +++ b/chromium/components/embedder_support/origin_trials/features.cc @@ -0,0 +1,20 @@ +// Copyright (c) 2020 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. + +#include "components/embedder_support/origin_trials/features.h" + +#include "base/feature_list.h" + +namespace embedder_support { + +// The feature is enabled by default, ensuring user from no-op groups have +// access to the underlying origin trial. +// Users from experiment group will behave the same as default. +// Users from control group will have the feature disabled, excluding them +// from the origin trial. +const base::Feature kOriginTrialsSampleAPIThirdPartyAlternativeUsage{ + "OriginTrialsSampleAPIThirdPartyAlternativeUsage", + base::FEATURE_ENABLED_BY_DEFAULT}; + +} // namespace embedder_support
\ No newline at end of file diff --git a/chromium/components/embedder_support/origin_trials/features.h b/chromium/components/embedder_support/origin_trials/features.h new file mode 100644 index 00000000000..ff06364dd90 --- /dev/null +++ b/chromium/components/embedder_support/origin_trials/features.h @@ -0,0 +1,20 @@ +// Copyright (c) 2020 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. + +#ifndef COMPONENTS_EMBEDDER_SUPPORT_ORIGIN_TRIALS_FEATURES_H_ +#define COMPONENTS_EMBEDDER_SUPPORT_ORIGIN_TRIALS_FEATURES_H_ + +namespace base { +struct Feature; +} + +namespace embedder_support { + +// Sample field trial feature for testing alternative usage restriction in +// origin trial third party tokens. +extern const base::Feature kOriginTrialsSampleAPIThirdPartyAlternativeUsage; + +} // namespace embedder_support + +#endif // COMPONENTS_EMBEDDER_SUPPORT_ORIGIN_TRIALS_FEATURES_H_
\ No newline at end of file diff --git a/chromium/components/embedder_support/origin_trials/origin_trial_policy_impl.cc b/chromium/components/embedder_support/origin_trials/origin_trial_policy_impl.cc index ff7c911adcd..cf0d8433937 100644 --- a/chromium/components/embedder_support/origin_trials/origin_trial_policy_impl.cc +++ b/chromium/components/embedder_support/origin_trials/origin_trial_policy_impl.cc @@ -12,6 +12,7 @@ #include "base/feature_list.h" #include "base/stl_util.h" #include "base/strings/string_split.h" +#include "components/embedder_support/origin_trials/features.h" #include "components/embedder_support/switches.h" #include "content/public/common/content_features.h" #include "content/public/common/origin_util.h" @@ -73,6 +74,25 @@ bool OriginTrialPolicyImpl::IsTokenDisabled( return disabled_tokens_.count(token_signature.as_string()) > 0; } +// Exclude users in Field trial control group from the corresponding origin +// trial. Users from experiment group/default group will have access to the +// origin trial. +bool OriginTrialPolicyImpl::IsFeatureDisabledForUser( + base::StringPiece feature) const { + struct OriginTrialFeatureToBaseFeatureMap { + const char* origin_trial_feature_name; + const base::Feature field_trial_feature; + } origin_trial_feature_to_field_trial_feature_map[] = { + {"FrobulateThirdParty", + kOriginTrialsSampleAPIThirdPartyAlternativeUsage}}; + for (const auto& mapping : origin_trial_feature_to_field_trial_feature_map) { + if (feature == mapping.origin_trial_feature_name) { + return !base::FeatureList::IsEnabled(mapping.field_trial_feature); + } + } + return false; +} + bool OriginTrialPolicyImpl::IsOriginSecure(const GURL& url) const { return content::IsOriginSecure(url); } diff --git a/chromium/components/embedder_support/origin_trials/origin_trial_policy_impl.h b/chromium/components/embedder_support/origin_trials/origin_trial_policy_impl.h index a5286a9a256..945f675b662 100644 --- a/chromium/components/embedder_support/origin_trials/origin_trial_policy_impl.h +++ b/chromium/components/embedder_support/origin_trials/origin_trial_policy_impl.h @@ -25,6 +25,7 @@ class OriginTrialPolicyImpl : public blink::OriginTrialPolicy { bool IsOriginTrialsSupported() const override; std::vector<base::StringPiece> GetPublicKeys() const override; bool IsFeatureDisabled(base::StringPiece feature) const override; + bool IsFeatureDisabledForUser(base::StringPiece feature) const override; bool IsTokenDisabled(base::StringPiece token_signature) const override; bool IsOriginSecure(const GURL& url) const override; diff --git a/chromium/components/embedder_support/origin_trials/origin_trial_policy_impl_unittest.cc b/chromium/components/embedder_support/origin_trials/origin_trial_policy_impl_unittest.cc index 0407bb02544..38139fe75ec 100644 --- a/chromium/components/embedder_support/origin_trials/origin_trial_policy_impl_unittest.cc +++ b/chromium/components/embedder_support/origin_trials/origin_trial_policy_impl_unittest.cc @@ -11,6 +11,8 @@ #include "base/stl_util.h" #include "base/strings/string_piece.h" #include "base/strings/string_util.h" +#include "base/test/scoped_feature_list.h" +#include "components/embedder_support/origin_trials/features.h" #include "components/embedder_support/switches.h" #include "testing/gtest/include/gtest/gtest.h" @@ -265,6 +267,17 @@ TEST_F(OriginTrialPolicyImplTest, DisableThreeTokens) { EXPECT_TRUE(manager()->IsTokenDisabled(token3_signature_)); } +TEST_F(OriginTrialPolicyImplTest, DisableFeatureForUser) { + base::test::ScopedFeatureList feature_list; + feature_list.InitAndEnableFeature( + kOriginTrialsSampleAPIThirdPartyAlternativeUsage); + EXPECT_FALSE(manager()->IsFeatureDisabledForUser("FrobulateThirdParty")); + feature_list.Reset(); + feature_list.InitAndDisableFeature( + kOriginTrialsSampleAPIThirdPartyAlternativeUsage); + EXPECT_TRUE(manager()->IsFeatureDisabledForUser("FrobulateThirdParty")); +} + // Tests for initialization from command line class OriginTrialPolicyImplInitializationTest : public OriginTrialPolicyImplTest { |