Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 54a8fe4b authored by David Pursell's avatar David Pursell
Browse files

iot: extract boot parameter logic.

Currently the boot parameters are tied pretty tightly to the bootaction
functionality, but volume and brightness need to be set on the
bootanimation regardless of whether there's a bootaction or not.

Extract boot parameters into a separate class to make it easier to apply
volume/brightness in a future CL.

Bug: 65462981
Test: Manual test, can succesfully read params on boot.
Change-Id: I32daad64cb8aab39fcd0ca17503218e0605ccd27
(cherry picked from commit f78561e7bbe580d0f0dbca7a615c575973ef6ce4)
parent 47944a00
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -31,12 +31,13 @@ LOCAL_SHARED_LIBRARIES += \

LOCAL_SRC_FILES += \
    iot/iotbootanimation_main.cpp \
    iot/BootAction.cpp
    iot/BootAction.cpp \
    iot/BootParameters.cpp \

LOCAL_SHARED_LIBRARIES += \
    libandroidthings \
    libbase \
    libbinder
    libbinder \

LOCAL_STATIC_LIBRARIES += cpufeatures

+2 −99
Original line number Diff line number Diff line
@@ -19,96 +19,20 @@
#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 <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) {
bool BootAction::init(const std::string& libraryPath,
                      const std::vector<ABootActionParameter>& parameters) {
    APeripheralManagerClient* client = nullptr;
    ALOGD("Connecting to peripheralmanager");
    // Wait for peripheral manager to come up.
@@ -122,27 +46,6 @@ bool BootAction::init(const std::string& libraryPath) {
    ALOGD("Peripheralmanager is up.");
    APeripheralManagerClient_delete(client);

    float brightness = -1.0f;
    float volume = -1.0f;
    std::vector<ABootActionParameter> 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);
+3 −20
Original line number Diff line number Diff line
@@ -17,38 +17,21 @@
#ifndef _BOOTANIMATION_BOOTACTION_H
#define _BOOTANIMATION_BOOTACTION_H

#include <map>
#include <string>
#include <vector>

#include <base/json/json_value_converter.h>
#include <boot_action/boot_action.h>  // libandroidthings native API.
#include <utils/RefBase.h>

using base::JSONValueConverter;

namespace android {

class BootAction : public RefBase {
public:
    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);
    bool init(const std::string& libraryPath,
              const std::vector<ABootActionParameter>& parameters);

    // The animation is going to start playing partNumber for the playCount'th
    // time, update the action as needed.
+124 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * 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 "BootParameters.h"

#define LOG_TAG "BootParameters"

#include <fcntl.h>

#include <string>

#include <android-base/file.h>
#include <base/json/json_parser.h>
#include <base/json/json_reader.h>
#include <base/json/json_value_converter.h>
#include <utils/Log.h>

using android::base::RemoveFileIfExists;
using android::base::ReadFileToString;
using base::JSONReader;
using base::JSONValueConverter;
using base::Value;

namespace android {

namespace {

// 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";

void 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 writable to everyone so DeviceManagementService
        // can save saved_parameters there.
        if (fchmod(fd, DEFFILEMODE))
            ALOGE("Unable to set next boot file permissions: %s", strerror(errno));
        close(fd);
    }
}

}  // namespace

BootParameters::SavedBootParameters::SavedBootParameters()
    : brightness(-kFloatScaleFactor), volume(-kFloatScaleFactor) {}

void BootParameters::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);
}

BootParameters::BootParameters() {
    swapBootConfigs();
    loadParameters();
}

void BootParameters::loadParameters() {
    std::string contents;
    if (!ReadFileToString(kLastBootFile, &contents)) {
        if (errno != ENOENT)
            ALOGE("Unable to read from %s: %s", kLastBootFile, strerror(errno));

        return;
    }

    std::unique_ptr<Value> json = JSONReader::Read(contents);
    if (json.get() == nullptr) {
        return;
    }

    JSONValueConverter<SavedBootParameters> converter;
    if (converter.Convert(*(json.get()), &mRawParameters)) {
        mBrightness = mRawParameters.brightness / kFloatScaleFactor;
        mVolume = mRawParameters.volume / kFloatScaleFactor;

        if (mRawParameters.param_names.size() == mRawParameters.param_values.size()) {
            for (size_t i = 0; i < mRawParameters.param_names.size(); i++) {
                mParameters.push_back({
                        .key = mRawParameters.param_names[i]->c_str(),
                        .value = mRawParameters.param_values[i]->c_str()
                });
            }
        } else {
            ALOGW("Parameter names and values size mismatch");
        }
    }
}

}  // namespace android
+73 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * 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.
 */

#ifndef _BOOTANIMATION_BOOT_PARAMETERS_H_
#define _BOOTANIMATION_BOOT_PARAMETERS_H_

#include <list>
#include <vector>

#include <base/json/json_value_converter.h>
#include <boot_action/boot_action.h>  // libandroidthings native API.

namespace android {

// Provides access to the parameters set by DeviceManager.reboot().
class BootParameters {
public:
    // Constructor loads the parameters for this boot and swaps the param files
    // to clear the parameters for next boot.
    BootParameters();

    // Returns true if volume/brightness were explicitly set on reboot.
    bool hasVolume() const { return mVolume >= 0; }
    bool hasBrightness() const { return mBrightness >= 0; }

    // Returns volume/brightness in [0,1], or -1 if unset.
    float getVolume() const { return mVolume; }
    float getBrightness() const { return mBrightness; }

    // Returns the additional boot parameters that were set on reboot.
    const std::vector<ABootActionParameter>& getParameters() const { return mParameters; }

private:
    // Raw boot saved_parameters loaded from .json.
    struct SavedBootParameters {
        int brightness;
        int volume;
        ScopedVector<std::string> param_names;
        ScopedVector<std::string> param_values;

        SavedBootParameters();
        static void RegisterJSONConverter(
                ::base::JSONValueConverter<SavedBootParameters>* converter);
    };

    void loadParameters();

    float mVolume = -1.f;
    float mBrightness = -1.f;
    std::vector<ABootActionParameter> mParameters;

    // ABootActionParameter is just a raw pointer so we need to keep the
    // original strings around to avoid losing them.
    SavedBootParameters mRawParameters;
};

}  // namespace android


#endif  // _BOOTANIMATION_BOOT_PARAMETERS_H_
Loading