Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(478)

Side by Side Diff: chrome/common/extensions/api/extension_api.cc

Issue 10025007: Convert tabs, windows, and extension APIs to feature system. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Remove obsolete special cases from ExtensionPermissionSet Created 8 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/common/extensions/api/extension_api.h" 5 #include "chrome/common/extensions/api/extension_api.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <string> 8 #include <string>
9 #include <vector> 9 #include <vector>
10 10
11 #include "base/json/json_reader.h" 11 #include "base/json/json_reader.h"
12 #include "base/json/json_writer.h" 12 #include "base/json/json_writer.h"
13 #include "base/lazy_instance.h" 13 #include "base/lazy_instance.h"
14 #include "base/logging.h" 14 #include "base/logging.h"
15 #include "base/string_number_conversions.h" 15 #include "base/string_number_conversions.h"
16 #include "base/string_split.h" 16 #include "base/string_split.h"
17 #include "base/string_util.h" 17 #include "base/string_util.h"
18 #include "base/values.h" 18 #include "base/values.h"
19 #include "chrome/common/extensions/api/extension_api_feature.h"
19 #include "chrome/common/extensions/api/generated_schemas.h" 20 #include "chrome/common/extensions/api/generated_schemas.h"
20 #include "chrome/common/extensions/extension.h" 21 #include "chrome/common/extensions/extension.h"
21 #include "chrome/common/extensions/extension_permission_set.h" 22 #include "chrome/common/extensions/extension_permission_set.h"
22 #include "chrome/common/extensions/simple_feature_provider.h" 23 #include "chrome/common/extensions/simple_feature_provider.h"
23 #include "googleurl/src/gurl.h" 24 #include "googleurl/src/gurl.h"
24 #include "grit/common_resources.h" 25 #include "grit/common_resources.h"
25 #include "ui/base/resource/resource_bundle.h" 26 #include "ui/base/resource/resource_bundle.h"
26 27
27 using base::DictionaryValue; 28 using base::DictionaryValue;
28 using base::ListValue; 29 using base::ListValue;
(...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after
188 } 189 }
189 190
190 // Populate feature maps. 191 // Populate feature maps.
191 // TODO(aa): Consider not storing features that can never run on the current 192 // TODO(aa): Consider not storing features that can never run on the current
192 // machine (e.g., because of platform restrictions). 193 // machine (e.g., because of platform restrictions).
193 bool uses_feature_system = false; 194 bool uses_feature_system = false;
194 schema->GetBoolean("uses_feature_system", &uses_feature_system); 195 schema->GetBoolean("uses_feature_system", &uses_feature_system);
195 if (!uses_feature_system) 196 if (!uses_feature_system)
196 continue; 197 continue;
197 198
198 Feature* feature = new Feature(); 199 ExtensionAPIFeature* feature = new ExtensionAPIFeature();
199 feature->set_name(schema_namespace); 200 feature->set_name(schema_namespace);
200 feature->Parse(schema); 201 feature->Parse(schema);
201 202
202 FeatureMap* schema_features = new FeatureMap(); 203 if (feature->contexts()->empty()) {
204 LOG(ERROR) << "API feature '" << schema_namespace << "' includes no "
205 << "contexts and will never be available.";
not at google - send to devlin 2012/04/10 02:04:27 Why not CHECK?
Aaron Boodman 2012/04/11 21:51:54 Done.
206 }
207
203 CHECK(features_.insert( 208 CHECK(features_.insert(
204 std::make_pair(schema_namespace, 209 std::make_pair(schema_namespace,
205 make_linked_ptr(schema_features))).second); 210 make_linked_ptr(feature))).second);
206 CHECK(schema_features->insert(
207 std::make_pair("", make_linked_ptr(feature))).second);
208
209 for (size_t i = 0; i < arraysize(kChildKinds); ++i) {
210 ListValue* child_list = NULL;
211 schema->GetList(kChildKinds[i], &child_list);
212 if (!child_list)
213 continue;
214
215 for (size_t j = 0; j < child_list->GetSize(); ++j) {
216 DictionaryValue* child = NULL;
217 CHECK(child_list->GetDictionary(j, &child));
218
219 scoped_ptr<Feature> child_feature(new Feature(*feature));
220 child_feature->Parse(child);
221 if (child_feature->Equals(*feature))
222 continue; // no need to store no-op features
223
224 std::string child_name;
225 CHECK(child->GetString("name", &child_name));
226 child_feature->set_name(schema_namespace + "." + child_name);
227 CHECK(schema_features->insert(
228 std::make_pair(child_name,
229 make_linked_ptr(child_feature.release()))).second);
230 }
231 }
232 } 211 }
233 } 212 }
234 213
235 ExtensionAPI::ExtensionAPI() { 214 ExtensionAPI::ExtensionAPI() {
236 RegisterDependencyProvider("api", this); 215 RegisterDependencyProvider("api", this);
237 216
238 // TODO(aa): Can remove this when all JSON files are converted. 217 // TODO(aa): Can remove this when all JSON files are converted.
239 RegisterDependencyProvider("", this); 218 RegisterDependencyProvider("", this);
240 } 219 }
241 220
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after
399 378
400 bool ExtensionAPI::IsAvailable(const std::string& full_name, 379 bool ExtensionAPI::IsAvailable(const std::string& full_name,
401 const Extension* extension, 380 const Extension* extension,
402 Feature::Context context) { 381 Feature::Context context) {
403 std::set<std::string> dependency_names; 382 std::set<std::string> dependency_names;
404 dependency_names.insert(full_name); 383 dependency_names.insert(full_name);
405 ResolveDependencies(&dependency_names); 384 ResolveDependencies(&dependency_names);
406 385
407 for (std::set<std::string>::iterator iter = dependency_names.begin(); 386 for (std::set<std::string>::iterator iter = dependency_names.begin();
408 iter != dependency_names.end(); ++iter) { 387 iter != dependency_names.end(); ++iter) {
409 Feature* feature = GetFeatureDependency(full_name); 388 Feature* feature = GetFeatureDependency(*iter);
410 CHECK(feature) << *iter; 389 CHECK(feature) << *iter;
411 390
412 Feature::Availability availability = 391 Feature::Availability availability =
413 feature->IsAvailableToContext(extension, context); 392 feature->IsAvailableToContext(extension, context);
414 if (availability != Feature::IS_AVAILABLE) 393 if (availability != Feature::IS_AVAILABLE)
415 return false; 394 return false;
416 } 395 }
417 396
418 return true; 397 return true;
419 } 398 }
420 399
421 bool ExtensionAPI::IsPrivileged(const std::string& full_name) { 400 bool ExtensionAPI::IsPrivileged(const std::string& full_name) {
not at google - send to devlin 2012/04/10 23:55:41 Urk, it seems like "IsPrivileged" is a bit of a st
422 std::string child_name; 401 std::string child_name;
423 std::string api_name = GetAPINameFromFullName(full_name, &child_name); 402 std::string api_name = GetAPINameFromFullName(full_name, &child_name);
424 403
425 // First try to use the feature system. 404 // First try to use the feature system.
426 Feature* feature(GetFeature(full_name)); 405 Feature* feature = GetFeature(full_name);
427 if (feature) { 406 if (feature) {
428 // An API is 'privileged' if it or any of its dependencies can only be run 407 // An API is 'privileged' if it or any of its dependencies can only be run
429 // in a blessed context. 408 // in a blessed context.
430 std::set<std::string> resolved_dependencies; 409 std::set<std::string> resolved_dependencies;
431 resolved_dependencies.insert(full_name); 410 resolved_dependencies.insert(full_name);
432 ResolveDependencies(&resolved_dependencies); 411 ResolveDependencies(&resolved_dependencies);
433 for (std::set<std::string>::iterator iter = resolved_dependencies.begin(); 412 for (std::set<std::string>::iterator iter = resolved_dependencies.begin();
434 iter != resolved_dependencies.end(); ++iter) { 413 iter != resolved_dependencies.end(); ++iter) {
435 Feature* dependency = GetFeatureDependency(*iter); 414 Feature* dependency = GetFeatureDependency(*iter);
436 for (std::set<Feature::Context>::iterator context = 415 if (dependency->contexts()->size() == 1u) {
437 dependency->contexts()->begin(); 416 Feature::Context context =
438 context != dependency->contexts()->end(); ++context) { 417 *(dependency->contexts()->begin());
439 if (*context != Feature::BLESSED_EXTENSION_CONTEXT) 418 if (context == Feature::BLESSED_EXTENSION_CONTEXT)
440 return false; 419 return true;
441 } 420 }
442 } 421 }
443 return true; 422 return false;
444 } 423 }
445 424
446 // If this API hasn't been converted yet, fall back to the old system. 425 // If this API hasn't been converted yet, fall back to the old system.
447 if (completely_unprivileged_apis_.count(api_name)) 426 if (completely_unprivileged_apis_.count(api_name))
448 return false; 427 return false;
449 428
450 const DictionaryValue* schema = GetSchema(api_name); 429 const DictionaryValue* schema = GetSchema(api_name);
451 if (partially_unprivileged_apis_.count(api_name)) 430 if (partially_unprivileged_apis_.count(api_name))
452 return IsChildNamePrivileged(schema, child_name); 431 return IsChildNamePrivileged(schema, child_name);
453 432
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
497 // about every API -- and the metadata is stored in the schemas themselves. 476 // about every API -- and the metadata is stored in the schemas themselves.
498 // This is a shame. 477 // This is a shame.
499 // TODO(aa/kalman): store metadata in a separate file and don't load all 478 // TODO(aa/kalman): store metadata in a separate file and don't load all
500 // schemas. 479 // schemas.
501 LoadAllSchemas(); 480 LoadAllSchemas();
502 481
503 std::set<std::string> temp_result; 482 std::set<std::string> temp_result;
504 483
505 // First handle all the APIs that have been converted to the feature system. 484 // First handle all the APIs that have been converted to the feature system.
506 if (extension) { 485 if (extension) {
507 for (APIFeatureMap::iterator iter = features_.begin(); 486 for (FeatureMap::iterator iter = features_.begin(); iter != features_.end();
508 iter != features_.end(); ++iter) { 487 ++iter) {
509 if (IsAvailable(iter->first, extension, context)) 488 if (IsAvailable(iter->first, extension, context))
510 temp_result.insert(iter->first); 489 temp_result.insert(iter->first);
511 } 490 }
512 } 491 }
513 492
514 // Second, fall back to the old way. 493 // Second, fall back to the old way.
515 // TODO(aa): Remove this when all APIs have been converted. 494 // TODO(aa): Remove this when all APIs have been converted.
516 switch (context) { 495 switch (context) {
517 case Feature::UNSPECIFIED_CONTEXT: 496 case Feature::UNSPECIFIED_CONTEXT:
518 break; 497 break;
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
558 return result.Pass(); 537 return result.Pass();
559 } 538 }
560 539
561 Feature* ExtensionAPI::GetFeature(const std::string& full_name) { 540 Feature* ExtensionAPI::GetFeature(const std::string& full_name) {
562 // Ensure it's loaded. 541 // Ensure it's loaded.
563 GetSchema(full_name); 542 GetSchema(full_name);
564 543
565 std::string child_name; 544 std::string child_name;
566 std::string api_namespace = GetAPINameFromFullName(full_name, &child_name); 545 std::string api_namespace = GetAPINameFromFullName(full_name, &child_name);
567 546
568 APIFeatureMap::iterator feature_map = features_.find(api_namespace); 547 FeatureMap::iterator parent = features_.find(api_namespace);
569 if (feature_map == features_.end()) 548 if (parent == features_.end())
570 return NULL; 549 return NULL;
571 550
572 Feature* result = NULL; 551 Feature* child = parent->second->GetChild(child_name);
573 FeatureMap::iterator child_feature = feature_map->second->find(child_name); 552 if (child) {
574 if (child_feature != feature_map->second->end()) { 553 return child;
575 result = child_feature->second.get();
576 } else { 554 } else {
577 FeatureMap::iterator parent_feature = feature_map->second->find(""); 555 // TODO(aa): This is lame. We should generate a feature with the correct
578 CHECK(parent_feature != feature_map->second->end()); 556 // name on the fly. In order to do that, change the return type of this
579 result = parent_feature->second.get(); 557 // method to linked_ptr.
558 return parent->second.get();
580 } 559 }
581
582 if (result->contexts()->empty()) {
583 LOG(ERROR) << "API feature '" << full_name
584 << "' must specify at least one context.";
585 return NULL;
586 }
587
588 return result;
589 } 560 }
590 561
591 Feature* ExtensionAPI::GetFeatureDependency(const std::string& full_name) { 562 Feature* ExtensionAPI::GetFeatureDependency(const std::string& full_name) {
592 std::string feature_type; 563 std::string feature_type;
593 std::string feature_name; 564 std::string feature_name;
594 SplitDependencyName(full_name, &feature_type, &feature_name); 565 SplitDependencyName(full_name, &feature_type, &feature_name);
595 566
596 FeatureProviderMap::iterator provider = 567 FeatureProviderMap::iterator provider =
597 dependency_providers_.find(feature_type); 568 dependency_providers_.find(feature_type);
598 CHECK(provider != dependency_providers_.end()) << full_name; 569 CHECK(provider != dependency_providers_.end()) << full_name;
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
667 const std::set<std::string>& excluding, 638 const std::set<std::string>& excluding,
668 std::set<std::string>* out) { 639 std::set<std::string>* out) {
669 std::string feature_type; 640 std::string feature_type;
670 std::string feature_name; 641 std::string feature_name;
671 SplitDependencyName(api_name, &feature_type, &feature_name); 642 SplitDependencyName(api_name, &feature_type, &feature_name);
672 643
673 // Only API features can have dependencies for now. 644 // Only API features can have dependencies for now.
674 if (feature_type != "api") 645 if (feature_type != "api")
675 return; 646 return;
676 647
648 // If this API is controlled by the feature system, use it to get dependencies
649 // to avoid loading the schema.
650 ExtensionAPIFeature* feature =
651 static_cast<ExtensionAPIFeature*>(GetFeature(api_name));
652 if (feature) {
653 for (std::set<std::string>::iterator iter =
654 feature->dependencies()->begin();
655 iter != feature->dependencies()->end(); ++iter) {
not at google - send to devlin 2012/04/10 23:55:41 nit: I think this would fit on 1 line. Certainly i
Aaron Boodman 2012/04/11 21:51:54 Done.
656 out->insert(*iter);
657 }
658 return;
659 }
660
661 // Otherwise, fall back to the old system.
677 const DictionaryValue* schema = GetSchema(feature_name); 662 const DictionaryValue* schema = GetSchema(feature_name);
678 CHECK(schema) << "Schema for " << feature_name << " not found"; 663 CHECK(schema) << "Schema for " << feature_name << " not found";
679 664
680 ListValue* dependencies = NULL; 665 ListValue* dependencies = NULL;
681 if (!schema->GetList("dependencies", &dependencies)) 666 if (!schema->GetList("dependencies", &dependencies))
682 return; 667 return;
683 668
684 for (size_t i = 0; i < dependencies->GetSize(); ++i) { 669 for (size_t i = 0; i < dependencies->GetSize(); ++i) {
685 std::string dependency_name; 670 std::string dependency_name;
686 if (dependencies->GetString(i, &dependency_name) && 671 if (dependencies->GetString(i, &dependency_name) &&
687 !excluding.count(dependency_name)) { 672 !excluding.count(dependency_name)) {
688 out->insert(dependency_name); 673 out->insert(dependency_name);
689 } 674 }
690 } 675 }
691 } 676 }
692 677
693 void ExtensionAPI::RemovePrivilegedAPIs(std::set<std::string>* apis) { 678 void ExtensionAPI::RemovePrivilegedAPIs(std::set<std::string>* apis) {
694 std::set<std::string> privileged_apis; 679 std::set<std::string> privileged_apis;
695 for (std::set<std::string>::iterator i = apis->begin(); i != apis->end(); 680 for (std::set<std::string>::iterator i = apis->begin(); i != apis->end();
696 ++i) { 681 ++i) {
682 if (features_.find(*i) != features_.end()) {
not at google - send to devlin 2012/04/10 23:55:41 This pattern is being used a lot. How about adding
Aaron Boodman 2012/04/11 21:51:54 I like it. Done.
683 // This API is controlled by the feature system. Nothing to do here.
684 continue;
685 }
686
697 if (!completely_unprivileged_apis_.count(*i) && 687 if (!completely_unprivileged_apis_.count(*i) &&
698 !partially_unprivileged_apis_.count(*i)) { 688 !partially_unprivileged_apis_.count(*i)) {
699 privileged_apis.insert(*i); 689 privileged_apis.insert(*i);
700 } 690 }
701 } 691 }
702 for (std::set<std::string>::iterator i = privileged_apis.begin(); 692 for (std::set<std::string>::iterator i = privileged_apis.begin();
703 i != privileged_apis.end(); ++i) { 693 i != privileged_apis.end(); ++i) {
704 apis->erase(*i); 694 apis->erase(*i);
705 } 695 }
706 } 696 }
(...skipping 12 matching lines...) Expand all
719 } 709 }
720 } 710 }
721 711
722 void ExtensionAPI::LoadAllSchemas() { 712 void ExtensionAPI::LoadAllSchemas() {
723 while (unloaded_schemas_.size()) { 713 while (unloaded_schemas_.size()) {
724 LoadSchema(unloaded_schemas_.begin()->second); 714 LoadSchema(unloaded_schemas_.begin()->second);
725 } 715 }
726 } 716 }
727 717
728 } // namespace extensions 718 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698