Skip to content

Commit

Permalink
[iOS] Adds IOS.TabPickup.TimeSinceLastCrossDeviceSync metric
Browse files Browse the repository at this point in the history
We want to record this metric in M116 before implementing the
TabPickup feature.
To record it, a light TabPickupBrowserAgent is created. This
browser agent will be implemented in subsequent CLs.

(cherry picked from commit a1ff9d096cfebaf6e3aaf86822f621d9fcf4e3ec)

Bug: 1456732
Change-Id: Ie1fface8eb9c1255234243bfc7b8705313079ef6
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4629693
Reviewed-by: Olivier Robin <olivierrobin@chromium.org>
Reviewed-by: Christian Xu <christianxu@chromium.org>
Reviewed-by: Gauthier Ambard <gambard@chromium.org>
Commit-Queue: Ewann Pellé <ewannpv@chromium.org>
Cr-Original-Commit-Position: refs/heads/main@{#1161713}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4638064
Cr-Commit-Position: refs/branch-heads/5845@{#85}
Cr-Branched-From: 5a5dff6-refs/heads/main@{#1160321}
  • Loading branch information
Ewann Pelle authored and Chromium LUCI CQ committed Jun 26, 2023
1 parent 67db02e commit 626b057
Show file tree
Hide file tree
Showing 6 changed files with 171 additions and 6 deletions.
1 change: 1 addition & 0 deletions ios/chrome/browser/main/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ source_set("main") {
"//ios/chrome/browser/sync:sync_error_browser_agent",
"//ios/chrome/browser/tabs",
"//ios/chrome/browser/tabs:features",
"//ios/chrome/browser/tabs/tab_pickup",
"//ios/chrome/browser/ui/start_surface",
"//ios/chrome/browser/upgrade",
"//ios/chrome/browser/url_loading",
Expand Down
27 changes: 21 additions & 6 deletions ios/chrome/browser/main/browser_agent_util.mm
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#import "ios/chrome/browser/tabs/features.h"
#import "ios/chrome/browser/tabs/synced_window_delegate_browser_agent.h"
#import "ios/chrome/browser/tabs/tab_parenting_browser_agent.h"
#import "ios/chrome/browser/tabs/tab_pickup/tab_pickup_browser_agent.h"
#import "ios/chrome/browser/ui/start_surface/start_surface_recent_tab_browser_agent.h"
#import "ios/chrome/browser/upgrade/upgrade_center.h"
#import "ios/chrome/browser/upgrade/upgrade_center_browser_agent.h"
Expand All @@ -51,6 +52,11 @@ void AttachBrowserAgents(Browser* browser) {
if (breadcrumbs::IsEnabled()) {
BreadcrumbManagerBrowserAgent::CreateForBrowser(browser);
}

const bool browser_is_off_record =
browser->GetBrowserState()->IsOffTheRecord();
const bool browser_is_inactive = browser->IsInactive();

LiveTabContextBrowserAgent::CreateForBrowser(browser);
TabInsertionBrowserAgent::CreateForBrowser(browser);
AttachInfobarOverlayBrowserAgent(browser);
Expand All @@ -68,16 +74,23 @@ void AttachBrowserAgents(Browser* browser) {
ClosingWebStateObserverBrowserAgent::CreateForBrowser(browser);
SnapshotBrowserAgent::CreateForBrowser(browser);

if (IsWebChannelsEnabled() && !browser->GetBrowserState()->IsOffTheRecord())
if (!browser_is_off_record && !browser_is_inactive) {
TabPickupBrowserAgent::CreateForBrowser(browser);
}

if (IsWebChannelsEnabled() && !browser_is_off_record) {
FollowBrowserAgent::CreateForBrowser(browser);
}

// PolicyWatcher is non-OTR only.
if (!browser->GetBrowserState()->IsOffTheRecord())
if (!browser_is_off_record) {
PolicyWatcherBrowserAgent::CreateForBrowser(browser);
}

// Send Tab To Self is non-OTR only.
if (!browser->GetBrowserState()->IsOffTheRecord())
if (!browser_is_off_record) {
SendTabToSelfBrowserAgent::CreateForBrowser(browser);
}

WebStateDelegateBrowserAgent::CreateForBrowser(
browser, TabInsertionBrowserAgent::FromBrowser(browser));
Expand All @@ -102,13 +115,15 @@ void AttachBrowserAgents(Browser* browser) {
browser, SessionMetrics::FromBrowserState(browser->GetBrowserState()));

// Normal browser states are the only ones to get tab usage recorder.
if (!browser->GetBrowserState()->IsOffTheRecord())
if (!browser_is_off_record) {
TabUsageRecorderBrowserAgent::CreateForBrowser(browser);
}

if (!browser->GetBrowserState()->IsOffTheRecord())
if (!browser_is_off_record) {
StartSurfaceRecentTabBrowserAgent::CreateForBrowser(browser);
}

if (!browser->IsInactive()) {
if (!browser_is_inactive) {
SyncErrorBrowserAgent::CreateForBrowser(browser);
}

Expand Down
20 changes: 20 additions & 0 deletions ios/chrome/browser/tabs/tab_pickup/BUILD.gn
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Copyright 2023 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

source_set("tab_pickup") {
configs += [ "//build/config/compiler:enable_arc" ]
sources = [
"tab_pickup_browser_agent.h",
"tab_pickup_browser_agent.mm",
]
deps = [
"//base",
"//components/sync_sessions",
"//ios/chrome/browser/shared/model/browser",
"//ios/chrome/browser/shared/model/browser_state",
"//ios/chrome/browser/shared/model/web_state_list",
"//ios/chrome/browser/sync",
"//ios/chrome/browser/synced_sessions",
]
}
50 changes: 50 additions & 0 deletions ios/chrome/browser/tabs/tab_pickup/tab_pickup_browser_agent.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef IOS_CHROME_BROWSER_TABS_TAB_PICKUP_TAB_PICKUP_BROWSER_AGENT_H_
#define IOS_CHROME_BROWSER_TABS_TAB_PICKUP_TAB_PICKUP_BROWSER_AGENT_H_

#import "base/callback_list.h"
#import "ios/chrome/browser/shared/model/browser/browser_observer.h"
#import "ios/chrome/browser/shared/model/browser/browser_user_data.h"

class Browser;

namespace sync_sessions {
class SessionSyncService;
}

// Service that creates/replaces tab pickup infobar.
class TabPickupBrowserAgent : public BrowserObserver,
public BrowserUserData<TabPickupBrowserAgent> {
public:
TabPickupBrowserAgent(const TabPickupBrowserAgent&) = delete;
TabPickupBrowserAgent& operator=(const TabPickupBrowserAgent&) = delete;
~TabPickupBrowserAgent() override;

private:
friend class BrowserUserData<TabPickupBrowserAgent>;
BROWSER_USER_DATA_KEY_DECL();

explicit TabPickupBrowserAgent(Browser* browser);

// Called when foreign sessions change.
void ForeignSessionsChanged();

// BrowserObserver methods.
void BrowserDestroyed(Browser* browser) override;

// The owning Browser.
raw_ptr<Browser> browser_ = nullptr;
// KeyedService responsible session sync.
raw_ptr<sync_sessions::SessionSyncService> session_sync_service_ = nullptr;
// CallbackListSubscription for the SessionSyncService method.
base::CallbackListSubscription foreign_session_updated_subscription_;

// Tracks if the `IOS.TabPickup.TimeSinceLastCrossDeviceSync` metric has been
// recorded.
static bool transition_time_metric_recorded;
};

#endif // IOS_CHROME_BROWSER_TABS_TAB_PICKUP_TAB_PICKUP_BROWSER_AGENT_H_
68 changes: 68 additions & 0 deletions ios/chrome/browser/tabs/tab_pickup/tab_pickup_browser_agent.mm
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#import "ios/chrome/browser/tabs/tab_pickup/tab_pickup_browser_agent.h"

#import "base/metrics/histogram_functions.h"
#import "components/sync_sessions/session_sync_service.h"
#import "ios/chrome/browser/shared/model/browser_state/chrome_browser_state.h"
#import "ios/chrome/browser/shared/model/web_state_list/web_state_list.h"
#import "ios/chrome/browser/sync/session_sync_service_factory.h"
#import "ios/chrome/browser/synced_sessions/distant_session.h"
#import "ios/chrome/browser/synced_sessions/synced_sessions.h"

#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif

BROWSER_USER_DATA_KEY_IMPL(TabPickupBrowserAgent)

bool TabPickupBrowserAgent::transition_time_metric_recorded = false;

TabPickupBrowserAgent::TabPickupBrowserAgent(Browser* browser)
: browser_(browser),
session_sync_service_(SessionSyncServiceFactory::GetForBrowserState(
browser_->GetBrowserState())) {
browser_->AddObserver(this);

// base::Unretained() is safe below because the subscription itself is a class
// member field and handles destruction well.
foreign_session_updated_subscription_ =
session_sync_service_->SubscribeToForeignSessionsChanged(
base::BindRepeating(&TabPickupBrowserAgent::ForeignSessionsChanged,
base::Unretained(this)));
}

TabPickupBrowserAgent::~TabPickupBrowserAgent() {
DCHECK(!browser_);
}

#pragma mark - BrowserObserver

void TabPickupBrowserAgent::BrowserDestroyed(Browser* browser) {
DCHECK_EQ(browser, browser_);
browser->RemoveObserver(this);
browser_ = nullptr;
}

#pragma mark - Private methods

void TabPickupBrowserAgent::ForeignSessionsChanged() {
if (transition_time_metric_recorded) {
return;
}

auto const synced_sessions =
std::make_unique<synced_sessions::SyncedSessions>(session_sync_service_);
if (synced_sessions->GetSessionCount()) {
transition_time_metric_recorded = true;
const synced_sessions::DistantSession* session =
synced_sessions->GetSession(0);
const base::TimeDelta time_since_last_sync =
base::Time::Now() - session->modified_time;
base::UmaHistogramCustomTimes("IOS.TabPickup.TimeSinceLastCrossDeviceSync",
time_since_last_sync, base::Minutes(1),
base::Days(24), 50);
}
}
11 changes: 11 additions & 0 deletions tools/metrics/histograms/metadata/ios/histograms.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2476,6 +2476,17 @@ chromium-metrics-reviews@google.com.
</summary>
</histogram>

<histogram name="IOS.TabPickup.TimeSinceLastCrossDeviceSync" units="ms"
expires_after="2024-06-20">
<owner>ewannpv@chromium.org</owner>
<owner>gambard@chromium.org</owner>
<owner>chromeleon@google.com</owner>
<summary>
Time spent since the last time another device has been sync. Recorded when
the app starts.
</summary>
</histogram>

<histogram name="IOS.TabStrip.DragInteraction" enum="Boolean"
expires_after="2024-02-08">
<owner>ewannpv@chromium.org</owner>
Expand Down

0 comments on commit 626b057

Please sign in to comment.