OSDN Git Service

Pass saved parameters to boot action
authorBraden Kell <bradenkell@google.com>
Tue, 26 Sep 2017 00:30:28 +0000 (17:30 -0700)
committerBraden Kell <bradenkell@google.com>
Tue, 26 Sep 2017 00:53:52 +0000 (17:53 -0700)
Bug: http://b/65462981
Test: Parameters in next_boot.json are passed to
      boot action; next_boot.json is moved to
      last_boot.json to allow reading by
      DeviceManagementService.

Change-Id: Ie290711ea48a3a221cfad2e9266215b76631ecbd

cmds/bootanimation/Android.mk
cmds/bootanimation/iot/BootAction.cpp
cmds/bootanimation/iot/BootAction.h
cmds/bootanimation/iot/bootanim_iot.rc [new file with mode: 0644]
cmds/bootanimation/iot/iotbootanimation_main.cpp

index 559e8de..dbd7749 100644 (file)
@@ -24,6 +24,11 @@ LOCAL_SRC_FILES:= \
     BootAnimationUtil.cpp \
 
 ifeq ($(PRODUCT_IOT),true)
+
+LOCAL_SHARED_LIBRARIES += libchrome
+
+LOCAL_C_INCLUDES += external/libchrome
+
 LOCAL_SRC_FILES += \
     iot/iotbootanimation_main.cpp \
     iot/BootAction.cpp
@@ -84,6 +89,12 @@ LOCAL_SHARED_LIBRARIES := \
     libtinyalsa \
     libbase
 
+ifeq ($(PRODUCT_IOT),true)
+
+LOCAL_INIT_RC := iot/bootanim_iot.rc
+
+endif # PRODUCT_IOT
+
 ifdef TARGET_32_BIT_SURFACEFLINGER
 LOCAL_32_BIT_ONLY := true
 endif
index 889eb2f..2bc7343 100644 (file)
 
 #define LOG_TAG "BootAction"
 
+#include <dlfcn.h>
+#include <fcntl.h>
+
+#include <map>
+
+#include <android-base/file.h>
 #include <android-base/strings.h>
+#include <base/json/json_parser.h>
+#include <base/json/json_value_converter.h>
 #include <cpu-features.h>
-#include <dlfcn.h>
 #include <pio/peripheral_manager_client.h>
 #include <utils/Log.h>
 
+using android::base::ReadFileToString;
+using android::base::RemoveFileIfExists;
 using android::base::Split;
 using android::base::Join;
 using android::base::StartsWith;
 using android::base::EndsWith;
