Home | History | Annotate | Download | only in config
      1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "gpu/config/gpu_control_list.h"
      6 
      7 #include "base/cpu.h"
      8 #include "base/json/json_reader.h"
      9 #include "base/logging.h"
     10 #include "base/strings/string_number_conversions.h"
     11 #include "base/strings/string_split.h"
     12 #include "base/strings/string_util.h"
     13 #include "base/sys_info.h"
     14 #include "gpu/config/gpu_info.h"
     15 #include "gpu/config/gpu_util.h"
     16 
     17 namespace gpu {
     18 namespace {
     19 
     20 // Break a version string into segments.  Return true if each segment is
     21 // a valid number.
     22 bool ProcessVersionString(const std::string& version_string,
     23                           char splitter,
     24                           std::vector<std::string>* version) {
     25   DCHECK(version);
     26   base::SplitString(version_string, splitter, version);
     27   if (version->size() == 0)
     28     return false;
     29   // If the splitter is '-', we assume it's a date with format "mm-dd-yyyy";
     30   // we split it into the order of "yyyy", "mm", "dd".
     31   if (splitter == '-') {
     32     std::string year = (*version)[version->size() - 1];
     33     for (int i = version->size() - 1; i > 0; --i) {
     34       (*version)[i] = (*version)[i - 1];
     35     }
     36     (*version)[0] = year;
     37   }
     38   for (size_t i = 0; i < version->size(); ++i) {
     39     unsigned num = 0;
     40     if (!base::StringToUint((*version)[i], &num))
     41       return false;
     42   }
     43   return true;
     44 }
     45 
     46 // Compare two number strings using numerical ordering.
     47 // Return  0 if number = number_ref,
     48 //         1 if number > number_ref,
     49 //        -1 if number < number_ref.
     50 int CompareNumericalNumberStrings(
     51     const std::string& number, const std::string& number_ref) {
     52   unsigned value1 = 0;
     53   unsigned value2 = 0;
     54   bool valid = base::StringToUint(number, &value1);
     55   DCHECK(valid);
     56   valid = base::StringToUint(number_ref, &value2);
     57   DCHECK(valid);
     58   if (value1 == value2)
     59     return 0;
     60   if (value1 > value2)
     61     return 1;
     62   return -1;
     63 }
     64 
     65 // Compare two number strings using lexical ordering.
     66 // Return  0 if number = number_ref,
     67 //         1 if number > number_ref,
     68 //        -1 if number < number_ref.
     69 // We only compare as many digits as number_ref contains.
     70 // If number_ref is xxx, it's considered as xxx*
     71 // For example: CompareLexicalNumberStrings("121", "12") returns 0,
     72 //              CompareLexicalNumberStrings("12", "121") returns -1.
     73 int CompareLexicalNumberStrings(
     74     const std::string& number, const std::string& number_ref) {
     75   for (size_t i = 0; i < number_ref.length(); ++i) {
     76     unsigned value1 = 0;
     77     if (i < number.length())
     78       value1 = number[i] - '0';
     79     unsigned value2 = number_ref[i] - '0';
     80     if (value1 > value2)
     81       return 1;
     82     if (value1 < value2)
     83       return -1;
     84   }
     85   return 0;
     86 }
     87 
     88 bool GpuUnmatched(uint32 vendor_id, const std::vector<uint32>& device_id_list,
     89                   const GPUInfo::GPUDevice& gpu) {
     90   if (vendor_id == 0)
     91     return false;
     92   if (vendor_id != gpu.vendor_id)
     93     return true;
     94   bool device_specified = false;
     95   for (size_t i = 0; i < device_id_list.size(); ++i) {
     96     if (device_id_list[i] == 0)
     97       continue;
     98     if (device_id_list[i] == gpu.device_id)
     99       return false;
    100     device_specified = true;
    101   }
    102   return device_specified;
    103 }
    104 
    105 const char kMultiGpuStyleStringAMDSwitchable[] = "amd_switchable";
    106 const char kMultiGpuStyleStringOptimus[] = "optimus";
    107 
    108 const char kMultiGpuCategoryStringPrimary[] = "primary";
    109 const char kMultiGpuCategoryStringSecondary[] = "secondary";
    110 const char kMultiGpuCategoryStringAny[] = "any";
    111 
    112 const char kVersionStyleStringNumerical[] = "numerical";
    113 const char kVersionStyleStringLexical[] = "lexical";
    114 
    115 const char kOp[] = "op";
    116 
    117 }  // namespace anonymous
    118 
    119 GpuControlList::VersionInfo::VersionInfo(
    120     const std::string& version_op,
    121     const std::string& version_style,
    122     const std::string& version_string,
    123     const std::string& version_string2)
    124     : version_style_(kVersionStyleNumerical) {
    125   op_ = StringToNumericOp(version_op);
    126   if (op_ == kUnknown || op_ == kAny)
    127     return;
    128   version_style_ = StringToVersionStyle(version_style);
    129   if (!ProcessVersionString(version_string, '.', &version_)) {
    130     op_ = kUnknown;
    131     return;
    132   }
    133   if (op_ == kBetween) {
    134     if (!ProcessVersionString(version_string2, '.', &version2_))
    135       op_ = kUnknown;
    136   }
    137 }
    138 
    139 GpuControlList::VersionInfo::~VersionInfo() {
    140 }
    141 
    142 bool GpuControlList::VersionInfo::Contains(
    143     const std::string& version_string) const {
    144   return Contains(version_string, '.');
    145 }
    146 
    147 bool GpuControlList::VersionInfo::Contains(
    148     const std::string& version_string, char splitter) const {
    149   if (op_ == kUnknown)
    150     return false;
    151   if (op_ == kAny)
    152     return true;
    153   std::vector<std::string> version;
    154   if (!ProcessVersionString(version_string, splitter, &version))
    155     return false;
    156   int relation = Compare(version, version_, version_style_);
    157   if (op_ == kEQ)
    158     return (relation == 0);
    159   else if (op_ == kLT)
    160     return (relation < 0);
    161   else if (op_ == kLE)
    162     return (relation <= 0);
    163   else if (op_ == kGT)
    164     return (relation > 0);
    165   else if (op_ == kGE)
    166     return (relation >= 0);
    167   // op_ == kBetween
    168   if (relation < 0)
    169     return false;
    170   return Compare(version, version2_, version_style_) <= 0;
    171 }
    172 
    173 bool GpuControlList::VersionInfo::IsValid() const {
    174   return (op_ != kUnknown && version_style_ != kVersionStyleUnknown);
    175 }
    176 
    177 bool GpuControlList::VersionInfo::IsLexical() const {
    178   return version_style_ == kVersionStyleLexical;
    179 }
    180 
    181 // static
    182 int GpuControlList::VersionInfo::Compare(
    183     const std::vector<std::string>& version,
    184     const std::vector<std::string>& version_ref,
    185     VersionStyle version_style) {
    186   DCHECK(version.size() > 0 && version_ref.size() > 0);
    187   DCHECK(version_style != kVersionStyleUnknown);
    188   for (size_t i = 0; i < version_ref.size(); ++i) {
    189     if (i >= version.size())
    190       return 0;
    191     int ret = 0;
    192     // We assume both versions are checked by ProcessVersionString().
    193     if (i > 0 && version_style == kVersionStyleLexical)
    194       ret = CompareLexicalNumberStrings(version[i], version_ref[i]);
    195     else
    196       ret = CompareNumericalNumberStrings(version[i], version_ref[i]);
    197     if (ret != 0)
    198       return ret;
    199   }
    200   return 0;
    201 }
    202 
    203 // static
    204 GpuControlList::VersionInfo::VersionStyle
    205 GpuControlList::VersionInfo::StringToVersionStyle(
    206     const std::string& version_style) {
    207   if (version_style.empty() || version_style == kVersionStyleStringNumerical)
    208     return kVersionStyleNumerical;
    209   if (version_style == kVersionStyleStringLexical)
    210     return kVersionStyleLexical;
    211   return kVersionStyleUnknown;
    212 }
    213 
    214 GpuControlList::OsInfo::OsInfo(const std::string& os,
    215                              const std::string& version_op,
    216                              const std::string& version_string,
    217                              const std::string& version_string2) {
    218   type_ = StringToOsType(os);
    219   if (type_ != kOsUnknown) {
    220     version_info_.reset(new VersionInfo(
    221         version_op, std::string(), version_string, version_string2));
    222   }
    223 }
    224 
    225 GpuControlList::OsInfo::~OsInfo() {}
    226 
    227 bool GpuControlList::OsInfo::Contains(OsType type,
    228                                     const std::string& version) const {
    229   if (!IsValid())
    230     return false;
    231   if (type_ != type && type_ != kOsAny)
    232     return false;
    233   return version_info_->Contains(version);
    234 }
    235 
    236 bool GpuControlList::OsInfo::IsValid() const {
    237   return type_ != kOsUnknown && version_info_->IsValid();
    238 }
    239 
    240 GpuControlList::OsType GpuControlList::OsInfo::type() const {
    241   return type_;
    242 }
    243 
    244 GpuControlList::OsType GpuControlList::OsInfo::StringToOsType(
    245     const std::string& os) {
    246   if (os == "win")
    247     return kOsWin;
    248   else if (os == "macosx")
    249     return kOsMacosx;
    250   else if (os == "android")
    251     return kOsAndroid;
    252   else if (os == "linux")
    253     return kOsLinux;
    254   else if (os == "chromeos")
    255     return kOsChromeOS;
    256   else if (os == "any")
    257     return kOsAny;
    258   return kOsUnknown;
    259 }
    260 
    261 GpuControlList::MachineModelInfo::MachineModelInfo(
    262     const std::string& name_op,
    263     const std::string& name_value,
    264     const std::string& version_op,
    265     const std::string& version_string,
    266     const std::string& version_string2) {
    267   name_info_.reset(new StringInfo(name_op, name_value));
    268   version_info_.reset(new VersionInfo(
    269       version_op, std::string(), version_string, version_string2));
    270 }
    271 
    272 GpuControlList::MachineModelInfo::~MachineModelInfo() {}
    273 
    274 bool GpuControlList::MachineModelInfo::Contains(
    275     const std::string& name, const std::string& version) const {
    276   if (!IsValid())
    277     return false;
    278   if (!name_info_->Contains(name))
    279     return false;
    280   return version_info_->Contains(version);
    281 }
    282 
    283 bool GpuControlList::MachineModelInfo::IsValid() const {
    284   return name_info_->IsValid() && version_info_->IsValid();
    285 }
    286 
    287 GpuControlList::StringInfo::StringInfo(const std::string& string_op,
    288                                      const std::string& string_value) {
    289   op_ = StringToOp(string_op);
    290   value_ = StringToLowerASCII(string_value);
    291 }
    292 
    293 bool GpuControlList::StringInfo::Contains(const std::string& value) const {
    294   std::string my_value = StringToLowerASCII(value);
    295   switch (op_) {
    296     case kContains:
    297       return strstr(my_value.c_str(), value_.c_str()) != NULL;
    298     case kBeginWith:
    299       return StartsWithASCII(my_value, value_, false);
    300     case kEndWith:
    301       return EndsWith(my_value, value_, false);
    302     case kEQ:
    303       return value_ == my_value;
    304     default:
    305       return false;
    306   }
    307 }
    308 
    309 bool GpuControlList::StringInfo::IsValid() const {
    310   return op_ != kUnknown;
    311 }
    312 
    313 GpuControlList::StringInfo::Op GpuControlList::StringInfo::StringToOp(
    314     const std::string& string_op) {
    315   if (string_op == "=")
    316     return kEQ;
    317   else if (string_op == "contains")
    318     return kContains;
    319   else if (string_op == "beginwith")
    320     return kBeginWith;
    321   else if (string_op == "endwith")
    322     return kEndWith;
    323   return kUnknown;
    324 }
    325 
    326 GpuControlList::FloatInfo::FloatInfo(const std::string& float_op,
    327                                      const std::string& float_value,
    328                                      const std::string& float_value2)
    329     : op_(kUnknown),
    330       value_(0.f),
    331       value2_(0.f) {
    332   op_ = StringToNumericOp(float_op);
    333   if (op_ == kAny)
    334     return;
    335   double dvalue = 0;
    336   if (!base::StringToDouble(float_value, &dvalue)) {
    337     op_ = kUnknown;
    338     return;
    339   }
    340   value_ = static_cast<float>(dvalue);
    341   if (op_ == kBetween) {
    342     if (!base::StringToDouble(float_value2, &dvalue)) {
    343       op_ = kUnknown;
    344       return;
    345     }
    346     value2_ = static_cast<float>(dvalue);
    347   }
    348 }
    349 
    350 bool GpuControlList::FloatInfo::Contains(float value) const {
    351   if (op_ == kUnknown)
    352     return false;
    353   if (op_ == kAny)
    354     return true;
    355   if (op_ == kEQ)
    356     return (value == value_);
    357   if (op_ == kLT)
    358     return (value < value_);
    359   if (op_ == kLE)
    360     return (value <= value_);
    361   if (op_ == kGT)
    362     return (value > value_);
    363   if (op_ == kGE)
    364     return (value >= value_);
    365   DCHECK(op_ == kBetween);
    366   return ((value_ <= value && value <= value2_) ||
    367           (value2_ <= value && value <= value_));
    368 }
    369 
    370 bool GpuControlList::FloatInfo::IsValid() const {
    371   return op_ != kUnknown;
    372 }
    373 
    374 GpuControlList::IntInfo::IntInfo(const std::string& int_op,
    375                                  const std::string& int_value,
    376                                  const std::string& int_value2)
    377     : op_(kUnknown),
    378       value_(0),
    379       value2_(0) {
    380   op_ = StringToNumericOp(int_op);
    381   if (op_ == kAny)
    382     return;
    383   if (!base::StringToInt(int_value, &value_)) {
    384     op_ = kUnknown;
    385     return;
    386   }
    387   if (op_ == kBetween &&
    388       !base::StringToInt(int_value2, &value2_))
    389     op_ = kUnknown;
    390 }
    391 
    392 bool GpuControlList::IntInfo::Contains(int value) const {
    393   if (op_ == kUnknown)
    394     return false;
    395   if (op_ == kAny)
    396     return true;
    397   if (op_ == kEQ)
    398     return (value == value_);
    399   if (op_ == kLT)
    400     return (value < value_);
    401   if (op_ == kLE)
    402     return (value <= value_);
    403   if (op_ == kGT)
    404     return (value > value_);
    405   if (op_ == kGE)
    406     return (value >= value_);
    407   DCHECK(op_ == kBetween);
    408   return ((value_ <= value && value <= value2_) ||
    409           (value2_ <= value && value <= value_));
    410 }
    411 
    412 bool GpuControlList::IntInfo::IsValid() const {
    413   return op_ != kUnknown;
    414 }
    415 
    416 // static
    417 GpuControlList::ScopedGpuControlListEntry
    418 GpuControlList::GpuControlListEntry::GetEntryFromValue(
    419     const base::DictionaryValue* value, bool top_level,
    420     const FeatureMap& feature_map,
    421     bool supports_feature_type_all) {
    422   DCHECK(value);
    423   ScopedGpuControlListEntry entry(new GpuControlListEntry());
    424 
    425   size_t dictionary_entry_count = 0;
    426 
    427   if (top_level) {
    428     uint32 id;
    429     if (!value->GetInteger("id", reinterpret_cast<int*>(&id)) ||
    430         !entry->SetId(id)) {
    431       LOG(WARNING) << "Malformed id entry " << entry->id();
    432       return NULL;
    433     }
    434     dictionary_entry_count++;
    435 
    436     bool disabled;
    437     if (value->GetBoolean("disabled", &disabled)) {
    438       entry->SetDisabled(disabled);
    439       dictionary_entry_count++;
    440     }
    441   }
    442 
    443   std::string description;
    444   if (value->GetString("description", &description)) {
    445     entry->description_ = description;
    446     dictionary_entry_count++;
    447   } else {
    448     entry->description_ = "The GPU is unavailable for an unexplained reason.";
    449   }
    450 
    451   const base::ListValue* cr_bugs;
    452   if (value->GetList("cr_bugs", &cr_bugs)) {
    453     for (size_t i = 0; i < cr_bugs->GetSize(); ++i) {
    454       int bug_id;
    455       if (cr_bugs->GetInteger(i, &bug_id)) {
    456         entry->cr_bugs_.push_back(bug_id);
    457       } else {
    458         LOG(WARNING) << "Malformed cr_bugs entry " << entry->id();
    459         return NULL;
    460       }
    461     }
    462     dictionary_entry_count++;
    463   }
    464 
    465   const base::ListValue* webkit_bugs;
    466   if (value->GetList("webkit_bugs", &webkit_bugs)) {
    467     for (size_t i = 0; i < webkit_bugs->GetSize(); ++i) {
    468       int bug_id;
    469       if (webkit_bugs->GetInteger(i, &bug_id)) {
    470         entry->webkit_bugs_.push_back(bug_id);
    471       } else {
    472         LOG(WARNING) << "Malformed webkit_bugs entry " << entry->id();
    473         return NULL;
    474       }
    475     }
    476     dictionary_entry_count++;
    477   }
    478 
    479   const base::DictionaryValue* os_value = NULL;
    480   if (value->GetDictionary("os", &os_value)) {
    481     std::string os_type;
    482     std::string os_version_op = "any";
    483     std::string os_version_string;
    484     std::string os_version_string2;
    485     os_value->GetString("type", &os_type);
    486     const base::DictionaryValue* os_version_value = NULL;
    487     if (os_value->GetDictionary("version", &os_version_value)) {
    488       os_version_value->GetString(kOp, &os_version_op);
    489       os_version_value->GetString("number", &os_version_string);
    490       os_version_value->GetString("number2", &os_version_string2);
    491     }
    492     if (!entry->SetOsInfo(os_type, os_version_op, os_version_string,
    493                           os_version_string2)) {
    494       LOG(WARNING) << "Malformed os entry " << entry->id();
    495       return NULL;
    496     }
    497     dictionary_entry_count++;
    498   }
    499 
    500   std::string vendor_id;
    501   if (value->GetString("vendor_id", &vendor_id)) {
    502     if (!entry->SetVendorId(vendor_id)) {
    503       LOG(WARNING) << "Malformed vendor_id entry " << entry->id();
    504       return NULL;
    505     }
    506     dictionary_entry_count++;
    507   }
    508 
    509   const base::ListValue* device_id_list;
    510   if (value->GetList("device_id", &device_id_list)) {
    511     for (size_t i = 0; i < device_id_list->GetSize(); ++i) {
    512         std::string device_id;
    513       if (!device_id_list->GetString(i, &device_id) ||
    514           !entry->AddDeviceId(device_id)) {
    515         LOG(WARNING) << "Malformed device_id entry " << entry->id();
    516         return NULL;
    517       }
    518     }
    519     dictionary_entry_count++;
    520   }
    521 
    522   std::string multi_gpu_style;
    523   if (value->GetString("multi_gpu_style", &multi_gpu_style)) {
    524     if (!entry->SetMultiGpuStyle(multi_gpu_style)) {
    525       LOG(WARNING) << "Malformed multi_gpu_style entry " << entry->id();
    526       return NULL;
    527     }
    528     dictionary_entry_count++;
    529   }
    530 
    531   std::string multi_gpu_category;
    532   if (value->GetString("multi_gpu_category", &multi_gpu_category)) {
    533     if (!entry->SetMultiGpuCategory(multi_gpu_category)) {
    534       LOG(WARNING) << "Malformed multi_gpu_category entry " << entry->id();
    535       return NULL;
    536     }
    537     dictionary_entry_count++;
    538   }
    539 
    540   const base::DictionaryValue* driver_vendor_value = NULL;
    541   if (value->GetDictionary("driver_vendor", &driver_vendor_value)) {
    542     std::string vendor_op;
    543     std::string vendor_value;
    544     driver_vendor_value->GetString(kOp, &vendor_op);
    545     driver_vendor_value->GetString("value", &vendor_value);
    546     if (!entry->SetDriverVendorInfo(vendor_op, vendor_value)) {
    547       LOG(WARNING) << "Malformed driver_vendor entry " << entry->id();
    548       return NULL;
    549     }
    550     dictionary_entry_count++;
    551   }
    552 
    553   const base::DictionaryValue* driver_version_value = NULL;
    554   if (value->GetDictionary("driver_version", &driver_version_value)) {
    555     std::string driver_version_op = "any";
    556     std::string driver_version_style;
    557     std::string driver_version_string;
    558     std::string driver_version_string2;
    559     driver_version_value->GetString(kOp, &driver_version_op);
    560     driver_version_value->GetString("style", &driver_version_style);
    561     driver_version_value->GetString("number", &driver_version_string);
    562     driver_version_value->GetString("number2", &driver_version_string2);
    563     if (!entry->SetDriverVersionInfo(driver_version_op,
    564                                      driver_version_style,
    565                                      driver_version_string,
    566                                      driver_version_string2)) {
    567       LOG(WARNING) << "Malformed driver_version entry " << entry->id();
    568       return NULL;
    569     }
    570     dictionary_entry_count++;
    571   }
    572 
    573   const base::DictionaryValue* driver_date_value = NULL;
    574   if (value->GetDictionary("driver_date", &driver_date_value)) {
    575     std::string driver_date_op = "any";
    576     std::string driver_date_string;
    577     std::string driver_date_string2;
    578     driver_date_value->GetString(kOp, &driver_date_op);
    579     driver_date_value->GetString("number", &driver_date_string);
    580     driver_date_value->GetString("number2", &driver_date_string2);
    581     if (!entry->SetDriverDateInfo(driver_date_op, driver_date_string,
    582                                   driver_date_string2)) {
    583       LOG(WARNING) << "Malformed driver_date entry " << entry->id();
    584       return NULL;
    585     }
    586     dictionary_entry_count++;
    587   }
    588 
    589   const base::DictionaryValue* gl_vendor_value = NULL;
    590   if (value->GetDictionary("gl_vendor", &gl_vendor_value)) {
    591     std::string vendor_op;
    592     std::string vendor_value;
    593     gl_vendor_value->GetString(kOp, &vendor_op);
    594     gl_vendor_value->GetString("value", &vendor_value);
    595     if (!entry->SetGLVendorInfo(vendor_op, vendor_value)) {
    596       LOG(WARNING) << "Malformed gl_vendor entry " << entry->id();
    597       return NULL;
    598     }
    599     dictionary_entry_count++;
    600   }
    601 
    602   const base::DictionaryValue* gl_renderer_value = NULL;
    603   if (value->GetDictionary("gl_renderer", &gl_renderer_value)) {
    604     std::string renderer_op;
    605     std::string renderer_value;
    606     gl_renderer_value->GetString(kOp, &renderer_op);
    607     gl_renderer_value->GetString("value", &renderer_value);
    608     if (!entry->SetGLRendererInfo(renderer_op, renderer_value)) {
    609       LOG(WARNING) << "Malformed gl_renderer entry " << entry->id();
    610       return NULL;
    611     }
    612     dictionary_entry_count++;
    613   }
    614 
    615   const base::DictionaryValue* gl_extensions_value = NULL;
    616   if (value->GetDictionary("gl_extensions", &gl_extensions_value)) {
    617     std::string extensions_op;
    618     std::string extensions_value;
    619     gl_extensions_value->GetString(kOp, &extensions_op);
    620     gl_extensions_value->GetString("value", &extensions_value);
    621     if (!entry->SetGLExtensionsInfo(extensions_op, extensions_value)) {
    622       LOG(WARNING) << "Malformed gl_extensions entry " << entry->id();
    623       return NULL;
    624     }
    625     dictionary_entry_count++;
    626   }
    627 
    628   const base::DictionaryValue* gl_reset_notification_strategy_value = NULL;
    629   if (value->GetDictionary("gl_reset_notification_strategy",
    630                            &gl_reset_notification_strategy_value)) {
    631     std::string op;
    632     std::string int_value;
    633     std::string int_value2;
    634     gl_reset_notification_strategy_value->GetString(kOp, &op);
    635     gl_reset_notification_strategy_value->GetString("value", &int_value);
    636     gl_reset_notification_strategy_value->GetString("value2", &int_value2);
    637     if (!entry->SetGLResetNotificationStrategyInfo(
    638             op, int_value, int_value2)) {
    639       LOG(WARNING) << "Malformed gl_reset_notification_strategy entry "
    640                    << entry->id();
    641       return NULL;
    642     }
    643     dictionary_entry_count++;
    644   }
    645 
    646   const base::DictionaryValue* cpu_brand_value = NULL;
    647   if (value->GetDictionary("cpu_info", &cpu_brand_value)) {
    648     std::string cpu_op;
    649     std::string cpu_value;
    650     cpu_brand_value->GetString(kOp, &cpu_op);
    651     cpu_brand_value->GetString("value", &cpu_value);
    652     if (!entry->SetCpuBrand(cpu_op, cpu_value)) {
    653       LOG(WARNING) << "Malformed cpu_brand entry " << entry->id();
    654       return NULL;
    655     }
    656     dictionary_entry_count++;
    657   }
    658 
    659   const base::DictionaryValue* perf_graphics_value = NULL;
    660   if (value->GetDictionary("perf_graphics", &perf_graphics_value)) {
    661     std::string op;
    662     std::string float_value;
    663     std::string float_value2;
    664     perf_graphics_value->GetString(kOp, &op);
    665     perf_graphics_value->GetString("value", &float_value);
    666     perf_graphics_value->GetString("value2", &float_value2);
    667     if (!entry->SetPerfGraphicsInfo(op, float_value, float_value2)) {
    668       LOG(WARNING) << "Malformed perf_graphics entry " << entry->id();
    669       return NULL;
    670     }
    671     dictionary_entry_count++;
    672   }
    673 
    674   const base::DictionaryValue* perf_gaming_value = NULL;
    675   if (value->GetDictionary("perf_gaming", &perf_gaming_value)) {
    676     std::string op;
    677     std::string float_value;
    678     std::string float_value2;
    679     perf_gaming_value->GetString(kOp, &op);
    680     perf_gaming_value->GetString("value", &float_value);
    681     perf_gaming_value->GetString("value2", &float_value2);
    682     if (!entry->SetPerfGamingInfo(op, float_value, float_value2)) {
    683       LOG(WARNING) << "Malformed perf_gaming entry " << entry->id();
    684       return NULL;
    685     }
    686     dictionary_entry_count++;
    687   }
    688 
    689   const base::DictionaryValue* perf_overall_value = NULL;
    690   if (value->GetDictionary("perf_overall", &perf_overall_value)) {
    691     std::string op;
    692     std::string float_value;
    693     std::string float_value2;
    694     perf_overall_value->GetString(kOp, &op);
    695     perf_overall_value->GetString("value", &float_value);
    696     perf_overall_value->GetString("value2", &float_value2);
    697     if (!entry->SetPerfOverallInfo(op, float_value, float_value2)) {
    698       LOG(WARNING) << "Malformed perf_overall entry " << entry->id();
    699       return NULL;
    700     }
    701     dictionary_entry_count++;
    702   }
    703 
    704   const base::DictionaryValue* machine_model_value = NULL;
    705   if (value->GetDictionary("machine_model", &machine_model_value)) {
    706     std::string name_op;
    707     std::string name_value;
    708     const base::DictionaryValue* name = NULL;
    709     if (machine_model_value->GetDictionary("name", &name)) {
    710       name->GetString(kOp, &name_op);
    711       name->GetString("value", &name_value);
    712     }
    713 
    714     std::string version_op = "any";
    715     std::string version_string;
    716     std::string version_string2;
    717     const base::DictionaryValue* version_value = NULL;
    718     if (machine_model_value->GetDictionary("version", &version_value)) {
    719       version_value->GetString(kOp, &version_op);
    720       version_value->GetString("number", &version_string);
    721       version_value->GetString("number2", &version_string2);
    722     }
    723     if (!entry->SetMachineModelInfo(
    724             name_op, name_value, version_op, version_string, version_string2)) {
    725       LOG(WARNING) << "Malformed machine_model entry " << entry->id();
    726       return NULL;
    727     }
    728     dictionary_entry_count++;
    729   }
    730 
    731   const base::DictionaryValue* gpu_count_value = NULL;
    732   if (value->GetDictionary("gpu_count", &gpu_count_value)) {
    733     std::string op;
    734     std::string int_value;
    735     std::string int_value2;
    736     gpu_count_value->GetString(kOp, &op);
    737     gpu_count_value->GetString("value", &int_value);
    738     gpu_count_value->GetString("value2", &int_value2);
    739     if (!entry->SetGpuCountInfo(op, int_value, int_value2)) {
    740       LOG(WARNING) << "Malformed gpu_count entry " << entry->id();
    741       return NULL;
    742     }
    743     dictionary_entry_count++;
    744   }
    745 
    746   if (top_level) {
    747     const base::ListValue* feature_value = NULL;
    748     if (value->GetList("features", &feature_value)) {
    749       std::vector<std::string> feature_list;
    750       for (size_t i = 0; i < feature_value->GetSize(); ++i) {
    751         std::string feature;
    752         if (feature_value->GetString(i, &feature)) {
    753           feature_list.push_back(feature);
    754         } else {
    755           LOG(WARNING) << "Malformed feature entry " << entry->id();
    756           return NULL;
    757         }
    758       }
    759       if (!entry->SetFeatures(
    760               feature_list, feature_map, supports_feature_type_all)) {
    761         LOG(WARNING) << "Malformed feature entry " << entry->id();
    762         return NULL;
    763       }
    764       dictionary_entry_count++;
    765     }
    766   }
    767 
    768   if (top_level) {
    769     const base::ListValue* exception_list_value = NULL;
    770     if (value->GetList("exceptions", &exception_list_value)) {
    771       for (size_t i = 0; i < exception_list_value->GetSize(); ++i) {
    772         const base::DictionaryValue* exception_value = NULL;
    773         if (!exception_list_value->GetDictionary(i, &exception_value)) {
    774           LOG(WARNING) << "Malformed exceptions entry " << entry->id();
    775           return NULL;
    776         }
    777         ScopedGpuControlListEntry exception(GetEntryFromValue(
    778             exception_value, false, feature_map, supports_feature_type_all));
    779         if (exception.get() == NULL) {
    780           LOG(WARNING) << "Malformed exceptions entry " << entry->id();
    781           return NULL;
    782         }
    783         // Exception should inherit vendor_id from parent, otherwise if only
    784         // device_ids are specified in Exception, the info will be incomplete.
    785         if (exception->vendor_id_ == 0 && entry->vendor_id_ != 0)
    786           exception->vendor_id_ = entry->vendor_id_;
    787         if (exception->contains_unknown_fields_) {
    788           LOG(WARNING) << "Exception with unknown fields " << entry->id();
    789           entry->contains_unknown_fields_ = true;
    790         } else {
    791           entry->AddException(exception);
    792         }
    793       }
    794       dictionary_entry_count++;
    795     }
    796 
    797     const base::DictionaryValue* browser_version_value = NULL;
    798     // browser_version is processed in LoadGpuControlList().
    799     if (value->GetDictionary("browser_version", &browser_version_value))
    800       dictionary_entry_count++;
    801   }
    802 
    803   if (value->size() != dictionary_entry_count) {
    804     LOG(WARNING) << "Entry with unknown fields " << entry->id();
    805     entry->contains_unknown_fields_ = true;
    806   }
    807   return entry;
    808 }
    809 
    810 GpuControlList::GpuControlListEntry::GpuControlListEntry()
    811     : id_(0),
    812       disabled_(false),
    813       vendor_id_(0),
    814       multi_gpu_style_(kMultiGpuStyleNone),
    815       multi_gpu_category_(kMultiGpuCategoryPrimary),
    816       contains_unknown_fields_(false),
    817       contains_unknown_features_(false) {
    818 }
    819 
    820 GpuControlList::GpuControlListEntry::~GpuControlListEntry() { }
    821 
    822 bool GpuControlList::GpuControlListEntry::SetId(uint32 id) {
    823   if (id != 0) {
    824     id_ = id;
    825     return true;
    826   }
    827   return false;
    828 }
    829 
    830 void GpuControlList::GpuControlListEntry::SetDisabled(bool disabled) {
    831   disabled_ = disabled;
    832 }
    833 
    834 bool GpuControlList::GpuControlListEntry::SetOsInfo(
    835     const std::string& os,
    836     const std::string& version_op,
    837     const std::string& version_string,
    838     const std::string& version_string2) {
    839   os_info_.reset(new OsInfo(os, version_op, version_string, version_string2));
    840   return os_info_->IsValid();
    841 }
    842 
    843 bool GpuControlList::GpuControlListEntry::SetVendorId(
    844     const std::string& vendor_id_string) {
    845   vendor_id_ = 0;
    846   return base::HexStringToInt(vendor_id_string,
    847                               reinterpret_cast<int*>(&vendor_id_));
    848 }
    849 
    850 bool GpuControlList::GpuControlListEntry::AddDeviceId(
    851     const std::string& device_id_string) {
    852   uint32 device_id = 0;
    853   if (base::HexStringToInt(device_id_string,
    854                            reinterpret_cast<int*>(&device_id))) {
    855     device_id_list_.push_back(device_id);
    856     return true;
    857   }
    858   return false;
    859 }
    860 
    861 bool GpuControlList::GpuControlListEntry::SetMultiGpuStyle(
    862     const std::string& multi_gpu_style_string) {
    863   MultiGpuStyle style = StringToMultiGpuStyle(multi_gpu_style_string);
    864   if (style == kMultiGpuStyleNone)
    865     return false;
    866   multi_gpu_style_ = style;
    867   return true;
    868 }
    869 
    870 bool GpuControlList::GpuControlListEntry::SetMultiGpuCategory(
    871     const std::string& multi_gpu_category_string) {
    872   MultiGpuCategory category =
    873       StringToMultiGpuCategory(multi_gpu_category_string);
    874   if (category == kMultiGpuCategoryNone)
    875     return false;
    876   multi_gpu_category_ = category;
    877   return true;
    878 }
    879 
    880 bool GpuControlList::GpuControlListEntry::SetDriverVendorInfo(
    881     const std::string& vendor_op,
    882     const std::string& vendor_value) {
    883   driver_vendor_info_.reset(new StringInfo(vendor_op, vendor_value));
    884   return driver_vendor_info_->IsValid();
    885 }
    886 
    887 bool GpuControlList::GpuControlListEntry::SetDriverVersionInfo(
    888     const std::string& version_op,
    889     const std::string& version_style,
    890     const std::string& version_string,
    891     const std::string& version_string2) {
    892   driver_version_info_.reset(new VersionInfo(
    893       version_op, version_style, version_string, version_string2));
    894   return driver_version_info_->IsValid();
    895 }
    896 
    897 bool GpuControlList::GpuControlListEntry::SetDriverDateInfo(
    898     const std::string& date_op,
    899     const std::string& date_string,
    900     const std::string& date_string2) {
    901   driver_date_info_.reset(
    902       new VersionInfo(date_op, std::string(), date_string, date_string2));
    903   return driver_date_info_->IsValid();
    904 }
    905 
    906 bool GpuControlList::GpuControlListEntry::SetGLVendorInfo(
    907     const std::string& vendor_op,
    908     const std::string& vendor_value) {
    909   gl_vendor_info_.reset(new StringInfo(vendor_op, vendor_value));
    910   return gl_vendor_info_->IsValid();
    911 }
    912 
    913 bool GpuControlList::GpuControlListEntry::SetGLRendererInfo(
    914     const std::string& renderer_op,
    915     const std::string& renderer_value) {
    916   gl_renderer_info_.reset(new StringInfo(renderer_op, renderer_value));
    917   return gl_renderer_info_->IsValid();
    918 }
    919 
    920 bool GpuControlList::GpuControlListEntry::SetGLExtensionsInfo(
    921     const std::string& extensions_op,
    922     const std::string& extensions_value) {
    923   gl_extensions_info_.reset(new StringInfo(extensions_op, extensions_value));
    924   return gl_extensions_info_->IsValid();
    925 }
    926 
    927 bool GpuControlList::GpuControlListEntry::SetGLResetNotificationStrategyInfo(
    928     const std::string& op,
    929     const std::string& int_string,
    930     const std::string& int_string2) {
    931   gl_reset_notification_strategy_info_.reset(
    932       new IntInfo(op, int_string, int_string2));
    933   return gl_reset_notification_strategy_info_->IsValid();
    934 }
    935 
    936 bool GpuControlList::GpuControlListEntry::SetCpuBrand(
    937     const std::string& cpu_op,
    938     const std::string& cpu_value) {
    939   cpu_brand_.reset(new StringInfo(cpu_op, cpu_value));
    940   return cpu_brand_->IsValid();
    941 }
    942 
    943 bool GpuControlList::GpuControlListEntry::SetPerfGraphicsInfo(
    944     const std::string& op,
    945     const std::string& float_string,
    946     const std::string& float_string2) {
    947   perf_graphics_info_.reset(new FloatInfo(op, float_string, float_string2));
    948   return perf_graphics_info_->IsValid();
    949 }
    950 
    951 bool GpuControlList::GpuControlListEntry::SetPerfGamingInfo(
    952     const std::string& op,
    953     const std::string& float_string,
    954     const std::string& float_string2) {
    955   perf_gaming_info_.reset(new FloatInfo(op, float_string, float_string2));
    956   return perf_gaming_info_->IsValid();
    957 }
    958 
    959 bool GpuControlList::GpuControlListEntry::SetPerfOverallInfo(
    960     const std::string& op,
    961     const std::string& float_string,
    962     const std::string& float_string2) {
    963   perf_overall_info_.reset(new FloatInfo(op, float_string, float_string2));
    964   return perf_overall_info_->IsValid();
    965 }
    966 
    967 bool GpuControlList::GpuControlListEntry::SetMachineModelInfo(
    968     const std::string& name_op,
    969     const std::string& name_value,
    970     const std::string& version_op,
    971     const std::string& version_string,
    972     const std::string& version_string2) {
    973   machine_model_info_.reset(new MachineModelInfo(
    974       name_op, name_value, version_op, version_string, version_string2));
    975   return machine_model_info_->IsValid();
    976 }
    977 
    978 bool GpuControlList::GpuControlListEntry::SetGpuCountInfo(
    979     const std::string& op,
    980     const std::string& int_string,
    981     const std::string& int_string2) {
    982   gpu_count_info_.reset(new IntInfo(op, int_string, int_string2));
    983   return gpu_count_info_->IsValid();
    984 }
    985 
    986 bool GpuControlList::GpuControlListEntry::SetFeatures(
    987     const std::vector<std::string>& feature_strings,
    988     const FeatureMap& feature_map,
    989     bool supports_feature_type_all) {
    990   size_t size = feature_strings.size();
    991   if (size == 0)
    992     return false;
    993   features_.clear();
    994   for (size_t i = 0; i < size; ++i) {
    995     int feature = 0;
    996     if (supports_feature_type_all && feature_strings[i] == "all") {
    997       for (FeatureMap::const_iterator iter = feature_map.begin();
    998            iter != feature_map.end(); ++iter)
    999         features_.insert(iter->second);
   1000       continue;
   1001     }
   1002     if (StringToFeature(feature_strings[i], &feature, feature_map))
   1003       features_.insert(feature);
   1004     else
   1005       contains_unknown_features_ = true;
   1006   }
   1007   return true;
   1008 }
   1009 
   1010 void GpuControlList::GpuControlListEntry::AddException(
   1011     ScopedGpuControlListEntry exception) {
   1012   exceptions_.push_back(exception);
   1013 }
   1014 
   1015 // static
   1016 GpuControlList::GpuControlListEntry::MultiGpuStyle
   1017 GpuControlList::GpuControlListEntry::StringToMultiGpuStyle(
   1018     const std::string& style) {
   1019   if (style == kMultiGpuStyleStringOptimus)
   1020     return kMultiGpuStyleOptimus;
   1021   if (style == kMultiGpuStyleStringAMDSwitchable)
   1022     return kMultiGpuStyleAMDSwitchable;
   1023   return kMultiGpuStyleNone;
   1024 }
   1025 
   1026 // static
   1027 GpuControlList::GpuControlListEntry::MultiGpuCategory
   1028 GpuControlList::GpuControlListEntry::StringToMultiGpuCategory(
   1029     const std::string& category) {
   1030   if (category == kMultiGpuCategoryStringPrimary)
   1031     return kMultiGpuCategoryPrimary;
   1032   if (category == kMultiGpuCategoryStringSecondary)
   1033     return kMultiGpuCategorySecondary;
   1034   if (category == kMultiGpuCategoryStringAny)
   1035     return kMultiGpuCategoryAny;
   1036   return kMultiGpuCategoryNone;
   1037 }
   1038 
   1039 bool GpuControlList::GpuControlListEntry::Contains(
   1040     OsType os_type, const std::string& os_version,
   1041     const GPUInfo& gpu_info) const {
   1042   DCHECK(os_type != kOsAny);
   1043   if (os_info_.get() != NULL && !os_info_->Contains(os_type, os_version))
   1044     return false;
   1045   bool is_not_primary_gpu =
   1046       GpuUnmatched(vendor_id_, device_id_list_, gpu_info.gpu);
   1047   bool is_not_secondary_gpu = true;
   1048   for (size_t i = 0; i < gpu_info.secondary_gpus.size(); ++i) {
   1049     is_not_secondary_gpu = is_not_secondary_gpu &&
   1050         GpuUnmatched(vendor_id_, device_id_list_, gpu_info.secondary_gpus[i]);
   1051   }
   1052   switch (multi_gpu_category_) {
   1053     case kMultiGpuCategoryPrimary:
   1054       if (is_not_primary_gpu)
   1055         return false;
   1056       break;
   1057     case kMultiGpuCategorySecondary:
   1058       if (is_not_secondary_gpu)
   1059         return false;
   1060       break;
   1061     case kMultiGpuCategoryAny:
   1062       if (is_not_primary_gpu && is_not_secondary_gpu)
   1063         return false;
   1064       break;
   1065     case kMultiGpuCategoryNone:
   1066       break;
   1067   }
   1068   switch (multi_gpu_style_) {
   1069     case kMultiGpuStyleOptimus:
   1070       if (!gpu_info.optimus)
   1071         return false;
   1072       break;
   1073     case kMultiGpuStyleAMDSwitchable:
   1074       if (!gpu_info.amd_switchable)
   1075         return false;
   1076       break;
   1077     case kMultiGpuStyleNone:
   1078       break;
   1079   }
   1080   if (driver_vendor_info_.get() != NULL && !gpu_info.driver_vendor.empty() &&
   1081       !driver_vendor_info_->Contains(gpu_info.driver_vendor))
   1082     return false;
   1083   if (driver_version_info_.get() != NULL && !gpu_info.driver_version.empty()) {
   1084     if (!driver_version_info_->Contains(gpu_info.driver_version))
   1085       return false;
   1086   }
   1087   if (driver_date_info_.get() != NULL && !gpu_info.driver_date.empty()) {
   1088     if (!driver_date_info_->Contains(gpu_info.driver_date, '-'))
   1089       return false;
   1090   }
   1091   if (gl_vendor_info_.get() != NULL && !gpu_info.gl_vendor.empty() &&
   1092       !gl_vendor_info_->Contains(gpu_info.gl_vendor))
   1093     return false;
   1094   if (gl_renderer_info_.get() != NULL && !gpu_info.gl_renderer.empty() &&
   1095       !gl_renderer_info_->Contains(gpu_info.gl_renderer))
   1096     return false;
   1097   if (gl_extensions_info_.get() != NULL && !gpu_info.gl_extensions.empty() &&
   1098       !gl_extensions_info_->Contains(gpu_info.gl_extensions))
   1099     return false;
   1100   if (gl_reset_notification_strategy_info_.get() != NULL &&
   1101       !gl_reset_notification_strategy_info_->Contains(
   1102           gpu_info.gl_reset_notification_strategy))
   1103     return false;
   1104   if (perf_graphics_info_.get() != NULL &&
   1105       (gpu_info.performance_stats.graphics == 0.0 ||
   1106        !perf_graphics_info_->Contains(gpu_info.performance_stats.graphics)))
   1107     return false;
   1108   if (perf_gaming_info_.get() != NULL &&
   1109       (gpu_info.performance_stats.gaming == 0.0 ||
   1110        !perf_gaming_info_->Contains(gpu_info.performance_stats.gaming)))
   1111     return false;
   1112   if (perf_overall_info_.get() != NULL &&
   1113       (gpu_info.performance_stats.overall == 0.0 ||
   1114        !perf_overall_info_->Contains(gpu_info.performance_stats.overall)))
   1115     return false;
   1116   if (machine_model_info_.get() != NULL) {
   1117     std::vector<std::string> name_version;
   1118     base::SplitString(gpu_info.machine_model, ' ', &name_version);
   1119     if (name_version.size() == 2 &&
   1120         !machine_model_info_->Contains(name_version[0], name_version[1]))
   1121       return false;
   1122   }
   1123   if (gpu_count_info_.get() != NULL &&
   1124       !gpu_count_info_->Contains(gpu_info.secondary_gpus.size() + 1))
   1125     return false;
   1126   if (cpu_brand_.get() != NULL) {
   1127     base::CPU cpu_info;
   1128     if (!cpu_brand_->Contains(cpu_info.cpu_brand()))
   1129       return false;
   1130   }
   1131 
   1132   for (size_t i = 0; i < exceptions_.size(); ++i) {
   1133     if (exceptions_[i]->Contains(os_type, os_version, gpu_info) &&
   1134         !exceptions_[i]->NeedsMoreInfo(gpu_info))
   1135       return false;
   1136   }
   1137   return true;
   1138 }
   1139 
   1140 bool GpuControlList::GpuControlListEntry::NeedsMoreInfo(
   1141     const GPUInfo& gpu_info) const {
   1142   // We only check for missing info that might be collected with a gl context.
   1143   // If certain info is missing due to some error, say, we fail to collect
   1144   // vendor_id/device_id, then even if we launch GPU process and create a gl
   1145   // context, we won't gather such missing info, so we still return false.
   1146   if (driver_vendor_info_.get() && gpu_info.driver_vendor.empty())
   1147     return true;
   1148   if (driver_version_info_.get() && gpu_info.driver_version.empty())
   1149     return true;
   1150   if (gl_vendor_info_.get() && gpu_info.gl_vendor.empty())
   1151     return true;
   1152   if (gl_renderer_info_.get() && gpu_info.gl_renderer.empty())
   1153     return true;
   1154   for (size_t i = 0; i < exceptions_.size(); ++i) {
   1155     if (exceptions_[i]->NeedsMoreInfo(gpu_info))
   1156       return true;
   1157   }
   1158   return false;
   1159 }
   1160 
   1161 GpuControlList::OsType GpuControlList::GpuControlListEntry::GetOsType() const {
   1162   if (os_info_.get() == NULL)
   1163     return kOsAny;
   1164   return os_info_->type();
   1165 }
   1166 
   1167 uint32 GpuControlList::GpuControlListEntry::id() const {
   1168   return id_;
   1169 }
   1170 
   1171 bool GpuControlList::GpuControlListEntry::disabled() const {
   1172   return disabled_;
   1173 }
   1174 
   1175 const std::set<int>& GpuControlList::GpuControlListEntry::features() const {
   1176   return features_;
   1177 }
   1178 
   1179 // static
   1180 bool GpuControlList::GpuControlListEntry::StringToFeature(
   1181     const std::string& feature_name, int* feature_id,
   1182     const FeatureMap& feature_map) {
   1183   FeatureMap::const_iterator iter = feature_map.find(feature_name);
   1184   if (iter != feature_map.end()) {
   1185     *feature_id = iter->second;
   1186     return true;
   1187   }
   1188   return false;
   1189 }
   1190 
   1191 GpuControlList::GpuControlList()
   1192     : max_entry_id_(0),
   1193       contains_unknown_fields_(false),
   1194       needs_more_info_(false),
   1195       supports_feature_type_all_(false) {
   1196 }
   1197 
   1198 GpuControlList::~GpuControlList() {
   1199   Clear();
   1200 }
   1201 
   1202 bool GpuControlList::LoadList(
   1203     const std::string& json_context, GpuControlList::OsFilter os_filter) {
   1204   const std::string browser_version_string = "0";
   1205   return LoadList(browser_version_string, json_context, os_filter);
   1206 }
   1207 
   1208 bool GpuControlList::LoadList(
   1209     const std::string& browser_version_string,
   1210     const std::string& json_context,
   1211     GpuControlList::OsFilter os_filter) {
   1212   std::vector<std::string> pieces;
   1213   if (!ProcessVersionString(browser_version_string, '.', &pieces))
   1214     return false;
   1215   browser_version_ = browser_version_string;
   1216 
   1217   scoped_ptr<base::Value> root;
   1218   root.reset(base::JSONReader::Read(json_context));
   1219   if (root.get() == NULL || !root->IsType(base::Value::TYPE_DICTIONARY))
   1220     return false;
   1221 
   1222   base::DictionaryValue* root_dictionary =
   1223       static_cast<base::DictionaryValue*>(root.get());
   1224   DCHECK(root_dictionary);
   1225   return LoadList(*root_dictionary, os_filter);
   1226 }
   1227 
   1228 bool GpuControlList::LoadList(const base::DictionaryValue& parsed_json,
   1229                               GpuControlList::OsFilter os_filter) {
   1230   std::vector<ScopedGpuControlListEntry> entries;
   1231 
   1232   parsed_json.GetString("version", &version_);
   1233   std::vector<std::string> pieces;
   1234   if (!ProcessVersionString(version_, '.', &pieces))
   1235     return false;
   1236 
   1237   const base::ListValue* list = NULL;
   1238   if (!parsed_json.GetList("entries", &list))
   1239     return false;
   1240 
   1241   uint32 max_entry_id = 0;
   1242   bool contains_unknown_fields = false;
   1243   for (size_t i = 0; i < list->GetSize(); ++i) {
   1244     const base::DictionaryValue* list_item = NULL;
   1245     bool valid = list->GetDictionary(i, &list_item);
   1246     if (!valid || list_item == NULL)
   1247       return false;
   1248     // Check browser version compatibility: if the entry is not for the
   1249     // current browser version, don't process it.
   1250     BrowserVersionSupport browser_version_support =
   1251         IsEntrySupportedByCurrentBrowserVersion(list_item);
   1252     if (browser_version_support == kMalformed)
   1253       return false;
   1254     if (browser_version_support == kUnsupported)
   1255       continue;
   1256     DCHECK(browser_version_support == kSupported);
   1257     ScopedGpuControlListEntry entry(GpuControlListEntry::GetEntryFromValue(
   1258         list_item, true, feature_map_, supports_feature_type_all_));
   1259     if (entry.get() == NULL)
   1260       return false;
   1261     if (entry->id() > max_entry_id)
   1262       max_entry_id = entry->id();
   1263     // If an unknown field is encountered, skip the entry; if an unknown
   1264     // feature is encountered, ignore the feature, but keep the entry.
   1265     if (entry->contains_unknown_fields()) {
   1266       contains_unknown_fields = true;
   1267       continue;
   1268     }
   1269     if (entry->contains_unknown_features())
   1270       contains_unknown_fields = true;
   1271     entries.push_back(entry);
   1272   }
   1273 
   1274   Clear();
   1275   OsType my_os = GetOsType();
   1276   for (size_t i = 0; i < entries.size(); ++i) {
   1277     OsType entry_os = entries[i]->GetOsType();
   1278     if (os_filter == GpuControlList::kAllOs ||
   1279         entry_os == kOsAny || entry_os == my_os)
   1280       entries_.push_back(entries[i]);
   1281   }
   1282   max_entry_id_ = max_entry_id;
   1283   contains_unknown_fields_ = contains_unknown_fields;
   1284   return true;
   1285 }
   1286 
   1287 std::set<int> GpuControlList::MakeDecision(
   1288     GpuControlList::OsType os,
   1289     std::string os_version,
   1290     const GPUInfo& gpu_info) {
   1291   active_entries_.clear();
   1292   std::set<int> features;
   1293 
   1294   needs_more_info_ = false;
   1295   std::set<int> possible_features;
   1296 
   1297   if (os == kOsAny)
   1298     os = GetOsType();
   1299   if (os_version.empty()) {
   1300     os_version = base::SysInfo::OperatingSystemVersion();
   1301     size_t pos = os_version.find_first_not_of("0123456789.");
   1302     if (pos != std::string::npos)
   1303       os_version = os_version.substr(0, pos);
   1304   }
   1305   std::vector<std::string> pieces;
   1306   if (!ProcessVersionString(os_version, '.', &pieces))
   1307     os_version = "0";
   1308 
   1309   for (size_t i = 0; i < entries_.size(); ++i) {
   1310     if (entries_[i]->Contains(os, os_version, gpu_info)) {
   1311       if (!entries_[i]->disabled()) {
   1312         MergeFeatureSets(&possible_features, entries_[i]->features());
   1313         if (!entries_[i]->NeedsMoreInfo(gpu_info))
   1314           MergeFeatureSets(&features, entries_[i]->features());
   1315       }
   1316       active_entries_.push_back(entries_[i]);
   1317     }
   1318   }
   1319 
   1320   if (possible_features.size() > features.size())
   1321     needs_more_info_ = true;
   1322 
   1323   return features;
   1324 }
   1325 
   1326 void GpuControlList::GetDecisionEntries(
   1327     std::vector<uint32>* entry_ids, bool disabled) const {
   1328   DCHECK(entry_ids);
   1329   entry_ids->clear();
   1330   for (size_t i = 0; i < active_entries_.size(); ++i) {
   1331     if (disabled == active_entries_[i]->disabled())
   1332       entry_ids->push_back(active_entries_[i]->id());
   1333   }
   1334 }
   1335 
   1336 void GpuControlList::GetReasons(base::ListValue* problem_list) const {
   1337   DCHECK(problem_list);
   1338   for (size_t i = 0; i < active_entries_.size(); ++i) {
   1339     GpuControlListEntry* entry = active_entries_[i].get();
   1340     if (entry->disabled())
   1341       continue;
   1342     base::DictionaryValue* problem = new base::DictionaryValue();
   1343 
   1344     problem->SetString("description", entry->description());
   1345 
   1346     base::ListValue* cr_bugs = new base::ListValue();
   1347     for (size_t j = 0; j < entry->cr_bugs().size(); ++j)
   1348       cr_bugs->Append(new base::FundamentalValue(entry->cr_bugs()[j]));
   1349     problem->Set("crBugs", cr_bugs);
   1350 
   1351     base::ListValue* webkit_bugs = new base::ListValue();
   1352     for (size_t j = 0; j < entry->webkit_bugs().size(); ++j) {
   1353       webkit_bugs->Append(new base::FundamentalValue(entry->webkit_bugs()[j]));
   1354     }
   1355     problem->Set("webkitBugs", webkit_bugs);
   1356 
   1357     problem_list->Append(problem);
   1358   }
   1359 }
   1360 
   1361 size_t GpuControlList::num_entries() const {
   1362   return entries_.size();
   1363 }
   1364 
   1365 uint32 GpuControlList::max_entry_id() const {
   1366   return max_entry_id_;
   1367 }
   1368 
   1369 std::string GpuControlList::version() const {
   1370   return version_;
   1371 }
   1372 
   1373 GpuControlList::OsType GpuControlList::GetOsType() {
   1374 #if defined(OS_CHROMEOS)
   1375   return kOsChromeOS;
   1376 #elif defined(OS_WIN)
   1377   return kOsWin;
   1378 #elif defined(OS_ANDROID)
   1379   return kOsAndroid;
   1380 #elif defined(OS_LINUX) || defined(OS_OPENBSD)
   1381   return kOsLinux;
   1382 #elif defined(OS_MACOSX)
   1383   return kOsMacosx;
   1384 #else
   1385   return kOsUnknown;
   1386 #endif
   1387 }
   1388 
   1389 void GpuControlList::Clear() {
   1390   entries_.clear();
   1391   active_entries_.clear();
   1392   max_entry_id_ = 0;
   1393   contains_unknown_fields_ = false;
   1394 }
   1395 
   1396 GpuControlList::BrowserVersionSupport
   1397 GpuControlList::IsEntrySupportedByCurrentBrowserVersion(
   1398     const base::DictionaryValue* value) {
   1399   DCHECK(value);
   1400   const base::DictionaryValue* browser_version_value = NULL;
   1401   if (value->GetDictionary("browser_version", &browser_version_value)) {
   1402     std::string version_op = "any";
   1403     std::string version_string;
   1404     std::string version_string2;
   1405     browser_version_value->GetString(kOp, &version_op);
   1406     browser_version_value->GetString("number", &version_string);
   1407     browser_version_value->GetString("number2", &version_string2);
   1408     scoped_ptr<VersionInfo> browser_version_info;
   1409     browser_version_info.reset(new VersionInfo(
   1410         version_op, std::string(), version_string, version_string2));
   1411     if (!browser_version_info->IsValid())
   1412       return kMalformed;
   1413     if (browser_version_info->Contains(browser_version_))
   1414       return kSupported;
   1415     return kUnsupported;
   1416   }
   1417   return kSupported;
   1418 }
   1419 
   1420 // static
   1421 GpuControlList::NumericOp GpuControlList::StringToNumericOp(
   1422     const std::string& op) {
   1423   if (op == "=")
   1424     return kEQ;
   1425   if (op == "<")
   1426     return kLT;
   1427   if (op == "<=")
   1428     return kLE;
   1429   if (op == ">")
   1430     return kGT;
   1431   if (op == ">=")
   1432     return kGE;
   1433   if (op == "any")
   1434     return kAny;
   1435   if (op == "between")
   1436     return kBetween;
   1437   return kUnknown;
   1438 }
   1439 
   1440 void GpuControlList::AddSupportedFeature(
   1441     const std::string& feature_name, int feature_id) {
   1442   feature_map_[feature_name] = feature_id;
   1443 }
   1444 
   1445 void GpuControlList::set_supports_feature_type_all(bool supported) {
   1446   supports_feature_type_all_ = supported;
   1447 }
   1448 
   1449 }  // namespace gpu
   1450 
   1451