Commit a2b7df9d authored by oshima's avatar oshima Committed by Commit bot

Read EDID for the 1st display for startup

BUG=449662, chrome-os-partner:35334
TEST=covered by unittest. Also tested on link_freon

Review URL: https://codereview.chromium.org/854203002

Cr-Commit-Position: refs/heads/master@{#312947}
parent 3932d125
......@@ -9,6 +9,7 @@
#include "base/hash.h"
#include "base/strings/string_util.h"
#include "base/sys_byteorder.h"
#include "ui/gfx/geometry/size.h"
namespace ui {
......@@ -37,7 +38,8 @@ bool GetDisplayIdFromEDID(const std::vector<uint8_t>& edid,
std::string product_name;
// ParseOutputDeviceData fails if it doesn't have product_name.
ParseOutputDeviceData(edid, &manufacturer_id, &product_name);
ParseOutputDeviceData(edid, &manufacturer_id, &product_name, nullptr,
nullptr);
// Generates product specific value from product_name instead of product code.
// See crbug.com/240341
......@@ -55,7 +57,9 @@ bool GetDisplayIdFromEDID(const std::vector<uint8_t>& edid,
bool ParseOutputDeviceData(const std::vector<uint8_t>& edid,
uint16_t* manufacturer_id,
std::string* human_readable_name) {
std::string* human_readable_name,
gfx::Size* active_pixel_out,
gfx::Size* physical_display_size_out) {
// See http://en.wikipedia.org/wiki/Extended_display_identification_data
// for the details of EDID data format. We use the following data:
// bytes 8-9: manufacturer EISA ID, in big-endian
......@@ -82,15 +86,57 @@ bool ParseOutputDeviceData(const std::vector<uint8_t>& edid,
#endif
}
if (!human_readable_name)
return true;
if (human_readable_name)
human_readable_name->clear();
human_readable_name->clear();
for (unsigned int i = 0; i < kNumDescriptors; ++i) {
if (edid.size() < kDescriptorOffset + (i + 1) * kDescriptorLength)
break;
size_t offset = kDescriptorOffset + i * kDescriptorLength;
// Detailed Timing Descriptor:
if (edid[offset] != 0 && edid[offset + 1] != 0) {
const int kMaxResolution = 10080; // 8k display.
if (active_pixel_out) {
const int kHorizontalPixelLsbOffset = 2;
const int kHorizontalPixelMsbOffset = 4;
const int kVerticalPixelLsbOffset = 5;
const int kVerticalPixelMsbOffset = 7;
int h_lsb = edid[offset + kHorizontalPixelLsbOffset];
int h_msb = edid[offset + kHorizontalPixelMsbOffset];
int h_pixel = std::min(h_lsb + ((h_msb & 0xF0) << 4), kMaxResolution);
int v_lsb = edid[offset + kVerticalPixelLsbOffset];
int v_msb = edid[offset + kVerticalPixelMsbOffset];
int v_pixel = std::min(v_lsb + ((v_msb & 0xF0) << 4), kMaxResolution);
active_pixel_out->SetSize(h_pixel, v_pixel);
// EDID may contain multiple DTD. Use first one that
// contains the highest resolution.
active_pixel_out = nullptr;
}
if (physical_display_size_out) {
const int kHorizontalSizeLsbOffset = 12;
const int kVerticalSizeLsbOffset = 13;
const int kSizeMsbOffset = 14;
int h_lsb = edid[offset + kHorizontalSizeLsbOffset];
int v_lsb = edid[offset + kVerticalSizeLsbOffset];
int msb = edid[offset + kSizeMsbOffset];
int h_size = h_lsb + ((msb & 0xF0) << 4);
int v_size = v_lsb + ((msb & 0x0F) << 8);
physical_display_size_out->SetSize(h_size, v_size);
physical_display_size_out = nullptr;
}
continue;
}
// EDID Other Monitor Descriptors:
// If the descriptor contains the display name, it has the following
// structure:
// bytes 0-2, 4: \0
......@@ -99,22 +145,26 @@ bool ParseOutputDeviceData(const std::vector<uint8_t>& edid,
// we should check bytes 0-2 and 4, since it may have other values in
// case that the descriptor contains other type of data.
if (edid[offset] == 0 && edid[offset + 1] == 0 && edid[offset + 2] == 0 &&
edid[offset + 3] == kMonitorNameDescriptor && edid[offset + 4] == 0) {
edid[offset + 3] == kMonitorNameDescriptor && edid[offset + 4] == 0 &&
human_readable_name) {
std::string found_name(reinterpret_cast<const char*>(&edid[offset + 5]),
kDescriptorLength - 5);
base::TrimWhitespaceASCII(
found_name, base::TRIM_TRAILING, human_readable_name);
break;
continue;
}
}
// Verify if the |human_readable_name| consists of printable characters only.
for (size_t i = 0; i < human_readable_name->size(); ++i) {
char c = (*human_readable_name)[i];
if (!isascii(c) || !isprint(c)) {
human_readable_name->clear();
LOG(ERROR) << "invalid EDID: human unreadable char in name";
return false;
// TODO(oshima|muka): Consider replacing unprintable chars with white space.
if (human_readable_name) {
for (size_t i = 0; i < human_readable_name->size(); ++i) {
char c = (*human_readable_name)[i];
if (!isascii(c) || !isprint(c)) {
human_readable_name->clear();
LOG(ERROR) << "invalid EDID: human unreadable char in name";
return false;
}
}
}
......
......@@ -12,6 +12,10 @@
#include "ui/display/util/display_util_export.h"
namespace gfx {
class Size;
}
// EDID (Extended Display Identification Data) is a format for monitor
// metadata. This provides a parser for the data.
......@@ -24,14 +28,17 @@ DISPLAY_UTIL_EXPORT bool GetDisplayIdFromEDID(const std::vector<uint8_t>& edid,
uint8_t index,
int64_t* display_id_out);
// Parses |edid| as EDID data and stores extracted data into |manufacturer_id|
// and |human_readable_name| and returns true. NULL can be passed for unwanted
// output parameters. Some devices (especially internal displays) may not have
// the field for |human_readable_name|, and it will return true in that case.
// Parses |edid| as EDID data and stores extracted data into |manufacturer_id|,
// |human_readable_name|, |active_pixel_out| and |physical_display_size_out|,
// then returns true. nullptr can be passed for unwanted output parameters.
// Some devices (especially internal displays) may not have the field for
// |human_readable_name|, and it will return true in that case.
DISPLAY_UTIL_EXPORT bool ParseOutputDeviceData(
const std::vector<uint8_t>& edid,
uint16_t* manufacturer_id,
std::string* human_readable_name);
std::string* human_readable_name,
gfx::Size* active_pixel_out,
gfx::Size* physical_display_size_out);
DISPLAY_UTIL_EXPORT bool ParseOutputOverscanFlag(
const std::vector<uint8_t>& edid,
......
......@@ -6,6 +6,7 @@
#include "base/memory/scoped_ptr.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/geometry/size.h"
namespace ui {
......@@ -93,6 +94,11 @@ const unsigned char kLP2565B[] =
"\x50\x20\x4C\x50\x32\x34\x36\x35\x0A\x20\x20\x20\x00\x00\x00\xFF"
"\x00\x43\x4E\x4B\x38\x30\x32\x30\x34\x48\x4D\x0A\x20\x20\x00\x45";
void Reset(gfx::Size* pixel, gfx::Size* size) {
pixel->SetSize(0, 0);
size->SetSize(0, 0);
}
} // namespace
TEST(EDIDParserTest, ParseOverscanFlag) {
......@@ -149,29 +155,42 @@ TEST(EDIDParserTest, ParseEDID) {
std::string human_readable_name;
std::vector<uint8_t> edid(
kNormalDisplay, kNormalDisplay + charsize(kNormalDisplay));
EXPECT_TRUE(ParseOutputDeviceData(
edid, &manufacturer_id, &human_readable_name));
gfx::Size pixel;
gfx::Size size;
EXPECT_TRUE(ParseOutputDeviceData(edid, &manufacturer_id,
&human_readable_name, &pixel, &size));
EXPECT_EQ(0x22f0u, manufacturer_id);
EXPECT_EQ("HP ZR30w", human_readable_name);
EXPECT_EQ("2560x1600", pixel.ToString());
EXPECT_EQ("641x400", size.ToString());
manufacturer_id = 0;
human_readable_name.clear();
Reset(&pixel, &size);
edid.assign(kInternalDisplay, kInternalDisplay + charsize(kInternalDisplay));
EXPECT_TRUE(ParseOutputDeviceData(edid, &manufacturer_id, NULL));
EXPECT_TRUE(
ParseOutputDeviceData(edid, &manufacturer_id, nullptr, &pixel, &size));
EXPECT_EQ(0x4ca3u, manufacturer_id);
EXPECT_EQ("", human_readable_name);
EXPECT_EQ("1280x800", pixel.ToString());
EXPECT_EQ("261x163", size.ToString());
// Internal display doesn't have name.
EXPECT_TRUE(ParseOutputDeviceData(edid, NULL, &human_readable_name));
EXPECT_TRUE(ParseOutputDeviceData(edid, nullptr, &human_readable_name, &pixel,
&size));
EXPECT_TRUE(human_readable_name.empty());
manufacturer_id = 0;
human_readable_name.clear();
Reset(&pixel, &size);
edid.assign(kOverscanDisplay, kOverscanDisplay + charsize(kOverscanDisplay));
EXPECT_TRUE(ParseOutputDeviceData(
edid, &manufacturer_id, &human_readable_name));
EXPECT_TRUE(ParseOutputDeviceData(edid, &manufacturer_id,
&human_readable_name, &pixel, &size));
EXPECT_EQ(0x4c2du, manufacturer_id);
EXPECT_EQ("SAMSUNG", human_readable_name);
EXPECT_EQ("1920x1080", pixel.ToString());
EXPECT_EQ("160x90", size.ToString());
}
TEST(EDIDParserTest, ParseBrokenEDID) {
......@@ -179,9 +198,11 @@ TEST(EDIDParserTest, ParseBrokenEDID) {
std::string human_readable_name;
std::vector<uint8_t> edid;
gfx::Size dummy;
// length == 0
EXPECT_FALSE(ParseOutputDeviceData(
edid, &manufacturer_id, &human_readable_name));
EXPECT_FALSE(ParseOutputDeviceData(edid, &manufacturer_id,
&human_readable_name, &dummy, &dummy));
// name is broken. Copying kNormalDisplay and substitute its name data by
// some control code.
......@@ -190,12 +211,13 @@ TEST(EDIDParserTest, ParseBrokenEDID) {
// display's name data is embedded in byte 95-107 in this specific example.
// Fix here too when the contents of kNormalDisplay is altered.
edid[97] = '\x1b';
EXPECT_FALSE(ParseOutputDeviceData(
edid, &manufacturer_id, &human_readable_name));
EXPECT_FALSE(ParseOutputDeviceData(edid, &manufacturer_id,
&human_readable_name, &dummy, &dummy));
// If |human_readable_name| isn't specified, it skips parsing the name.
manufacturer_id = 0;
EXPECT_TRUE(ParseOutputDeviceData(edid, &manufacturer_id, NULL));
EXPECT_TRUE(
ParseOutputDeviceData(edid, &manufacturer_id, nullptr, &dummy, &dummy));
EXPECT_EQ(0x22f0u, manufacturer_id);
}
......
......@@ -54,7 +54,7 @@ bool GetEDIDProperty(XID output, std::vector<uint8_t>* edid) {
int actual_format;
unsigned long bytes_after;
unsigned long nitems = 0;
unsigned char* prop = NULL;
unsigned char* prop = nullptr;
XRRGetOutputProperty(display,
output,
edid_property,
......@@ -78,7 +78,7 @@ bool GetEDIDProperty(XID output, std::vector<uint8_t>* edid) {
// Gets some useful data from the specified output device, such like
// manufacturer's ID, product code, and human readable name. Returns false if it
// fails to get those data and doesn't touch manufacturer ID/product code/name.
// NULL can be passed for unwanted output parameters.
// nullptr can be passed for unwanted output parameters.
bool GetOutputDeviceData(XID output,
uint16_t* manufacturer_id,
std::string* human_readable_name) {
......@@ -86,9 +86,8 @@ bool GetOutputDeviceData(XID output,
if (!GetEDIDProperty(output, &edid))
return false;
bool result = ParseOutputDeviceData(
edid, manufacturer_id, human_readable_name);
return result;
return ParseOutputDeviceData(edid, manufacturer_id, human_readable_name,
nullptr, nullptr);
}
} // namespace
......@@ -106,7 +105,7 @@ bool GetDisplayId(XID output_id,
std::string GetDisplayName(RROutput output) {
std::string display_name;
GetOutputDeviceData(output, NULL, &display_name);
GetOutputDeviceData(output, nullptr, &display_name);
return display_name;
}
......
......@@ -171,6 +171,7 @@ action("generate_constructor_list") {
test("ozone_unittests") {
sources = [
"common/display_util_unittest.cc",
"run_all_unittests.cc",
]
......
......@@ -3,6 +3,7 @@ include_rules = [
"+third_party/khronos",
"+third_party/skia",
"+ui/display/types",
"+ui/display/util",
"+ui/events",
"+ui/gfx",
"+ui/base/cursor",
......
......@@ -5,8 +5,12 @@
#include "ui/ozone/common/display_util.h"
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "ui/display/types/display_mode.h"
#include "ui/display/types/display_snapshot.h"
#include "ui/display/util/edid_parser.h"
#include "ui/display/util/edid_parser.h"
#include "ui/ozone/public/ozone_switches.h"
namespace ui {
......@@ -59,25 +63,19 @@ DisplaySnapshot_Params GetDisplaySnapshotParams(
return params;
}
DisplaySnapshot_Params CreateSnapshotFromCommandLine() {
DisplaySnapshot_Params display_param;
bool CreateSnapshotFromCommandLine(DisplaySnapshot_Params* snapshot_out) {
base::CommandLine* cmd = base::CommandLine::ForCurrentProcess();
std::string spec =
cmd->GetSwitchValueASCII(switches::kOzoneInitialDisplayBounds);
std::string physical_spec =
cmd->GetSwitchValueASCII(switches::kOzoneInitialDisplayPhysicalSizeMm);
if (spec.empty())
return display_param;
int width = 0;
int height = 0;
if (sscanf(spec.c_str(), "%dx%d", &width, &height) < 2)
return display_param;
if (width == 0 || height == 0)
return display_param;
if (spec.empty() || sscanf(spec.c_str(), "%dx%d", &width, &height) < 2 ||
width == 0 || height == 0) {
return false;
}
int physical_width = 0;
int physical_height = 0;
......@@ -87,16 +85,61 @@ DisplaySnapshot_Params CreateSnapshotFromCommandLine() {
mode_param.size = gfx::Size(width, height);
mode_param.refresh_rate = 60;
display_param.display_id = kDummyDisplayId;
display_param.modes.push_back(mode_param);
display_param.type = DISPLAY_CONNECTION_TYPE_INTERNAL;
display_param.physical_size = gfx::Size(physical_width, physical_height);
display_param.has_current_mode = true;
display_param.current_mode = mode_param;
display_param.has_native_mode = true;
display_param.native_mode = mode_param;
snapshot_out->display_id = kDummyDisplayId;
snapshot_out->modes.push_back(mode_param);
snapshot_out->type = DISPLAY_CONNECTION_TYPE_INTERNAL;
snapshot_out->physical_size = gfx::Size(physical_width, physical_height);
snapshot_out->has_current_mode = true;
snapshot_out->current_mode = mode_param;
snapshot_out->has_native_mode = true;
snapshot_out->native_mode = mode_param;
return true;
}
bool CreateSnapshotFromEDID(bool internal,
const std::vector<uint8_t>& edid,
DisplaySnapshot_Params* snapshot_out) {
uint16_t manufacturer_id = 0;
gfx::Size resolution;
DisplayMode_Params mode_param;
mode_param.refresh_rate = 60.0f;
if (!ParseOutputDeviceData(edid, &manufacturer_id,
&snapshot_out->display_name, &mode_param.size,
&snapshot_out->physical_size) ||
!GetDisplayIdFromEDID(edid, 0, &snapshot_out->display_id)) {
return false;
}
ParseOutputOverscanFlag(edid, &snapshot_out->has_overscan);
snapshot_out->modes.push_back(mode_param);
// Use VGA for external display for now.
// TODO(oshima): frecon should set this value in the display_info.bin file.
snapshot_out->type =
internal ? DISPLAY_CONNECTION_TYPE_INTERNAL : DISPLAY_CONNECTION_TYPE_VGA;
snapshot_out->has_current_mode = true;
snapshot_out->current_mode = mode_param;
snapshot_out->has_native_mode = true;
snapshot_out->native_mode = mode_param;
return true;
}
return display_param;
bool CreateSnapshotFromEDIDFile(const base::FilePath& file,
DisplaySnapshot_Params* snapshot_out) {
std::string raw_display_info;
const int kEDIDMaxSize = 128;
if (!base::ReadFileToString(file, &raw_display_info, kEDIDMaxSize + 1) ||
raw_display_info.size() < 10) {
return false;
}
std::vector<uint8_t> edid;
// The head of the file contains one byte flag that indicates the type of
// display.
bool internal = raw_display_info[0] == 1;
edid.assign(raw_display_info.c_str() + 1,
raw_display_info.c_str() + raw_display_info.size());
return CreateSnapshotFromEDID(internal, edid, snapshot_out);
}
} // namespace ui
......@@ -5,8 +5,14 @@
#ifndef UI_OZONE_COMMON_DISPLAY_UTIL_H_
#define UI_OZONE_COMMON_DISPLAY_UTIL_H_
#include <vector>
#include "ui/ozone/common/gpu/ozone_gpu_message_params.h"
namespace base {
class FilePath;
}
namespace ui {
class DisplayMode;
......@@ -28,7 +34,19 @@ DisplayMode_Params GetDisplayModeParams(const DisplayMode& mode);
DisplaySnapshot_Params GetDisplaySnapshotParams(const DisplaySnapshot& display);
// Create a display using the Ozone command line parameters.
DisplaySnapshot_Params CreateSnapshotFromCommandLine();
// Return false if the command line flags are not specified.
bool CreateSnapshotFromCommandLine(DisplaySnapshot_Params* snapshot_out);
// Create a display snapshot from |file| that contains EDID.
// Return false if the file doesn't exist, or it doesn't contain valid EDID.
bool CreateSnapshotFromEDIDFile(const base::FilePath& file,
DisplaySnapshot_Params* snapshot_out);
// Create a display snaphot from edid.
// Return false if it doesn't contain valid EDID.
bool CreateSnapshotFromEDID(bool internal,
const std::vector<uint8_t>& edid,
DisplaySnapshot_Params* snapshot_out);
} // namespace ui
......
// Copyright 2015 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.
#include "ui/ozone/common/display_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/ozone/common/gpu/ozone_gpu_message_params.h"
typedef testing::Test DisplayUtilTest;
namespace ui {
namespace {
// EDID from HP ZR30w
const unsigned char kTestEDID[] =
"\x00\xff\xff\xff\xff\xff\xff\x00\x22\xf0\x6c\x28\x01\x01\x01\x01"
"\x02\x16\x01\x04\xb5\x40\x28\x78\xe2\x8d\x85\xad\x4f\x35\xb1\x25"
"\x0e\x50\x54\x00\x00\x00\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01"
"\x01\x01\x01\x01\x01\x01\xe2\x68\x00\xa0\xa0\x40\x2e\x60\x30\x20"
"\x36\x00\x81\x90\x21\x00\x00\x1a\xbc\x1b\x00\xa0\x50\x20\x17\x30"
"\x30\x20\x36\x00\x81\x90\x21\x00\x00\x1a\x00\x00\x00\xfc\x00\x48"
"\x50\x20\x5a\x52\x33\x30\x77\x0a\x20\x20\x20\x20\x00\x00\x00\xff"
"\x00\x43\x4e\x34\x32\x30\x32\x31\x33\x37\x51\x0a\x20\x20\x00\x71";
} // namespace
TEST_F(DisplayUtilTest, BasicEDID) {
DisplaySnapshot_Params params;
// -1 to skip NULL byte.
std::vector<uint8_t> edid(kTestEDID, kTestEDID + arraysize(kTestEDID) - 1);
// External Display
EXPECT_TRUE(CreateSnapshotFromEDID(true, edid, &params));
EXPECT_EQ("HP ZR30w", params.display_name);
EXPECT_EQ(1u, params.modes.size());
EXPECT_TRUE(params.has_current_mode);
EXPECT_EQ("2560x1600", params.current_mode.size.ToString());
EXPECT_EQ("641x400", params.physical_size.ToString());
EXPECT_EQ(DISPLAY_CONNECTION_TYPE_INTERNAL, params.type);
// Reset
params = DisplaySnapshot_Params();
// External Display
EXPECT_TRUE(CreateSnapshotFromEDID(false, edid, &params));
EXPECT_EQ("HP ZR30w", params.display_name);
EXPECT_EQ(1u, params.modes.size());
EXPECT_TRUE(params.has_current_mode);
EXPECT_EQ("2560x1600", params.current_mode.size.ToString());
EXPECT_EQ("641x400", params.physical_size.ToString());
EXPECT_EQ(DISPLAY_CONNECTION_TYPE_VGA, params.type);
}
TEST_F(DisplayUtilTest, EmptyEDID) {
DisplaySnapshot_Params params;
std::vector<uint8_t> edid;
EXPECT_FALSE(CreateSnapshotFromEDID(true, std::vector<uint8_t>(), &params));
}
} // namespace ui
......@@ -17,9 +17,11 @@ NativeDisplayDelegateOzone::~NativeDisplayDelegateOzone() {
}
void NativeDisplayDelegateOzone::Initialize() {
DisplaySnapshot_Params params = CreateSnapshotFromCommandLine();
if (params.type != DISPLAY_CONNECTION_TYPE_NONE)
DisplaySnapshot_Params params;
if (CreateSnapshotFromCommandLine(&params)) {
DCHECK_NE(DISPLAY_CONNECTION_TYPE_NONE, params.type);
displays_.push_back(new DisplaySnapshotProxy(params));
}
}
void NativeDisplayDelegateOzone::GrabServer() {
......
......@@ -174,10 +174,11 @@
'target_name': 'ozone_unittests',
'type': '<(gtest_target_type)',
'sources': [
'common/display_util_unittest.cc',
'run_all_unittests.cc',
],
'dependencies': [
'ozone_base',
'ozone',
'../../base/base.gyp:base',
'../../base/base.gyp:test_support_base',
'../../testing/gtest.gyp:gtest',
......
......@@ -79,8 +79,8 @@ DisplaySnapshotDri::DisplaySnapshotDri(DriWrapper* drm,
false,
std::string(),
std::vector<const DisplayMode*>(),
NULL,
NULL),
nullptr,
nullptr),
connector_(connector->connector_id),
crtc_(crtc->crtc_id),
dpms_property_(drm->GetProperty(connector, "DPMS")) {
......@@ -98,7 +98,7 @@ DisplaySnapshotDri::DisplaySnapshotDri(DriWrapper* drm,
if (!GetDisplayIdFromEDID(edid, index, &display_id_))
display_id_ = index;
ParseOutputDeviceData(edid, NULL, &display_name_);
ParseOutputDeviceData(edid, nullptr, &display_name_, nullptr, nullptr);
ParseOutputOverscanFlag(edid, &overscan_flag_);
} else {
VLOG(1) << "Failed to get EDID blob for connector "
......
......@@ -7,6 +7,7 @@
#include <stdio.h>
#include "base/logging.h"
#include "base/threading/thread_restrictions.h"
#include "ui/display/types/display_snapshot.h"
#include "ui/display/types/native_display_observer.h"
#include "ui/events/ozone/device/device_event.h"
......@@ -63,9 +64,22 @@ void NativeDisplayDelegateProxy::Initialize() {
if (!displays_.empty())
return;
DisplaySnapshot_Params params;
bool success = false;
{
// The file generated by frecon that contains EDID for the 1st display.
const base::FilePath kEDIDFile("/tmp/display_info.bin");
// Just read it on current thread as this is necessary information
// to start. This access only tmpfs, which is fast.
// TODO(dnicoara|oshima): crbug.com/450886.
base::ThreadRestrictions::ScopedAllowIO allow_io;
success = CreateSnapshotFromEDIDFile(kEDIDFile, &params);
}
DisplaySnapshot_Params params = CreateSnapshotFromCommandLine();
if (params.type != DISPLAY_CONNECTION_TYPE_NONE) {
// Fallback to command line if the file doesn't exit or failed to read.
if (success || CreateSnapshotFromCommandLine(&params)) {
DCHECK_NE(DISPLAY_CONNECTION_TYPE_NONE, params.type);
displays_.push_back(new DriDisplaySnapshotProxy(params, display_manager_));
has_dummy_display_ = true;
}
......
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