blob: a3292e62e198615cbc2151df2466fde77b1d740a [file] [log] [blame]
// Copyright (C) 2016 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package main
import (
"fmt"
"regexp"
"strings"
"android.googlesource.com/platform/tools/gpu/client/adb"
"android.googlesource.com/platform/tools/gpu/client/gapis"
"android.googlesource.com/platform/tools/gpu/framework/app"
"android.googlesource.com/platform/tools/gpu/framework/log"
"android.googlesource.com/platform/tools/gpu/gapid/auth"
"android.googlesource.com/platform/tools/gpu/gapid/service"
"android.googlesource.com/platform/tools/gpu/gapid/service/path"
)
type gapisFlags struct {
profile string
port int
authToken string
argStr string
}
func (f *gapisFlags) bind(verb *app.Verb) {
verb.Flags.IntVar(&f.port, "gapis", 0, "gapis tcp port to connect to, 0 means start new instance.")
verb.Flags.StringVar(&f.profile, "profile", "", "produce a pprof file from gapis")
verb.Flags.StringVar(&f.authToken, "gapis-auth-token", "", "The connection authorization token for gapis")
verb.Flags.StringVar(&f.argStr, "gapis-args", "", `"<The arguments to be passed to gapis>"`)
}
type gapirFlags struct {
argStr string
device string
}
func (f *gapirFlags) bind(verb *app.Verb) {
verb.Flags.StringVar(&f.argStr, "gapir-args", "", `"<The arguments to be passed to gapir>"`)
verb.Flags.StringVar(&f.device, "device", "host", `"Device to spawn GAPIR on. One of: 'host', 'android' or <device-serial>"`)
}
type replayFlags struct {
gapis gapisFlags
gapir gapirFlags
}
func (f *replayFlags) bind(verb *app.Verb) {
f.gapis.bind(verb)
f.gapir.bind(verb)
}
func getGapis(ctx log.Context, gapisFlags gapisFlags, gapirFlags gapirFlags) (service.Client, error) {
args := strings.Fields(gapisFlags.argStr)
if gapirFlags.argStr != "" {
// Pass the arguments for gapir further to gapis. Add flag to tag the
// gapir argument string for gapis.
args = append(args, "--gapir-args", gapirFlags.argStr)
}
if gapisFlags.profile != "" {
args = append(args, "-cpuprofile", gapisFlags.profile)
}
token := auth.GenToken()
if gapisFlags.authToken != "" {
token = auth.Token(gapisFlags.authToken)
}
client, _, err := gapis.Connect(ctx, gapisFlags.port, token, args...)
if err != nil {
return nil, ctx.WrapError(err, "Failed to connect to the GAPIS server")
}
return client.(service.Client), nil
}
func getDevice(ctx log.Context, client service.Client, flags replayFlags) (*path.Device, error) {
ctx = ctx.S("device", flags.gapir.device)
paths, err := client.GetDevices(ctx)
if err != nil {
return nil, ctx.WrapError(err, "Failed query list of devices")
}
switch flags.gapir.device {
case "host":
if len(paths) > 0 {
return paths[0], nil // TODO: don't assume host is the first device!
}
case "android":
devs, err := adb.Devices(ctx)
if err != nil {
return nil, err
}
if len(devs) > 0 {
return client.RegisterAndroidDevice(ctx, devs[0].Info().Serial)
}
default:
dev, err := getADBDevice(ctx, flags.gapir.device)
if err != nil {
return nil, err
}
return client.RegisterAndroidDevice(ctx, dev.Info().Serial)
}
return nil, ctx.AsError("Device not found")
}
func getADBDevice(ctx log.Context, pattern string) (adb.Device, error) {
devices, err := adb.Devices(ctx)
if err != nil {
return nil, err
}
if len(devices) == 0 {
return nil, fmt.Errorf("No devices found")
}
info := ctx.Info()
if info.Active() {
info.Log("Device list:")
for _, test := range devices {
info.S("serial", test.Info().URL().Path).Log("")
}
}
matchingDevices := []adb.Device{}
if pattern == "" {
matchingDevices = devices
} else {
re := regexp.MustCompile("(?i)" + pattern)
for _, test := range devices {
if re.MatchString(fmt.Sprint(test)) {
matchingDevices = append(matchingDevices, test)
}
}
}
if len(matchingDevices) == 0 {
return nil, fmt.Errorf("No devices matching %q found", pattern)
} else if len(matchingDevices) > 1 {
fmt.Println("Matching devices:")
for _, test := range matchingDevices {
fmt.Print(" ")
fmt.Println(test.Info().Address)
}
return nil, fmt.Errorf("Multiple devices matching %q found", pattern)
}
info.WithValue("device", matchingDevices[0]).Log("Tracing")
return matchingDevices[0], nil
}