blob: 4e8abc79fdcdcd1c20029211de1d9540900458d0 [file] [log] [blame]
// Copyright 2019 The Cobalt Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <vector>
#include "starboard/common/log.h"
#include "starboard/configuration.h"
#include "starboard/configuration_constants.h"
#include "starboard/elf_loader/elf_loader.h"
#include "starboard/event.h"
#include "starboard/loader_app/installation_manager.h"
#include "starboard/loader_app/system_get_extension_shim.h"
#include "starboard/mutex.h"
#include "starboard/string.h"
#include "starboard/thread_types.h"
// TODO: Try to merge with the implementation in starboard/elf_loader/sandbox.cc
namespace {
// The max number of installations slots.
const int kMaxNumInstallations = 2;
// Relative path for the Cobalt so file.
const char kCobaltLibraryPath[] = "lib";
// Filename for the Cobalt binary.
const char kCobaltLibraryName[] = "libcobalt.so";
// Relative path for the content directory of
// the Cobalt installation.
const char kCobaltContentPath[] = "content";
// Portable ELF loader.
starboard::elf_loader::ElfLoader g_elf_loader;
// Pointer to the |SbEventHandle| function in the
// Cobalt binary.
void (*g_sb_event_func)(const SbEvent*) = NULL;
void LoadLibraryAndInitialize() {
// Initialize the Installation Manager.
SB_CHECK(ImInitialize(kMaxNumInstallations) == IM_SUCCESS)
<< "Abort. Failed to initialize Installation Manager";
// Roll forward if needed.
if (ImRollForwardIfNeeded() == IM_ERROR) {
SB_LOG(WARNING) << "Failed to roll forward";
}
// Loop by priority.
int current_installation = ImGetCurrentInstallationIndex();
while (current_installation != IM_ERROR) {
// if not successful and num_tries_left > 0 decrement and try to
// load the library.
if (ImGetInstallationStatus(current_installation) !=
IM_INSTALLATION_STATUS_SUCCESS) {
int num_tries_left = ImGetInstallationNumTriesLeft(current_installation);
if (num_tries_left == IM_ERROR || num_tries_left <= 0 ||
ImDecrementInstallationNumTries(current_installation) == IM_ERROR) {
// If no more tries are left or if we have hard failure,
// discard the image and auto rollback, but only if
// the current image is not the system image.
if (current_installation != 0) {
current_installation = ImRevertToSuccessfulInstallation();
}
}
}
SB_LOG(INFO) << "Try to load the Cobalt binary";
SB_LOG(INFO) << "current_installation=" << current_installation;
// Try to load the image. Failures here discard the image.
std::vector<char> installation_path(kSbFileMaxPath);
if (ImGetInstallationPath(current_installation, installation_path.data(),
kSbFileMaxPath) == IM_ERROR) {
SB_LOG(ERROR) << "Failed to find library file";
// Hard failure. Discard the image and auto rollback, but only if
// the current image is not the system image.
if (current_installation != 0) {
current_installation = ImRevertToSuccessfulInstallation();
continue;
} else {
// The system image at index 0 failed.
break;
}
}
SB_DLOG(INFO) << "installation_path=" << installation_path.data();
// installation_n/lib/libcobalt.so
std::vector<char> lib_path(kSbFileMaxPath);
SbStringFormatF(lib_path.data(), kSbFileMaxPath, "%s%s%s%s%s",
installation_path.data(), kSbFileSepString,
kCobaltLibraryPath, kSbFileSepString, kCobaltLibraryName);
SB_LOG(INFO) << "lib_path=" << lib_path.data();
// installation_n/content
std::vector<char> content_path(kSbFileMaxPath);
SbStringFormatF(content_path.data(), kSbFileMaxPath, "%s%s%s",
installation_path.data(), kSbFileSepString,
kCobaltContentPath);
SB_LOG(INFO) << "content_path=" << content_path.data();
if (!g_elf_loader.Load(lib_path.data(), content_path.data(), false,
&starboard::loader_app::SbSystemGetExtensionShim)) {
SB_LOG(WARNING) << "Failed to load Cobalt!";
// Hard failure. Discard the image and auto rollback, but only if
// the current image is not the system image.
if (current_installation != 0) {
current_installation = ImRevertToSuccessfulInstallation();
continue;
} else {
// The system image at index 0 failed.
break;
}
}
SB_DLOG(INFO) << "Successfully loaded Cobalt!\n";
void* p = g_elf_loader.LookupSymbol("SbEventHandle");
if (p != NULL) {
SB_DLOG(INFO) << "Symbol Lookup succeeded address: " << p;
g_sb_event_func = (void (*)(const SbEvent*))p;
break;
} else {
SB_LOG(ERROR) << "Symbol Lookup failed\n";
// Hard failure. Discard the image and auto rollback, but only if
// the current image is not the system image.
if (current_installation != 0) {
current_installation = ImRevertToSuccessfulInstallation();
continue;
} else {
// The system image at index 0 failed.
break;
}
}
}
}
} // namespace
void SbEventHandle(const SbEvent* event) {
static SbMutex mutex = SB_MUTEX_INITIALIZER;
SB_CHECK(SbMutexAcquire(&mutex) == kSbMutexAcquired);
if (!g_sb_event_func) {
LoadLibraryAndInitialize();
SB_CHECK(g_sb_event_func);
}
g_sb_event_func(event);
SB_CHECK(SbMutexRelease(&mutex) == true);
}