Home | History | Annotate | Download | only in iot
      1 /*
      2  * Copyright (C) 2017 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include "BootAction.h"
     18 
     19 #define LOG_TAG "BootAction"
     20 
     21 #include <android-base/strings.h>
     22 #include <cpu-features.h>
     23 #include <dlfcn.h>
     24 #include <pio/peripheral_manager_client.h>
     25 #include <utils/Log.h>
     26 
     27 using android::base::Split;
     28 using android::base::Join;
     29 using android::base::StartsWith;
     30 using android::base::EndsWith;
     31 
     32 namespace android {
     33 
     34 BootAction::~BootAction() {
     35     if (mLibHandle != nullptr) {
     36         dlclose(mLibHandle);
     37     }
     38 }
     39 
     40 bool BootAction::init(const std::string& libraryPath, const std::string& config) {
     41     APeripheralManagerClient* client = nullptr;
     42     ALOGD("Connecting to peripheralmanager");
     43     // Wait for peripheral manager to come up.
     44     while (client == nullptr) {
     45         client = APeripheralManagerClient_new();
     46         if (client == nullptr) {
     47           ALOGV("peripheralmanager is not up, sleeping before we check again.");
     48           usleep(250000);
     49         }
     50     }
     51     ALOGD("Peripheralmanager is up.");
     52     APeripheralManagerClient_delete(client);
     53 
     54     std::string path_to_lib = libraryPath;
     55     if (!parseConfig(config, &path_to_lib)) {
     56         return false;
     57     }
     58 
     59     ALOGI("Loading boot action %s", path_to_lib.c_str());
     60     mLibHandle = dlopen(path_to_lib.c_str(), RTLD_NOW);
     61     if (mLibHandle == nullptr) {
     62         ALOGE("Unable to load library at %s :: %s",
     63               path_to_lib.c_str(), dlerror());
     64         return false;
     65     }
     66 
     67     void* loaded = nullptr;
     68     if (!loadSymbol("boot_action_init", &loaded) || loaded == nullptr) {
     69         return false;
     70     }
     71     mLibInit = reinterpret_cast<libInit>(loaded);
     72 
     73     loaded = nullptr;
     74     if (!loadSymbol("boot_action_shutdown", &loaded) || loaded == nullptr) {
     75         return false;
     76     }
     77     mLibShutdown = reinterpret_cast<libShutdown>(loaded);
     78 
     79     // StartPart is considered optional, if it isn't exported by the library
     80     // we will still call init and shutdown.
     81     loaded = nullptr;
     82     if (!loadSymbol("boot_action_start_part", &loaded) || loaded == nullptr) {
     83         ALOGI("No boot_action_start_part found, action will not be told when "
     84               "Animation parts change.");
     85     } else {
     86         mLibStartPart = reinterpret_cast<libStartPart>(loaded);
     87     }
     88 
     89     ALOGD("Entering boot_action_init");
     90     bool result = mLibInit();
     91     ALOGD("Returned from boot_action_init");
     92     return result;
     93 }
     94 
     95 void BootAction::startPart(int partNumber, int playNumber) {
     96     if (mLibStartPart == nullptr) return;
     97 
     98     ALOGD("Entering boot_action_start_part");
     99     mLibStartPart(partNumber, playNumber);
    100     ALOGD("Returned from boot_action_start_part");
    101 }
    102 
    103 void BootAction::shutdown() {
    104     ALOGD("Entering boot_action_shutdown");
    105     mLibShutdown();
    106     ALOGD("Returned from boot_action_shutdown");
    107 }
    108 
    109 bool BootAction::loadSymbol(const char* symbol, void** loaded) {
    110     *loaded = dlsym(mLibHandle, symbol);
    111     if (loaded == nullptr) {
    112         ALOGE("Unable to load symbol : %s :: %s", symbol, dlerror());
    113         return false;
    114     }
    115     return true;
    116 }
    117 
    118 
    119 bool BootAction::parseConfig(const std::string& config, std::string* path) {
    120     auto lines = Split(config, "\n");
    121 
    122     if (lines.size() < 1) {
    123         ALOGE("Config format invalid, expected one line, found %d",
    124               lines.size());
    125         return false;
    126     }
    127 
    128     size_t lineNumber = 0;
    129     auto& line1 = lines.at(lineNumber);
    130     while (StartsWith(line1, "#")) {
    131       if (lines.size() < ++lineNumber) {
    132         ALOGE("Config file contains no non-comment lines.");
    133         return false;
    134       }
    135       line1 = lines.at(lineNumber);
    136     }
    137 
    138     const std::string libraryNameToken("LIBRARY_NAME=");
    139     if (!StartsWith(line1, libraryNameToken.c_str())) {
    140         ALOGE("Invalid config format, expected second line to start  with %s "
    141               "Instead found: %s", libraryNameToken.c_str(), line1.c_str());
    142         return false;
    143     }
    144 
    145     std::string libraryName = line1.substr(libraryNameToken.length());
    146 
    147     *path += "/";
    148     *path += architectureDirectory();
    149     *path += "/";
    150     *path += libraryName;
    151 
    152     return true;
    153 }
    154 
    155 const char* BootAction::architectureDirectory() {
    156   switch(android_getCpuFamily()) {
    157       case ANDROID_CPU_FAMILY_ARM:
    158           return "arm";
    159       case ANDROID_CPU_FAMILY_X86:
    160           return "x86";
    161       case ANDROID_CPU_FAMILY_MIPS:
    162           return "mips";
    163       case ANDROID_CPU_FAMILY_ARM64:
    164           return "arm64";
    165       case ANDROID_CPU_FAMILY_X86_64:
    166           return "x86_64";
    167       case ANDROID_CPU_FAMILY_MIPS64:
    168           return "mips64";
    169       default:
    170           ALOGE("Unsupported cpu family: %d", android_getCpuFamily());
    171           return "";
    172   }
    173 }
    174 
    175 }  // namespace android
    176