| // 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); |
| } |