Commit 9d6264d0 authored by Xiyuan Xia's avatar Xiyuan Xia Committed by Commit Bot

Add autotest private api to start/stop smoothness tracking

This CL wires the API with ash::FpsCounter to report smoothness.

Bug: 1062124
Change-Id: I5df059da64a507ee4349f0717df81633d063a7d6
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2147864
Commit-Queue: Xiyuan Xia <xiyuan@chromium.org>
Reviewed-by: default avatarJun Mukai <mukai@chromium.org>
Cr-Commit-Position: refs/heads/master@{#760258}
parent 3f284885
......@@ -6,6 +6,7 @@
#include <algorithm>
#include <deque>
#include <map>
#include <set>
#include <sstream>
#include <utility>
......@@ -19,6 +20,7 @@
#include "ash/public/cpp/autotest_private_api_utils.h"
#include "ash/public/cpp/default_frame_header.h"
#include "ash/public/cpp/desks_helper.h"
#include "ash/public/cpp/fps_counter.h"
#include "ash/public/cpp/frame_header.h"
#include "ash/public/cpp/immersive/immersive_fullscreen_controller.h"
#include "ash/public/cpp/login_screen.h"
......@@ -40,6 +42,7 @@
#include "base/feature_list.h"
#include "base/json/json_reader.h"
#include "base/lazy_instance.h"
#include "base/no_destructor.h"
#include "base/run_loop.h"
#include "base/scoped_observer.h"
#include "base/strings/strcat.h"
......@@ -679,6 +682,27 @@ int GetMouseEventFlags(api::autotest_private::MouseButton button) {
return ui::EF_NONE;
}
// Gets display id out of an optional DOMString display id argument. Returns
// false if optional display id is given but in bad format. Otherwise returns
// true and fills |display_id| with either the primary display id when the
// optional arg is not given or the parsed display id out of the arg
bool GetDisplayIdFromOptionalArg(const std::unique_ptr<std::string>& arg,
int64_t* display_id) {
if (arg.get() && !arg->empty()) {
return base::StringToInt64(*arg, display_id);
}
*display_id = display::Screen::GetScreen()->GetPrimaryDisplay().id();
return true;
}
using DisplaySmoothnessTrackers =
std::map<int64_t, std::unique_ptr<ash::FpsCounter>>;
DisplaySmoothnessTrackers* GetDisplaySmoothnessTrackers() {
static base::NoDestructor<DisplaySmoothnessTrackers> trackers;
return trackers.get();
}
} // namespace
class WindowStateChangeObserver : public aura::WindowObserver {
......@@ -4287,6 +4311,81 @@ void AutotestPrivateSetWindowBoundsFunction::WindowBoundsChanged(
}
}
///////////////////////////////////////////////////////////////////////////////
// AutotestPrivateStartSmoothnessTrackingFunction
///////////////////////////////////////////////////////////////////////////////
AutotestPrivateStartSmoothnessTrackingFunction::
~AutotestPrivateStartSmoothnessTrackingFunction() = default;
ExtensionFunction::ResponseAction
AutotestPrivateStartSmoothnessTrackingFunction::Run() {
auto params(
api::autotest_private::StartSmoothnessTracking::Params::Create(*args_));
EXTENSION_FUNCTION_VALIDATE(params);
int64_t display_id;
if (!GetDisplayIdFromOptionalArg(params->display_id, &display_id)) {
return RespondNow(
Error(base::StrCat({"Invalid display id: ", *params->display_id})));
}
auto* trackers = GetDisplaySmoothnessTrackers();
if (trackers->find(display_id) != trackers->end()) {
return RespondNow(
Error(base::StrCat({"Smoothness already tracked for display: ",
base::NumberToString(display_id)})));
}
auto* root_window = ash::Shell::GetRootWindowForDisplayId(display_id);
if (!root_window) {
return RespondNow(Error(base::StrCat(
{"Invalid display_id; no root window found for the display id ",
base::NumberToString(display_id)})));
}
(*trackers)[display_id] =
std::make_unique<ash::FpsCounter>(root_window->layer()->GetCompositor());
return RespondNow(NoArguments());
}
///////////////////////////////////////////////////////////////////////////////
// AutotestPrivateStopSmoothnessTrackingFunction
//////////////////////////////////////////////////////////////////////////////
AutotestPrivateStopSmoothnessTrackingFunction::
~AutotestPrivateStopSmoothnessTrackingFunction() = default;
ExtensionFunction::ResponseAction
AutotestPrivateStopSmoothnessTrackingFunction::Run() {
auto params(
api::autotest_private::StopSmoothnessTracking::Params::Create(*args_));
EXTENSION_FUNCTION_VALIDATE(params);
int64_t display_id;
if (!GetDisplayIdFromOptionalArg(params->display_id, &display_id)) {
return RespondNow(
Error(base::StrCat({"Invalid display id: ", *params->display_id})));
}
auto* trackers = GetDisplaySmoothnessTrackers();
auto it = trackers->find(display_id);
if (it == trackers->end()) {
return RespondNow(
Error(base::StrCat({"Smoothness is not tracked for display: ",
base::NumberToString(display_id)})));
}
auto fps_tracker = std::move(it->second);
trackers->erase(it);
const int smoothness = fps_tracker->ComputeSmoothness();
if (smoothness == -1)
return RespondNow(Error("Could not compute smoothness."));
return RespondNow(OneArgument(std::make_unique<base::Value>(smoothness)));
}
///////////////////////////////////////////////////////////////////////////////
// AutotestPrivateAPI
///////////////////////////////////////////////////////////////////////////////
......
......@@ -1201,6 +1201,27 @@ class AutotestPrivateSetWindowBoundsFunction : public ExtensionFunction {
std::unique_ptr<WindowBoundsChangeObserver> window_bounds_observer_;
};
class AutotestPrivateStartSmoothnessTrackingFunction
: public ExtensionFunction {
public:
DECLARE_EXTENSION_FUNCTION("autotestPrivate.startSmoothnessTracking",
AUTOTESTPRIVATE_STARTSMOOTHNESSTRACKING)
private:
~AutotestPrivateStartSmoothnessTrackingFunction() override;
ResponseAction Run() override;
};
class AutotestPrivateStopSmoothnessTrackingFunction : public ExtensionFunction {
public:
DECLARE_EXTENSION_FUNCTION("autotestPrivate.stopSmoothnessTracking",
AUTOTESTPRIVATE_STOPSMOOTHNESSTRACKING)
private:
~AutotestPrivateStopSmoothnessTrackingFunction() override;
ResponseAction Run() override;
};
template <>
KeyedService*
BrowserContextKeyedAPIFactory<AutotestPrivateAPI>::BuildServiceInstanceFor(
......
......@@ -533,6 +533,10 @@ namespace autotestPrivate {
};
callback WindowBoundsCallback = void (SetWindowBoundsResult result);
// Callback invoked to report the smoothness after StopSmoothnessTracking is
// called. |smoothness| is a percentage number between 0 to 100.
callback StopSmoothnessTrackingCallback = void (long smoothness);
interface Functions {
// Must be called to allow autotestPrivateAPI events to be fired.
static void initializeEvents();
......@@ -994,6 +998,18 @@ namespace autotestPrivate {
Bounds bounds,
DOMString displayId,
WindowBoundsCallback callback);
// Starts smoothness tracking for a display. If the display id is not
// specified, the primary display is used. Otherwise, the display specified
// by the display id is used.
static void startSmoothnessTracking(optional DOMString displayId,
VoidCallback callback);
// Stops smoothness tracking for a display and report the smoothness. If
// the display id is not specified, the primary display is used. Otherwise,
// the display specified by the display id is used.
static void stopSmoothnessTracking(optional DOMString displayId,
StopSmoothnessTrackingCallback callback);
};
interface Events {
......
<!--
* Copyright 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.
-->
<script src="raf.js"></script>
// Copyright 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.
window.onload = async function() {
// Waits 2 raf callbacks the notifies background page.
await new Promise(window.requestAnimationFrame);
await new Promise(window.requestAnimationFrame);
chrome.extension.getBackgroundPage().onRaf(window);
}
......@@ -17,6 +17,28 @@ function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
// Returns a promise that gets resolved after "window.requestAnimationFrame"
// callbacks happened on a front window.
var pendingRafPromise = null;
function raf() {
chrome.test.assertTrue(pendingRafPromise === null);
var res;
pendingRafPromise = new Promise((resolve) => {
res = resolve;
});
pendingRafPromise.resolve = res;
chrome.windows.create({'url': 'raf.html'}, function() {});
return pendingRafPromise;
}
function onRaf(rafWin) {
chrome.test.assertTrue(pendingRafPromise !== null);
pendingRafPromise.resolve();
pendingRafPromise = null;
rafWin.close();
}
var defaultTests = [
// logout/restart/shutdown don't do anything as we don't want to kill the
// browser with these tests.
......@@ -802,6 +824,51 @@ var defaultTests = [
});
},
function startSmoothnessTracking() {
chrome.autotestPrivate.startSmoothnessTracking(async function() {
chrome.test.assertNoLastError();
// Wait for a few frames.
await raf();
chrome.autotestPrivate.stopSmoothnessTracking(function(smoothness) {
chrome.test.assertNoLastError();
chrome.test.assertTrue(smoothness >= 0 && smoothness <= 100);
chrome.test.succeed();
});
});
},
function startSmoothnessTrackingExplicitDisplay() {
const badDisplay = '-1';
chrome.autotestPrivate.startSmoothnessTracking(badDisplay, function() {
chrome.test.assertEq(chrome.runtime.lastError.message,
'Invalid display_id; no root window found for the display id -1');
chrome.system.display.getInfo(function(info) {
var displayId = info[0].id;
chrome.autotestPrivate.startSmoothnessTracking(displayId,
async function() {
chrome.test.assertNoLastError();
// Wait for a few frames.
await raf();
chrome.autotestPrivate.stopSmoothnessTracking(badDisplay,
function(smoothness) {
chrome.test.assertEq(chrome.runtime.lastError.message,
'Smoothness is not tracked for display: -1');
chrome.autotestPrivate.stopSmoothnessTracking(displayId,
function(smoothness) {
chrome.test.assertNoLastError();
chrome.test.assertTrue(smoothness >= 0 && smoothness <= 100);
chrome.test.succeed();
});
});
});
});
});
},
// KEEP |lockScreen()| TESTS AT THE BOTTOM OF THE defaultTests AS IT WILL
// CHANGE THE SESSION STATE TO LOCKED STATE.
function lockScreen() {
......
......@@ -1527,6 +1527,8 @@ enum HistogramValue {
CRYPTOTOKENPRIVATE_RECORDSIGNREQUEST = 1464,
VIRTUALKEYBOARDPRIVATE_SETWINDOWBOUNDSINSCREEN = 1465,
AUTOTESTPRIVATE_SETWINDOWBOUNDS = 1466,
AUTOTESTPRIVATE_STARTSMOOTHNESSTRACKING = 1467,
AUTOTESTPRIVATE_STOPSMOOTHNESSTRACKING = 1468,
// Last entry: Add new entries above, then run:
// python tools/metrics/histograms/update_extension_histograms.py
ENUM_BOUNDARY
......
......@@ -22668,6 +22668,8 @@ Called by update_extension_histograms.py.-->
<int value="1464" label="CRYPTOTOKENPRIVATE_RECORDSIGNREQUEST"/>
<int value="1465" label="VIRTUALKEYBOARDPRIVATE_SETWINDOWBOUNDSINSCREEN"/>
<int value="1466" label="AUTOTESTPRIVATE_SETWINDOWBOUNDS"/>
<int value="1467" label="AUTOTESTPRIVATE_STARTSMOOTHNESSTRACKING"/>
<int value="1468" label="AUTOTESTPRIVATE_STOPSMOOTHNESSTRACKING"/>
</enum>
<enum name="ExtensionIconState">
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