| Index: chrome/common/extensions/api/extension_api.cc
 | 
| diff --git a/chrome/common/extensions/api/extension_api.cc b/chrome/common/extensions/api/extension_api.cc
 | 
| index c2a9cce97931c24a04b16ad3b7f1e8a911e57e13..d2c2b78d50a18a6c29fe2f72e38bfba67a69b4be 100644
 | 
| --- a/chrome/common/extensions/api/extension_api.cc
 | 
| +++ b/chrome/common/extensions/api/extension_api.cc
 | 
| @@ -234,11 +234,6 @@ void ExtensionAPI::SplitDependencyName(const std::string& full_name,
 | 
|    *feature_name = full_name.substr(colon_index + 1);
 | 
|  }
 | 
|  
 | 
| -bool ExtensionAPI::UsesFeatureSystem(const std::string& full_name) {
 | 
| -  std::string api_name = GetAPINameFromFullName(full_name, NULL);
 | 
| -  return features_.find(api_name) != features_.end();
 | 
| -}
 | 
| -
 | 
|  void ExtensionAPI::LoadSchema(const std::string& name,
 | 
|                                const base::StringPiece& schema) {
 | 
|    scoped_ptr<ListValue> schema_list(LoadSchemaList(name, schema));
 | 
| @@ -332,10 +327,6 @@ void ExtensionAPI::LoadSchema(const std::string& name,
 | 
|  }
 | 
|  
 | 
|  ExtensionAPI::ExtensionAPI() {
 | 
| -  RegisterDependencyProvider("api", this);
 | 
| -
 | 
| -  // TODO(aa): Can remove this when all JSON files are converted.
 | 
| -  RegisterDependencyProvider("", this);
 | 
|  }
 | 
|  
 | 
|  ExtensionAPI::~ExtensionAPI() {
 | 
| @@ -343,6 +334,8 @@ ExtensionAPI::~ExtensionAPI() {
 | 
|  
 | 
|  void ExtensionAPI::InitDefaultConfiguration() {
 | 
|    RegisterDependencyProvider(
 | 
| +      "api", BaseFeatureProvider::GetApiFeatures());
 | 
| +  RegisterDependencyProvider(
 | 
|        "manifest", BaseFeatureProvider::GetManifestFeatures());
 | 
|    RegisterDependencyProvider(
 | 
|        "permission", BaseFeatureProvider::GetPermissionFeatures());
 | 
| @@ -422,27 +415,34 @@ Feature::Availability ExtensionAPI::IsAvailable(const std::string& full_name,
 | 
|                                                  const Extension* extension,
 | 
|                                                  Feature::Context context,
 | 
|                                                  const GURL& url) {
 | 
| -  std::set<std::string> dependency_names;
 | 
| -  dependency_names.insert(full_name);
 | 
| -  ResolveDependencies(&dependency_names);
 | 
| +  std::string feature_type;
 | 
| +  std::string feature_name;
 | 
| +  SplitDependencyName(full_name, &feature_type, &feature_name);
 | 
| +
 | 
| +  std::string child_name;
 | 
| +  std::string api_name = GetAPINameFromFullName(feature_name, &child_name);
 | 
| +
 | 
| +  Feature* feature = GetFeatureDependency(full_name);
 | 
|  
 | 
|    // Check APIs not using the feature system first.
 | 
| -  if (!UsesFeatureSystem(full_name)) {
 | 
| -    return IsNonFeatureAPIAvailable(full_name, context, extension, url) ?
 | 
| +  if (!feature) {
 | 
| +    return IsNonFeatureAPIAvailable(api_name, context, extension, url) ?
 | 
|          Feature::CreateAvailability(Feature::IS_AVAILABLE, "") :
 | 
|          Feature::CreateAvailability(Feature::INVALID_CONTEXT,
 | 
|                                      kUnavailableMessage);
 | 
|    }
 | 
|  
 | 
| -  for (std::set<std::string>::iterator iter = dependency_names.begin();
 | 
| -       iter != dependency_names.end(); ++iter) {
 | 
| -    Feature* feature = GetFeatureDependency(*iter);
 | 
| -    CHECK(feature) << *iter;
 | 
| -
 | 
| -    Feature::Availability availability =
 | 
| -        feature->IsAvailableToContext(extension, context, url);
 | 
| -    if (!availability.is_available())
 | 
| -      return availability;
 | 
| +  Feature::Availability availability =
 | 
| +      feature->IsAvailableToContext(extension, context, url);
 | 
| +  if (!availability.is_available())
 | 
| +    return availability;
 | 
| +
 | 
| +  for (std::set<std::string>::iterator iter = feature->dependencies().begin();
 | 
| +       iter != feature->dependencies().end(); ++iter) {
 | 
| +    Feature::Availability dependency_availability =
 | 
| +        IsAvailable(*iter, extension, context, url);
 | 
| +    if (!dependency_availability.is_available())
 | 
| +      return dependency_availability;
 | 
|    }
 | 
|  
 | 
|    return Feature::CreateAvailability(Feature::IS_AVAILABLE, "");
 | 
| @@ -451,33 +451,21 @@ Feature::Availability ExtensionAPI::IsAvailable(const std::string& full_name,
 | 
|  bool ExtensionAPI::IsPrivileged(const std::string& full_name) {
 | 
|    std::string child_name;
 | 
|    std::string api_name = GetAPINameFromFullName(full_name, &child_name);
 | 
| +  Feature* feature = GetFeatureDependency(full_name);
 | 
|  
 | 
|    // First try to use the feature system.
 | 
| -  Feature* feature(GetFeature(full_name));
 | 
|    if (feature) {
 | 
| -    // An API is 'privileged' if it or any of its dependencies can only be run
 | 
| -    // in a blessed context.
 | 
| -    std::set<std::string> resolved_dependencies;
 | 
| -    resolved_dependencies.insert(full_name);
 | 
| -    ResolveDependencies(&resolved_dependencies);
 | 
| -    for (std::set<std::string>::iterator iter = resolved_dependencies.begin();
 | 
| -         iter != resolved_dependencies.end(); ++iter) {
 | 
| -      Feature* dependency = GetFeatureDependency(*iter);
 | 
| -      for (std::set<Feature::Context>::iterator context =
 | 
| -               dependency->GetContexts()->begin();
 | 
| -           context != dependency->GetContexts()->end(); ++context) {
 | 
| -        if (*context != Feature::BLESSED_EXTENSION_CONTEXT)
 | 
| -          return false;
 | 
| -      }
 | 
| -    }
 | 
| -    return true;
 | 
| +    // An API is 'privileged' if it can only be run in a blessed context.
 | 
| +    return feature->GetContexts()->size() ==
 | 
| +        feature->GetContexts()->count(Feature::BLESSED_EXTENSION_CONTEXT);
 | 
|    }
 | 
|  
 | 
| +  // Get the schema now to populate |completely_unprivileged_apis_|.
 | 
| +  const DictionaryValue* schema = GetSchema(api_name);
 | 
|    // If this API hasn't been converted yet, fall back to the old system.
 | 
|    if (completely_unprivileged_apis_.count(api_name))
 | 
|      return false;
 | 
|  
 | 
| -  const DictionaryValue* schema = GetSchema(api_name);
 | 
|    if (partially_unprivileged_apis_.count(api_name))
 | 
|      return IsChildNamePrivileged(schema, child_name);
 | 
|  
 | 
| @@ -549,6 +537,8 @@ bool ExtensionAPI::IsNonFeatureAPIAvailable(const std::string& name,
 | 
|                                              Feature::Context context,
 | 
|                                              const Extension* extension,
 | 
|                                              const GURL& url) {
 | 
| +  // Make sure schema is loaded.
 | 
| +  GetSchema(name);
 | 
|    switch (context) {
 | 
|      case Feature::UNSPECIFIED_CONTEXT:
 | 
|        break;
 | 
| @@ -597,36 +587,6 @@ std::set<std::string> ExtensionAPI::GetAllAPINames() {
 | 
|    return result;
 | 
|  }
 | 
|  
 | 
| -Feature* ExtensionAPI::GetFeature(const std::string& full_name) {
 | 
| -  // Ensure it's loaded.
 | 
| -  GetSchema(full_name);
 | 
| -
 | 
| -  std::string child_name;
 | 
| -  std::string api_namespace = GetAPINameFromFullName(full_name, &child_name);
 | 
| -
 | 
| -  APIFeatureMap::iterator feature_map = features_.find(api_namespace);
 | 
| -  if (feature_map == features_.end())
 | 
| -    return NULL;
 | 
| -
 | 
| -  Feature* result = NULL;
 | 
| -  FeatureMap::iterator child_feature = feature_map->second->find(child_name);
 | 
| -  if (child_feature != feature_map->second->end()) {
 | 
| -    result = child_feature->second.get();
 | 
| -  } else {
 | 
| -    FeatureMap::iterator parent_feature = feature_map->second->find("");
 | 
| -    CHECK(parent_feature != feature_map->second->end());
 | 
| -    result = parent_feature->second.get();
 | 
| -  }
 | 
| -
 | 
| -  if (result->GetContexts()->empty()) {
 | 
| -    LOG(ERROR) << "API feature '" << full_name
 | 
| -               << "' must specify at least one context.";
 | 
| -    return NULL;
 | 
| -  }
 | 
| -
 | 
| -  return result;
 | 
| -}
 | 
| -
 | 
|  Feature* ExtensionAPI::GetFeatureDependency(const std::string& full_name) {
 | 
|    std::string feature_type;
 | 
|    std::string feature_name;
 | 
| @@ -634,11 +594,16 @@ Feature* ExtensionAPI::GetFeatureDependency(const std::string& full_name) {
 | 
|  
 | 
|    FeatureProviderMap::iterator provider =
 | 
|        dependency_providers_.find(feature_type);
 | 
| -  CHECK(provider != dependency_providers_.end()) << full_name;
 | 
| +  if (provider == dependency_providers_.end())
 | 
| +    return NULL;
 | 
|  
 | 
|    Feature* feature = provider->second->GetFeature(feature_name);
 | 
| -  CHECK(feature) << full_name;
 | 
| -
 | 
| +  // Try getting the feature for the parent API, if this was a child.
 | 
| +  if (!feature) {
 | 
| +    std::string child_name;
 | 
| +    feature = provider->second->GetFeature(
 | 
| +        GetAPINameFromFullName(feature_name, &child_name));
 | 
| +  }
 | 
|    return feature;
 | 
|  }
 | 
|  
 | 
| @@ -678,47 +643,6 @@ bool ExtensionAPI::IsAPIAllowed(const std::string& name,
 | 
|        extension->optional_permission_set()->HasAnyAccessToAPI(name);
 | 
|  }
 | 
|  
 | 
| -void ExtensionAPI::ResolveDependencies(std::set<std::string>* out) {
 | 
| -  std::set<std::string> missing_dependencies;
 | 
| -  for (std::set<std::string>::iterator i = out->begin(); i != out->end(); ++i)
 | 
| -    GetMissingDependencies(*i, *out, &missing_dependencies);
 | 
| -
 | 
| -  while (missing_dependencies.size()) {
 | 
| -    std::string next = *missing_dependencies.begin();
 | 
| -    missing_dependencies.erase(next);
 | 
| -    out->insert(next);
 | 
| -    GetMissingDependencies(next, *out, &missing_dependencies);
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -void ExtensionAPI::GetMissingDependencies(
 | 
| -    const std::string& api_name,
 | 
| -    const std::set<std::string>& excluding,
 | 
| -    std::set<std::string>* out) {
 | 
| -  std::string feature_type;
 | 
| -  std::string feature_name;
 | 
| -  SplitDependencyName(api_name, &feature_type, &feature_name);
 | 
| -
 | 
| -  // Only API features can have dependencies for now.
 | 
| -  if (feature_type != "api")
 | 
| -    return;
 | 
| -
 | 
| -  const DictionaryValue* schema = GetSchema(feature_name);
 | 
| -  CHECK(schema) << "Schema for " << feature_name << " not found";
 | 
| -
 | 
| -  const ListValue* dependencies = NULL;
 | 
| -  if (!schema->GetList("dependencies", &dependencies))
 | 
| -    return;
 | 
| -
 | 
| -  for (size_t i = 0; i < dependencies->GetSize(); ++i) {
 | 
| -    std::string dependency_name;
 | 
| -    if (dependencies->GetString(i, &dependency_name) &&
 | 
| -        !excluding.count(dependency_name)) {
 | 
| -      out->insert(dependency_name);
 | 
| -    }
 | 
| -  }
 | 
| -}
 | 
| -
 | 
|  bool ExtensionAPI::IsPrivilegedAPI(const std::string& name) {
 | 
|    return completely_unprivileged_apis_.count(name) ||
 | 
|        partially_unprivileged_apis_.count(name);
 | 
| 
 |