+using base::JSONReader;
+using base::Value;
 
 namespace android {
 
+// Brightness and volume are stored as integer strings in next_boot.json.
+// They are divided by this constant to produce the actual float values in
+// range [0.0, 1.0]. This constant must match its counterpart in
+// DeviceManager.
+constexpr const float kFloatScaleFactor = 1000.0f;
+
+constexpr const char* kNextBootFile = "/data/misc/bootanimation/next_boot.json";
+constexpr const char* kLastBootFile = "/data/misc/bootanimation/last_boot.json";
+
+bool loadParameters(BootAction::SavedBootParameters* parameters)
+{
+    std::string contents;
+    if (!ReadFileToString(kLastBootFile, &contents)) {
+        if (errno != ENOENT)
+            ALOGE("Unable to read from %s: %s", kLastBootFile, strerror(errno));
+
+        return false;
+    }
+
+    std::unique_ptr<Value> json = JSONReader::Read(contents);
+    if (json.get() == nullptr) return false;
+
+    JSONValueConverter<BootAction::SavedBootParameters> converter;
+    if (!converter.Convert(*(json.get()), parameters)) return false;
+
+    return true;
+}
+
+void BootAction::SavedBootParameters::RegisterJSONConverter(
+        JSONValueConverter<SavedBootParameters> *converter) {
+    converter->RegisterIntField("brightness", &SavedBootParameters::brightness);
+    converter->RegisterIntField("volume", &SavedBootParameters::volume);
+    converter->RegisterRepeatedString("param_names",
+                                      &SavedBootParameters::param_names);
+    converter->RegisterRepeatedString("param_values",
+                                      &SavedBootParameters::param_values);
+}
+
 BootAction::~BootAction() {
     if (mLibHandle != nullptr) {
         dlclose(mLibHandle);
     }
 }
 
+void BootAction::swapBootConfigs() {
+    // rename() will fail if next_boot.json doesn't exist, so delete
+    // last_boot.json manually first.
+    std::string err;
+    if (!RemoveFileIfExists(kLastBootFile, &err))
+        ALOGE("Unable to delete last boot file: %s", err.c_str());
+
+    if (rename(kNextBootFile, kLastBootFile) && errno != ENOENT)
+        ALOGE("Unable to swap boot files: %s", strerror(errno));
+
+    int fd = open(kNextBootFile, O_CREAT, DEFFILEMODE);
+    if (fd == -1) {
+        ALOGE("Unable to create next boot file: %s", strerror(errno));
+    } else {
+        // Make next_boot.json writible to everyone so DeviceManagementService
+        // can save parameters there.
+        if (fchmod(fd, DEFFILEMODE))
+            ALOGE("Unable to set next boot file permissions: %s", strerror(errno));
+        close(fd);
+    }
+}
+
 bool BootAction::init(const std::string& libraryPath) {
     APeripheralManagerClient* client = nullptr;
     ALOGD("Connecting to peripheralmanager");
@@ -51,6 +122,28 @@ bool BootAction::init(const std::string& libraryPath) {
     ALOGD("Peripheralmanager is up.");
     APeripheralManagerClient_delete(client);
 
+    float brightness = -1.0f;
+    float volume = -1.0f;
+    std::vector<BootParameter> parameters;
+    SavedBootParameters saved_parameters;
+
+    if (loadParameters(&saved_parameters)) {
+        // TODO(b/65462981): Do something with brightness and volume?
+        brightness = saved_parameters.brightness / kFloatScaleFactor;
+        volume = saved_parameters.volume / kFloatScaleFactor;
+
+        if (saved_parameters.param_names.size() == saved_parameters.param_values.size()) {
+            for (size_t i = 0; i < saved_parameters.param_names.size(); i++) {
+                parameters.push_back({
+                        .key = saved_parameters.param_names[i]->c_str(),
+                        .value = saved_parameters.param_values[i]->c_str()
+                });
+            }
+        } else {
+            ALOGW("Parameter names and values size mismatch");
+        }
+    }
+
     ALOGI("Loading boot action %s", libraryPath.c_str());
     mLibHandle = dlopen(libraryPath.c_str(), RTLD_NOW);
     if (mLibHandle == nullptr) {
@@ -82,7 +175,7 @@ bool BootAction::init(const std::string& libraryPath) {
     }
 
     ALOGD("Entering boot_action_init");
-    bool result = mLibInit();
+    bool result = mLibInit(parameters.data(), parameters.size());
     ALOGD("Returned from boot_action_init");
     return result;
 }
index 495aa4f..d8bff75 100644 (file)
 #ifndef _BOOTANIMATION_BOOTACTION_H
 #define _BOOTANIMATION_BOOTACTION_H
 
+#include <map>
 #include <string>
 
+#include <base/json/json_value_converter.h>
 #include <utils/RefBase.h>
 
+using base::JSONValueConverter;
+
 namespace android {
 
 class BootAction : public RefBase {
 public:
+    struct BootParameter {
+      const char* key;
+      const char* value;
+    };
+
+    struct SavedBootParameters {
+      int brightness;
+      int volume;
+      ScopedVector<std::string> param_names;
+      ScopedVector<std::string> param_values;
+      static void RegisterJSONConverter(
+          JSONValueConverter<SavedBootParameters>* converter);
+    };
+
     ~BootAction();
 
+    // Rename next_boot.json to last_boot.json so that we don't repeat
+    // parameters if there is a crash before the framework comes up.
+    // TODO(b/65462981): Is this what we want to do? Should we swap in the
+    // framework instead?
+    static void swapBootConfigs();
+
     // libraryPath is a fully qualified path to the target .so library.
     bool init(const std::string& libraryPath);
 
@@ -41,7 +65,7 @@ public:
     void shutdown();
 
 private:
-    typedef bool (*libInit)();
+    typedef bool (*libInit)(const BootParameter* parameters, size_t num_parameters);
     typedef void (*libStartPart)(int partNumber, int playNumber);
     typedef void (*libShutdown)();
 
diff --git a/cmds/bootanimation/iot/bootanim_iot.rc b/cmds/bootanimation/iot/bootanim_iot.rc
new file mode 100644 (file)
index 0000000..2fc1336
--- /dev/null
@@ -0,0 +1,2 @@
+on post-fs-data
+    mkdir /data/misc/bootanimation 0777 root root
index d62478b..2527488 100644 (file)
@@ -80,6 +80,10 @@ private:
 int main() {
     setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_DISPLAY);
 
+    // TODO(b/65462981): Should we set brightness/volume here in case the boot
+    // animation is disabled?
+    BootAction::swapBootConfigs();
+
     if (bootAnimationDisabled()) {
         ALOGI("boot animation disabled");
         return 0;