blob: e524337200b480b223ade8c8aba43f816fa33c15 [file] [log] [blame]
// Copyright (C) 2015 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 replay
import (
"fmt"
"sync"
"android.googlesource.com/platform/tools/gpu/binary"
"android.googlesource.com/platform/tools/gpu/binary/endian"
"android.googlesource.com/platform/tools/gpu/binary/flat"
"android.googlesource.com/platform/tools/gpu/database"
"android.googlesource.com/platform/tools/gpu/log"
"android.googlesource.com/platform/tools/gpu/replay/protocol"
"android.googlesource.com/platform/tools/gpu/service"
)
// discovery is used to find replay devices on the local machine and connected
// Android devices.
type discovery struct {
sync.Mutex
devices []Device
logger log.Logger
}
func newDiscovery(db database.Database, logger log.Logger) *discovery {
m := &discovery{logger: logger}
go m.discoverLocalDevices(db)
go m.discoverAndroidDevices(db)
return m
}
func (d *discovery) device(id binary.ID) Device {
d.Lock()
defer d.Unlock()
for _, d := range d.devices {
if d.ID() == id {
return d
}
}
return nil
}
func (d *discovery) getDevices() []Device {
d.Lock()
defer d.Unlock()
return d.devices
}
func (d *discovery) discoverAndroidDevices(db database.Database) {
dev := &androidDevice{deviceBase{device: &service.Device{
Name: "Android device",
Model: "Unknown",
}}}
if err := loadDeviceConfig(dev, db, d.logger); err == nil {
id, err := database.Store(dev.device, db, log.Nop{})
if err != nil {
panic(err)
}
dev.id = id
d.Lock()
defer d.Unlock()
d.devices = append(d.devices, dev)
} else {
log.Infof(d.logger, "Failed to communicate with Android device '%s': %v", dev.Info().Name, err)
}
}
func (d *discovery) discoverLocalDevices(db database.Database) {
dev := &localDevice{deviceBase{device: &service.Device{
Name: "Local machine",
Model: "Unknown",
}}}
if err := loadDeviceConfig(dev, db, d.logger); err == nil {
id, err := database.Store(dev.device, db, log.Nop{})
if err != nil {
panic(err)
}
dev.id = id
d.Lock()
defer d.Unlock()
d.devices = append(d.devices, dev)
} else {
log.Warningf(d.logger, "Failed to communicate with local device '%s': %v", dev.Info().Name, err)
}
}
func loadDeviceConfig(d Device, db database.Database, logger log.Logger) error {
connection, err := d.Connect()
if err != nil {
return err
}
defer connection.Close()
// Endianness has yet to be discovered - we use Little for the hand-shaking.
enc := flat.Encoder(endian.Writer(connection, endian.Little))
dec := flat.Decoder(endian.Reader(connection, endian.Little))
if err := enc.Uint8(uint8(protocol.ConnectionTypeDeviceInfo)); err != nil {
return err
}
protocolVersion, err := dec.Uint32()
if err != nil {
return err
}
td := d.Info()
switch protocolVersion {
case 1:
td.PointerSize, err = dec.Uint8()
if err != nil {
return err
}
td.PointerAlignment, err = dec.Uint8()
if err != nil {
return err
}
// TODO: Integer size
// TODO: Endianness
td.MaxMemorySize, err = dec.Uint64()
if err != nil {
return err
}
var os deviceOS
if val, err := dec.Uint8(); err == nil {
os = deviceOS(val)
} else {
return err
}
td.OS = os.String()
if td.Extensions, err = dec.String(); err != nil {
return err
}
if td.Renderer, err = dec.String(); err != nil {
return err
}
if td.Vendor, err = dec.String(); err != nil {
return err
}
if td.Version, err = dec.String(); err != nil {
return err
}
default:
return fmt.Errorf("Unsupported device protocol version: %d", protocolVersion)
}
return nil
}