blob: 86bd7bfbf5c9bdf5d0a4cd38af3df49918ad416e [file] [log] [blame]
// Copyright 2021 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package arc
import (
"bufio"
"context"
"io/ioutil"
"os"
"path"
"regexp"
"strconv"
"time"
"chromiumos/tast/common/perf"
"chromiumos/tast/common/testexec"
"chromiumos/tast/local/arc"
"chromiumos/tast/local/media/cpu"
"chromiumos/tast/testing"
)
func init() {
testing.AddTest(&testing.Test{
Func: RobloxUncompressOBBPerf,
Desc: "Measures time it takes to uncompress Roblox OBB file",
Contacts: []string{
"ricardoq@chromium.org",
"arc-performance+tast@google.com",
"arc-gaming+tast@google.com",
},
Attr: []string{"group:crosbolt", "crosbolt_perbuild"},
SoftwareDeps: []string{"chrome"},
Fixture: "arcBooted",
Data: []string{"com.roblox.client-886.zip"},
Params: []testing.Param{{
ExtraSoftwareDeps: []string{"android_p"},
}, {
Name: "vm",
ExtraSoftwareDeps: []string{"android_vm"},
}},
})
}
func RobloxUncompressOBBPerf(ctx context.Context, s *testing.State) {
// Roblox itself measures the time it takes to uncompress the OBB file
// and the result it logged in logcat.
// This test just grabs that value from logcat and reports it.
// Roblox has the OBB file built-in. This means that this test does not
// download the OBB, or for the matter any file, from the internet.
// However, Roblox requires internet to run. If internet is down, this test
// will fail.
// Roblox might trigger an ANR while uncompressing the OBB file (see: http://b/169182810).
// In case the ANR dialog appears, it will be closed automatically at cleanup time,
// when the Roblox APK gets uninstalled.
// Unzip "split" APK and install all the "splits" at the same time.
tempDir, err := ioutil.TempDir("", "roblox-split-apk-")
if err != nil {
s.Fatal("Failed to create temp dir: ", err)
}
defer os.RemoveAll(tempDir)
const zipName = "com.roblox.client-886.zip"
if err := testexec.CommandContext(ctx, "unzip", s.DataPath(zipName), "-d", tempDir).Run(testexec.DumpLogOnError); err != nil {
s.Fatalf("Failed to unzip %v from %v: %v", zipName, tempDir, err)
}
// These files belong to the .zip file.
apks := []string{
path.Join(tempDir, "com.roblox.client_886_base_split.apk"),
path.Join(tempDir, "com.roblox.client_886_001.apk"),
path.Join(tempDir, "com.roblox.client_886_002.apk"),
}
a := s.FixtValue().(*arc.PreData).ARC
s.Log("Installing split APK")
if err := a.InstallMultiple(ctx, apks); err != nil {
s.Fatal("Failed installing split APK: ", err)
}
// To make test as stable as possible, wait until the CPU is "idle".
if err := cpu.WaitUntilIdle(ctx); err != nil {
s.Fatal("Failed to wait until CPU is idle: ", err)
}
const (
pkgName = "com.roblox.client"
actName = ".startup.ActivitySplash"
)
act, err := arc.NewActivity(a, pkgName, actName)
if err != nil {
s.Fatal("Failed to create new activity: ", err)
}
defer act.Close()
cr := s.FixtValue().(*arc.PreData).Chrome
tconn, err := cr.TestAPIConn(ctx)
if err != nil {
s.Fatal("Failed to connect Test API: ", err)
}
s.Logf("Starting activity: %s/%s", pkgName, actName)
if err := act.Start(ctx, tconn); err != nil {
s.Fatal("Failed start activity: ", err)
}
// Set timeout for the logcat command below.
const logcatTimeout = 30 * time.Second
ctx, cancel := context.WithTimeout(ctx, logcatTimeout)
defer cancel()
// Reduce the scope of logcat entries. Searching for:
// 2304 2304 D rbx.xapkmanager: [f.e()-193]: unpackAssets_internal: unzipContainer took (ms) 2266
cmd := a.Command(ctx, "logcat", "-s", "rbx.xapkmanager:*", "-e", "unzipContainer")
pipe, err := cmd.StdoutPipe()
if err != nil {
s.Fatal("Failed to obtain a pipe for ", cmd)
}
if err := cmd.Start(); err != nil {
s.Fatal("Failed to start ", cmd)
}
defer func() {
cmd.Kill()
cmd.Wait()
}()
logcatRegexp := regexp.MustCompile(`unzipContainer took \(ms\) (\d+)`)
s.Log(ctx, "Scanning logcat output")
scanner := bufio.NewScanner(pipe)
obbTimeMS := -1
for scanner.Scan() {
l := scanner.Text()
m := logcatRegexp.FindStringSubmatch(l)
if m == nil {
continue
}
obbTimeMS, err = strconv.Atoi(m[1])
if err != nil {
s.Fatal("Failed to extract time: ", err)
}
break
}
// Happens if scanner timesout.
if obbTimeMS == -1 {
s.Fatal("Failed to get OBB unzip time")
}
obbTimeMetric := perf.Metric{Name: "obb_unzip_time", Unit: "ms", Direction: perf.SmallerIsBetter}
p := perf.NewValues()
p.Set(obbTimeMetric, float64(obbTimeMS))
if err = p.Save(s.OutDir()); err != nil {
s.Fatal("Failed saving perf data: ", err)
}
}