17464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne/*
27464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne * Copyright (C) 2017 The Android Open Source Project
37464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne *
47464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne * Licensed under the Apache License, Version 2.0 (the "License");
57464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne * you may not use this file except in compliance with the License.
67464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne * You may obtain a copy of the License at
77464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne *
87464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne *      http://www.apache.org/licenses/LICENSE-2.0
97464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne *
107464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne * Unless required by applicable law or agreed to in writing, software
117464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne * distributed under the License is distributed on an "AS IS" BASIS,
127464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
137464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne * See the License for the specific language governing permissions and
147464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne * limitations under the License.
157464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne */
167464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne
177464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne#include "BootAction.h"
187464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne
197464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne#define LOG_TAG "BootAction"
207464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne
217464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne#include <android-base/strings.h>
227464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne#include <cpu-features.h>
237464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne#include <dlfcn.h>
247464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne#include <pio/peripheral_manager_client.h>
257464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne#include <utils/Log.h>
267464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne
277464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyneusing android::base::Split;
287464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyneusing android::base::Join;
297464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyneusing android::base::StartsWith;
307464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyneusing android::base::EndsWith;
317464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne
327464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coynenamespace android {
337464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne
347464ac9bd7fe89061e47617e4b6004b88c91d636Ed CoyneBootAction::~BootAction() {
357464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne    if (mLibHandle != nullptr) {
367464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne        dlclose(mLibHandle);
377464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne    }
387464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne}
397464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne
407464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coynebool BootAction::init(const std::string& libraryPath, const std::string& config) {
417464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne    APeripheralManagerClient* client = nullptr;
427464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne    ALOGD("Connecting to peripheralmanager");
437464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne    // Wait for peripheral manager to come up.
447464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne    while (client == nullptr) {
457464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne        client = APeripheralManagerClient_new();
467464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne        if (client == nullptr) {
477464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne          ALOGV("peripheralmanager is not up, sleeping before we check again.");
487464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne          usleep(250000);
497464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne        }
507464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne    }
517464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne    ALOGD("Peripheralmanager is up.");
527464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne    APeripheralManagerClient_delete(client);
537464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne
547464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne    std::string path_to_lib = libraryPath;
557464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne    if (!parseConfig(config, &path_to_lib)) {
567464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne        return false;
577464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne    }
587464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne
597464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne    ALOGI("Loading boot action %s", path_to_lib.c_str());
607464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne    mLibHandle = dlopen(path_to_lib.c_str(), RTLD_NOW);
617464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne    if (mLibHandle == nullptr) {
627464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne        ALOGE("Unable to load library at %s :: %s",
637464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne              path_to_lib.c_str(), dlerror());
647464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne        return false;
657464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne    }
667464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne
677464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne    void* loaded = nullptr;
687464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne    if (!loadSymbol("boot_action_init", &loaded) || loaded == nullptr) {
697464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne        return false;
707464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne    }
717464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne    mLibInit = reinterpret_cast<libInit>(loaded);
727464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne
737464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne    loaded = nullptr;
747464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne    if (!loadSymbol("boot_action_shutdown", &loaded) || loaded == nullptr) {
757464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne        return false;
767464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne    }
777464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne    mLibShutdown = reinterpret_cast<libShutdown>(loaded);
787464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne
797464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne    // StartPart is considered optional, if it isn't exported by the library
807464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne    // we will still call init and shutdown.
817464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne    loaded = nullptr;
827464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne    if (!loadSymbol("boot_action_start_part", &loaded) || loaded == nullptr) {
837464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne        ALOGI("No boot_action_start_part found, action will not be told when "
847464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne              "Animation parts change.");
857464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne    } else {
867464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne        mLibStartPart = reinterpret_cast<libStartPart>(loaded);
877464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne    }
887464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne
897464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne    ALOGD("Entering boot_action_init");
907464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne    bool result = mLibInit();
917464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne    ALOGD("Returned from boot_action_init");
927464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne    return result;
937464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne}
947464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne
957464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coynevoid BootAction::startPart(int partNumber, int playNumber) {
967464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne    if (mLibStartPart == nullptr) return;
977464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne
987464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne    ALOGD("Entering boot_action_start_part");
997464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne    mLibStartPart(partNumber, playNumber);
1007464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne    ALOGD("Returned from boot_action_start_part");
1017464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne}
1027464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne
1037464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coynevoid BootAction::shutdown() {
1047464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne    ALOGD("Entering boot_action_shutdown");
1057464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne    mLibShutdown();
1067464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne    ALOGD("Returned from boot_action_shutdown");
1077464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne}
1087464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne
1097464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coynebool BootAction::loadSymbol(const char* symbol, void** loaded) {
1107464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne    *loaded = dlsym(mLibHandle, symbol);
1117464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne    if (loaded == nullptr) {
1127464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne        ALOGE("Unable to load symbol : %s :: %s", symbol, dlerror());
1137464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne        return false;
1147464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne    }
1157464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne    return true;
1167464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne}
1177464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne
1187464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne
1197464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coynebool BootAction::parseConfig(const std::string& config, std::string* path) {
1207464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne    auto lines = Split(config, "\n");
1217464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne
1227464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne    if (lines.size() < 1) {
1237464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne        ALOGE("Config format invalid, expected one line, found %d",
1247464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne              lines.size());
1257464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne        return false;
1267464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne    }
1277464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne
1287464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne    size_t lineNumber = 0;
1297464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne    auto& line1 = lines.at(lineNumber);
1307464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne    while (StartsWith(line1, "#")) {
1317464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne      if (lines.size() < ++lineNumber) {
1327464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne        ALOGE("Config file contains no non-comment lines.");
1337464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne        return false;
1347464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne      }
1357464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne      line1 = lines.at(lineNumber);
1367464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne    }
1377464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne
1387464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne    const std::string libraryNameToken("LIBRARY_NAME=");
1397464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne    if (!StartsWith(line1, libraryNameToken.c_str())) {
1407464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne        ALOGE("Invalid config format, expected second line to start  with %s "
1417464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne              "Instead found: %s", libraryNameToken.c_str(), line1.c_str());
1427464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne        return false;
1437464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne    }
1447464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne
1457464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne    std::string libraryName = line1.substr(libraryNameToken.length());
1467464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne
1477464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne    *path += "/";
1487464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne    *path += architectureDirectory();
1497464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne    *path += "/";
1507464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne    *path += libraryName;
1517464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne
1527464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne    return true;
1537464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne}
1547464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne
1557464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyneconst char* BootAction::architectureDirectory() {
1567464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne  switch(android_getCpuFamily()) {
1577464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne      case ANDROID_CPU_FAMILY_ARM:
1587464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne          return "arm";
1597464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne      case ANDROID_CPU_FAMILY_X86:
1607464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne          return "x86";
1617464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne      case ANDROID_CPU_FAMILY_MIPS:
1627464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne          return "mips";
1637464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne      case ANDROID_CPU_FAMILY_ARM64:
1647464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne          return "arm64";
1657464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne      case ANDROID_CPU_FAMILY_X86_64:
1667464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne          return "x86_64";
1677464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne      case ANDROID_CPU_FAMILY_MIPS64:
1687464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne          return "mips64";
1697464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne      default:
1707464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne          ALOGE("Unsupported cpu family: %d", android_getCpuFamily());
1717464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne          return "";
1727464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne  }
1737464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne}
1747464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne
1757464ac9bd7fe89061e47617e4b6004b88c91d636Ed Coyne}  // namespace android
176