This source file includes following definitions.
- SanitizeForPath
- SetPnaclHash
- CheckVersionCompatiblity
- GetPlatformDir
- OverrideDirPnaclComponent
- GetLatestPnaclDirectory
- ReadJSONManifest
- ReadPnaclManifest
- ReadComponentManifest
- CheckPnaclComponentManifest
- cus_
- OnUpdateError
- GetPnaclBaseDirectory
- OnProfileChange
- GetInstalledFile
- GetCrxComponent
- FinishPnaclUpdateRegistration
- StartPnaclUpdateRegistration
- ReapOldChromeOSPnaclFiles
- GetProfileInformation
- RegisterPnaclComponent
- ReRegisterPnacl
- NeedsOnDemandUpdate
#include "chrome/browser/component_updater/pnacl/pnacl_component_installer.h"
#include "base/atomicops.h"
#include "base/base_paths.h"
#include "base/bind.h"
#include "base/callback.h"
#include "base/command_line.h"
#include "base/compiler_specific.h"
#include "base/file_util.h"
#include "base/files/file_enumerator.h"
#include "base/files/file_path.h"
#include "base/json/json_file_value_serializer.h"
#include "base/logging.h"
#include "base/path_service.h"
#include "base/strings/string_util.h"
#include "base/values.h"
#include "base/version.h"
#include "base/win/windows_version.h"
#include "build/build_config.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/component_updater/component_updater_service.h"
#include "chrome/browser/omaha_query_params/omaha_query_params.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/common/chrome_paths.h"
#include "components/nacl/common/nacl_switches.h"
#include "content/public/browser/browser_thread.h"
using chrome::OmahaQueryParams;
using content::BrowserThread;
namespace component_updater {
namespace {
const char kPnaclManifestName[] = "PNaCl Translator";
std::string SanitizeForPath(const std::string& input) {
std::string result;
base::ReplaceChars(input, "-", "_", &result);
return result;
}
void SetPnaclHash(CrxComponent* component) {
static const uint8 sha256_hash[32] =
{
0x7d, 0x8c, 0xfd, 0x47, 0xee, 0x37, 0x44, 0x36, 0x73, 0x44,
0x89, 0xab, 0xa4, 0x00, 0x21, 0x32, 0x4a, 0x06, 0x06, 0xf1, 0x51,
0x3c, 0x51, 0xba, 0x31, 0x2f, 0xbc, 0xb3, 0x99, 0x07, 0xdc, 0x9c};
component->pk_hash.assign(sha256_hash,
&sha256_hash[arraysize(sha256_hash)]);
}
const char kNullVersion[] = "0.0.0.0";
const char kMinPnaclVersion[] = "0.1.0.12773";
volatile base::subtle::Atomic32 needs_on_demand_update = 0;
void CheckVersionCompatiblity(const base::Version& current_version) {
base::subtle::NoBarrier_Store(&needs_on_demand_update,
current_version.IsOlderThan(kMinPnaclVersion));
}
base::FilePath GetPlatformDir(const base::FilePath& base_path) {
std::string arch = SanitizeForPath(OmahaQueryParams::GetNaclArch());
return base_path.AppendASCII("_platform_specific").AppendASCII(arch);
}
void OverrideDirPnaclComponent(const base::FilePath& base_path) {
PathService::Override(chrome::DIR_PNACL_COMPONENT,
GetPlatformDir(base_path));
}
bool GetLatestPnaclDirectory(PnaclComponentInstaller* pci,
base::FilePath* latest_dir,
Version* latest_version,
std::vector<base::FilePath>* older_dirs) {
base::FilePath base_dir = pci->GetPnaclBaseDirectory();
bool found = false;
base::FileEnumerator
file_enumerator(base_dir, false, base::FileEnumerator::DIRECTORIES);
for (base::FilePath path = file_enumerator.Next(); !path.value().empty();
path = file_enumerator.Next()) {
Version version(path.BaseName().MaybeAsASCII());
if (!version.IsValid())
continue;
if (found) {
if (version.CompareTo(*latest_version) > 0) {
older_dirs->push_back(*latest_dir);
*latest_dir = path;
*latest_version = version;
} else {
older_dirs->push_back(path);
}
} else {
*latest_version = version;
*latest_dir = path;
found = true;
}
}
return found;
}
base::DictionaryValue* ReadJSONManifest(
const base::FilePath& manifest_path) {
JSONFileValueSerializer serializer(manifest_path);
std::string error;
scoped_ptr<base::Value> root(serializer.Deserialize(NULL, &error));
if (!root.get())
return NULL;
if (!root->IsType(base::Value::TYPE_DICTIONARY))
return NULL;
return static_cast<base::DictionaryValue*>(root.release());
}
base::DictionaryValue* ReadPnaclManifest(const base::FilePath& unpack_path) {
base::FilePath manifest_path = GetPlatformDir(unpack_path).AppendASCII(
"pnacl_public_pnacl_json");
if (!base::PathExists(manifest_path))
return NULL;
return ReadJSONManifest(manifest_path);
}
base::DictionaryValue* ReadComponentManifest(
const base::FilePath& unpack_path) {
base::FilePath manifest_path = unpack_path.Append(
FILE_PATH_LITERAL("manifest.json"));
if (!base::PathExists(manifest_path))
return NULL;
return ReadJSONManifest(manifest_path);
}
bool CheckPnaclComponentManifest(const base::DictionaryValue& manifest,
const base::DictionaryValue& pnacl_manifest,
Version* version_out) {
std::string name;
if (!manifest.GetStringASCII("name", &name)) {
LOG(WARNING) << "'name' field is missing from manifest!";
return false;
}
if (name.find(kPnaclManifestName) == std::string::npos) {
LOG(WARNING) << "'name' field in manifest is invalid ("
<< name << ") -- missing ("
<< kPnaclManifestName << ")";
return false;
}
std::string proposed_version;
if (!manifest.GetStringASCII("version", &proposed_version)) {
LOG(WARNING) << "'version' field is missing from manifest!";
return false;
}
Version version(proposed_version.c_str());
if (!version.IsValid()) {
LOG(WARNING) << "'version' field in manifest is invalid "
<< version.GetString();
return false;
}
std::string arch;
if (!pnacl_manifest.GetStringASCII("pnacl-arch", &arch)) {
LOG(WARNING) << "'pnacl-arch' field is missing from pnacl-manifest!";
return false;
}
if (arch.compare(OmahaQueryParams::GetNaclArch()) != 0) {
LOG(WARNING) << "'pnacl-arch' field in manifest is invalid (" << arch
<< " vs " << OmahaQueryParams::GetNaclArch() << ")";
return false;
}
*version_out = version;
return true;
}
}
PnaclComponentInstaller::PnaclComponentInstaller()
: per_user_(false),
updates_disabled_(false),
cus_(NULL) {
#if defined(OS_CHROMEOS)
per_user_ = true;
#endif
}
PnaclComponentInstaller::~PnaclComponentInstaller() {
}
void PnaclComponentInstaller::OnUpdateError(int error) {
NOTREACHED() << "Pnacl update error: " << error;
}
base::FilePath PnaclComponentInstaller::GetPnaclBaseDirectory() {
if (per_user_) {
DCHECK(!current_profile_path_.empty());
base::FilePath path = current_profile_path_.Append(
FILE_PATH_LITERAL("pnacl"));
return path;
} else {
base::FilePath result;
CHECK(PathService::Get(chrome::DIR_PNACL_BASE, &result));
return result;
}
}
void PnaclComponentInstaller::OnProfileChange() {
ProfileManager* pm = g_browser_process->profile_manager();
current_profile_path_ = pm->user_data_dir().Append(
pm->GetInitialProfileDir());
}
bool PnaclComponentInstaller::Install(const base::DictionaryValue& manifest,
const base::FilePath& unpack_path) {
scoped_ptr<base::DictionaryValue> pnacl_manifest(
ReadPnaclManifest(unpack_path));
if (pnacl_manifest == NULL) {
LOG(WARNING) << "Failed to read pnacl manifest.";
return false;
}
Version version;
if (!CheckPnaclComponentManifest(manifest, *pnacl_manifest, &version)) {
LOG(WARNING) << "CheckPnaclComponentManifest failed, not installing.";
return false;
}
if (current_version().CompareTo(version) > 0) {
return false;
}
base::FilePath path = GetPnaclBaseDirectory().AppendASCII(
version.GetString());
if (base::PathExists(path)) {
if (!base::DeleteFile(path, true))
return false;
}
if (!base::Move(unpack_path, path)) {
LOG(WARNING) << "Move failed, not installing.";
return false;
}
set_current_version(version);
CheckVersionCompatiblity(version);
OverrideDirPnaclComponent(path);
return true;
}
bool PnaclComponentInstaller::GetInstalledFile(
const std::string& file, base::FilePath* installed_file) {
if (current_version().Equals(Version(kNullVersion)))
return false;
*installed_file = GetPnaclBaseDirectory().AppendASCII(
current_version().GetString()).AppendASCII(file);
return true;
}
CrxComponent PnaclComponentInstaller::GetCrxComponent() {
CrxComponent pnacl_component;
pnacl_component.version = current_version();
pnacl_component.name = "pnacl";
pnacl_component.installer = this;
pnacl_component.fingerprint = current_fingerprint();
SetPnaclHash(&pnacl_component);
return pnacl_component;
}
namespace {
void FinishPnaclUpdateRegistration(const Version& current_version,
const std::string& current_fingerprint,
PnaclComponentInstaller* pci) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
pci->set_current_version(current_version);
CheckVersionCompatiblity(current_version);
pci->set_current_fingerprint(current_fingerprint);
CrxComponent pnacl_component = pci->GetCrxComponent();
ComponentUpdateService::Status status =
pci->cus()->RegisterComponent(pnacl_component);
if (status != ComponentUpdateService::kOk
&& status != ComponentUpdateService::kReplaced) {
NOTREACHED() << "Pnacl component registration failed.";
}
}
void StartPnaclUpdateRegistration(PnaclComponentInstaller* pci) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
base::FilePath path = pci->GetPnaclBaseDirectory();
if (!base::PathExists(path)) {
if (!base::CreateDirectory(path)) {
NOTREACHED() << "Could not create base Pnacl directory.";
return;
}
}
Version current_version(kNullVersion);
std::string current_fingerprint;
std::vector<base::FilePath> older_dirs;
if (GetLatestPnaclDirectory(pci, &path, ¤t_version, &older_dirs)) {
scoped_ptr<base::DictionaryValue> manifest(
ReadComponentManifest(path));
scoped_ptr<base::DictionaryValue> pnacl_manifest(
ReadPnaclManifest(path));
Version manifest_version;
if (manifest == NULL || pnacl_manifest == NULL
|| !CheckPnaclComponentManifest(*manifest,
*pnacl_manifest,
&manifest_version)
|| !current_version.Equals(manifest_version)) {
current_version = Version(kNullVersion);
} else {
OverrideDirPnaclComponent(path);
base::ReadFileToString(path.AppendASCII("manifest.fingerprint"),
¤t_fingerprint);
}
}
if (pci->updates_disabled())
return;
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::Bind(&FinishPnaclUpdateRegistration,
current_version,
current_fingerprint,
pci));
for (std::vector<base::FilePath>::iterator iter = older_dirs.begin();
iter != older_dirs.end(); ++iter) {
base::DeleteFile(*iter, true);
}
}
void ReapOldChromeOSPnaclFiles(PnaclComponentInstaller* pci) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
base::FilePath path = pci->GetPnaclBaseDirectory();
if (!base::PathExists(path))
return;
if (pci->per_user()
&& path.BaseName().value().compare(FILE_PATH_LITERAL("pnacl")) == 0)
base::DeleteFile(path, true);
}
void GetProfileInformation(PnaclComponentInstaller* pci) {
if (!g_browser_process->profile_manager()->IsLoggedIn()) {
return;
}
pci->OnProfileChange();
BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
base::Bind(&ReapOldChromeOSPnaclFiles, pci));
}
}
void PnaclComponentInstaller::RegisterPnaclComponent(
ComponentUpdateService* cus,
const CommandLine& command_line) {
updates_disabled_ = command_line.HasSwitch(switches::kDisablePnaclInstall);
cus_ = cus;
if (per_user_ && !profile_observer_) {
profile_observer_.reset(new PnaclProfileObserver(this));
}
if (per_user_) {
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
base::Bind(&GetProfileInformation, this));
} else {
BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
base::Bind(&StartPnaclUpdateRegistration, this));
}
}
void PnaclComponentInstaller::ReRegisterPnacl() {
DCHECK(per_user_);
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::Bind(&GetProfileInformation, this));
}
}
namespace pnacl {
bool NeedsOnDemandUpdate() {
return base::subtle::NoBarrier_Load(
&component_updater::needs_on_demand_update) != 0;
}
}