Commit 5b56f9b2 authored by khmel@google.com's avatar khmel@google.com Committed by Commit Bot

arc: Support loading default apps from different sources.

This is to support per-board configuration for uni-builds.
Related CLs: crrev.com/c/1208892, crrev.com/i/673295

TEST=Manually on device, test data restructured to be covered by unit
     tests
BUG=b:113908266

Change-Id: I56b3268390ce31e28204e53d443d465a032a84f4
Reviewed-on: https://chromium-review.googlesource.com/1208195
Commit-Queue: Yury Khmel <khmel@google.com>
Reviewed-by: default avatarXiyuan Xia <xiyuan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#589395}
parent dfaa4293
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#include "chrome/browser/ui/app_list/arc/arc_default_app_list.h" #include "chrome/browser/ui/app_list/arc/arc_default_app_list.h"
#include "base/barrier_closure.h"
#include "base/files/file_enumerator.h" #include "base/files/file_enumerator.h"
#include "base/files/file_util.h"
#include "base/json/json_file_value_serializer.h" #include "base/json/json_file_value_serializer.h"
#include "base/path_service.h" #include "base/path_service.h"
#include "base/task/post_task.h" #include "base/task/post_task.h"
...@@ -34,87 +35,78 @@ constexpr char kHidden[] = "hidden"; ...@@ -34,87 +35,78 @@ constexpr char kHidden[] = "hidden";
const base::FilePath::CharType kArcDirectory[] = FILE_PATH_LITERAL("arc"); const base::FilePath::CharType kArcDirectory[] = FILE_PATH_LITERAL("arc");
const base::FilePath::CharType kArcTestDirectory[] = const base::FilePath::CharType kArcTestDirectory[] =
FILE_PATH_LITERAL("arc_default_apps"); FILE_PATH_LITERAL("arc_default_apps");
const base::FilePath::CharType kArcTestBoardDirectory[] =
FILE_PATH_LITERAL("arc_board_default_apps");
const base::FilePath::CharType kBoardDirectory[] =
FILE_PATH_LITERAL("/var/cache/arc_default_apps");
bool use_test_apps_directory = false; bool use_test_apps_directory = false;
std::unique_ptr<ArcDefaultAppList::AppInfoMap> std::unique_ptr<ArcDefaultAppList::AppInfoMap> ReadAppsFromFileThread(
ReadAppsFromFileThread() { const base::FilePath& base_path) {
base::FilePath root_dir;
// FileEnumerator does not work with a symbolic link dir. So map link
// to real folder in case |base_path| specifies a symbolic link.
if (!base::ReadSymbolicLink(base_path, &root_dir))
root_dir = base_path;
std::unique_ptr<ArcDefaultAppList::AppInfoMap> apps = std::unique_ptr<ArcDefaultAppList::AppInfoMap> apps =
std::make_unique<ArcDefaultAppList::AppInfoMap>(); std::make_unique<ArcDefaultAppList::AppInfoMap>();
base::FilePath base_path;
if (!use_test_apps_directory) {
if (!base::PathService::Get(chrome::DIR_STANDALONE_EXTERNAL_EXTENSIONS,
&base_path))
return apps;
base_path = base_path.Append(kArcDirectory);
} else {
if (!base::PathService::Get(chrome::DIR_TEST_DATA, &base_path))
return apps;
base_path = base_path.AppendASCII(kArcTestDirectory);
}
base::FilePath::StringType extension(".json"); base::FilePath::StringType extension(".json");
base::FileEnumerator json_files( base::FileEnumerator json_files(root_dir,
base_path, false, // Recursive.
false, // Recursive. base::FileEnumerator::FILES);
base::FileEnumerator::FILES);
for (base::FilePath file = json_files.Next(); !file.empty(); for (base::FilePath file = json_files.Next(); !file.empty();
file = json_files.Next()) { file = json_files.Next()) {
if (!file.MatchesExtension(extension)) {
if (file.MatchesExtension(extension)) {
JSONFileValueDeserializer deserializer(file);
std::string error_msg;
std::unique_ptr<base::Value> app_info =
deserializer.Deserialize(nullptr, &error_msg);
if (!app_info) {
VLOG(2) << "Unable to deserialize json data: " << error_msg
<< " in file " << file.value() << ".";
continue;
}
std::unique_ptr<base::DictionaryValue> app_info_dictionary =
base::DictionaryValue::From(std::move(app_info));
CHECK(app_info_dictionary);
std::string name;
std::string package_name;
std::string activity;
std::string app_path;
bool oem = false;
app_info_dictionary->GetString(kName, &name);
app_info_dictionary->GetString(kPackageName, &package_name);
app_info_dictionary->GetString(kActivity, &activity);
app_info_dictionary->GetString(kAppPath, &app_path);
app_info_dictionary->GetBoolean(kOem, &oem);
if (name.empty() ||
package_name.empty() ||
activity.empty() ||
app_path.empty()) {
VLOG(2) << "ARC app declaration is incomplete in file " << file.value()
<< ".";
continue;
}
const std::string app_id = ArcAppListPrefs::GetAppId(
package_name, activity);
std::unique_ptr<ArcDefaultAppList::AppInfo> app =
std::make_unique<ArcDefaultAppList::AppInfo>(name,
package_name,
activity,
oem,
base_path.Append(app_path));
apps.get()->insert(
std::pair<std::string,
std::unique_ptr<ArcDefaultAppList::AppInfo>>(
app_id, std::move(app)));
} else {
DVLOG(1) << "Not considering: " << file.LossyDisplayName() DVLOG(1) << "Not considering: " << file.LossyDisplayName()
<< " (does not have a .json extension)"; << " (does not have a .json extension)";
continue;
}
JSONFileValueDeserializer deserializer(file);
std::string error_msg;
std::unique_ptr<base::Value> app_info =
deserializer.Deserialize(nullptr, &error_msg);
if (!app_info) {
VLOG(2) << "Unable to deserialize json data: " << error_msg << " in file "
<< file.value() << ".";
continue;
} }
std::unique_ptr<base::DictionaryValue> app_info_dictionary =
base::DictionaryValue::From(std::move(app_info));
CHECK(app_info_dictionary);
std::string name;
std::string package_name;
std::string activity;
std::string app_path;
bool oem = false;
app_info_dictionary->GetString(kName, &name);
app_info_dictionary->GetString(kPackageName, &package_name);
app_info_dictionary->GetString(kActivity, &activity);
app_info_dictionary->GetString(kAppPath, &app_path);
app_info_dictionary->GetBoolean(kOem, &oem);
if (name.empty() || package_name.empty() || activity.empty() ||
app_path.empty()) {
VLOG(2) << "ARC app declaration is incomplete in file " << file.value()
<< ".";
continue;
}
const std::string app_id =
ArcAppListPrefs::GetAppId(package_name, activity);
std::unique_ptr<ArcDefaultAppList::AppInfo> app =
std::make_unique<ArcDefaultAppList::AppInfo>(
name, package_name, activity, oem, root_dir.Append(app_path));
apps.get()->insert(
std::pair<std::string, std::unique_ptr<ArcDefaultAppList::AppInfo>>(
app_id, std::move(app)));
} }
return apps; return apps;
...@@ -150,17 +142,48 @@ ArcDefaultAppList::ArcDefaultAppList(Profile* profile, ...@@ -150,17 +142,48 @@ ArcDefaultAppList::ArcDefaultAppList(Profile* profile,
weak_ptr_factory_(this) { weak_ptr_factory_(this) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
// Load default apps from two sources.
// /usr/share/google-chrome/extensions/arc - contains default apps for all
// boards that share the same image.
// /var/cache/arc_default_apps that is link to
// /usr/share/google-chrome/extensions/arc/BOARD_NAME - contains default
// apps for particular current board.
//
std::vector<base::FilePath> sources;
base::FilePath base_path;
if (!use_test_apps_directory) {
const bool valid_path = base::PathService::Get(
chrome::DIR_STANDALONE_EXTERNAL_EXTENSIONS, &base_path);
DCHECK(valid_path);
sources.push_back(base_path.Append(kArcDirectory));
sources.push_back(base::FilePath(kBoardDirectory));
} else {
const bool valid_path =
base::PathService::Get(chrome::DIR_TEST_DATA, &base_path);
DCHECK(valid_path);
sources.push_back(base_path.Append(kArcTestDirectory));
sources.push_back(base_path.Append(kArcTestBoardDirectory));
}
// Using base::Unretained(this) here is safe since we own barrier_closure_.
barrier_closure_ = base::BarrierClosure(
sources.size(),
base::BindOnce(&ArcDefaultAppList::OnAppsReady, base::Unretained(this)));
// Once ready OnAppsReady is called. // Once ready OnAppsReady is called.
base::PostTaskWithTraitsAndReplyWithResult( for (const auto& source : sources) {
FROM_HERE, {base::MayBlock(), base::TaskPriority::BEST_EFFORT}, base::PostTaskWithTraitsAndReplyWithResult(
base::Bind(&ReadAppsFromFileThread), FROM_HERE, {base::MayBlock(), base::TaskPriority::BEST_EFFORT},
base::Bind(&ArcDefaultAppList::OnAppsReady, base::BindOnce(&ReadAppsFromFileThread, source),
weak_ptr_factory_.GetWeakPtr())); base::BindOnce(&ArcDefaultAppList::OnAppsRead,
weak_ptr_factory_.GetWeakPtr()));
}
} }
ArcDefaultAppList::~ArcDefaultAppList() = default; ArcDefaultAppList::~ArcDefaultAppList() = default;
void ArcDefaultAppList::OnAppsReady(std::unique_ptr<AppInfoMap> apps) { void ArcDefaultAppList::OnAppsRead(std::unique_ptr<AppInfoMap> apps) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
const PrefService* const prefs = profile_->GetPrefs(); const PrefService* const prefs = profile_->GetPrefs();
...@@ -170,6 +193,11 @@ void ArcDefaultAppList::OnAppsReady(std::unique_ptr<AppInfoMap> apps) { ...@@ -170,6 +193,11 @@ void ArcDefaultAppList::OnAppsReady(std::unique_ptr<AppInfoMap> apps) {
app_map[entry.first] = std::move(entry.second); app_map[entry.first] = std::move(entry.second);
} }
barrier_closure_.Run();
}
void ArcDefaultAppList::OnAppsReady() {
const PrefService* const prefs = profile_->GetPrefs();
// Register Play Store as default app. Some services and ArcSupportHost may // Register Play Store as default app. Some services and ArcSupportHost may
// not be available in tests. // not be available in tests.
extensions::ExtensionService* service = extensions::ExtensionService* service =
......
...@@ -86,8 +86,10 @@ class ArcDefaultAppList { ...@@ -86,8 +86,10 @@ class ArcDefaultAppList {
} }
private: private:
// Called when default apps are ready. // Called when default apps are read from the provided source.
void OnAppsReady(std::unique_ptr<AppInfoMap> apps); void OnAppsRead(std::unique_ptr<AppInfoMap> apps);
// Called when default apps from all sources are read.
void OnAppsReady();
// Unowned pointer. // Unowned pointer.
Profile* profile_; Profile* profile_;
...@@ -100,6 +102,8 @@ class ArcDefaultAppList { ...@@ -100,6 +102,8 @@ class ArcDefaultAppList {
AppInfoMap visible_apps_; AppInfoMap visible_apps_;
// Keeps hidden apps. // Keeps hidden apps.
AppInfoMap hidden_apps_; AppInfoMap hidden_apps_;
// To wait until all sources with apps are loaded.
base::RepeatingClosure barrier_closure_;
base::WeakPtrFactory<ArcDefaultAppList> weak_ptr_factory_; base::WeakPtrFactory<ArcDefaultAppList> weak_ptr_factory_;
......
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