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

Commit 54c70ca1 authored by Tom Cherry's avatar Tom Cherry Committed by Gerrit Code Review
Browse files

Merge "init: Use classes for parsing and clean up memory allocations"

parents 78ea165e b7349902
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@ include $(CLEAR_VARS)
LOCAL_CPPFLAGS := $(init_cflags)
LOCAL_SRC_FILES:= \
    action.cpp \
    import_parser.cpp \
    init_parser.cpp \
    log.cpp \
    parser.cpp \
+151 −135
Original line number Diff line number Diff line
@@ -21,46 +21,27 @@
#include <base/strings.h>
#include <base/stringprintf.h>

#include "builtins.h"
#include "error.h"
#include "init_parser.h"
#include "log.h"
#include "property_service.h"
#include "util.h"

class Action::Command
{
public:
    Command(int (*f)(const std::vector<std::string>& args),
            const std::vector<std::string>& args,
            const std::string& filename,
            int line);

    int InvokeFunc() const;
    std::string BuildCommandString() const;
    std::string BuildSourceString() const;

private:
    int (*func_)(const std::vector<std::string>& args);
    const std::vector<std::string> args_;
    const std::string filename_;
    int line_;
};
using android::base::Join;
using android::base::StringPrintf;

Action::Command::Command(int (*f)(const std::vector<std::string>& args),
                         const std::vector<std::string>& args,
                         const std::string& filename,
                         int line) :
    func_(f), args_(args), filename_(filename), line_(line)
{
Command::Command(BuiltinFunction f, const std::vector<std::string>& args,
                 const std::string& filename, int line)
    : func_(f), args_(args), filename_(filename), line_(line) {
}

int Action::Command::InvokeFunc() const
{
int Command::InvokeFunc() const {
    std::vector<std::string> expanded_args;
    expanded_args.resize(args_.size());
    expanded_args[0] = args_[0];
    for (std::size_t i = 1; i < args_.size(); ++i) {
        if (expand_props(args_[i], &expanded_args[i]) == -1) {
        if (!expand_props(args_[i], &expanded_args[i])) {
            ERROR("%s: cannot expand '%s'\n", args_[0].c_str(), args_[i].c_str());
            return -EINVAL;
        }
@@ -69,51 +50,71 @@ int Action::Command::InvokeFunc() const
    return func_(expanded_args);
}

std::string Action::Command::BuildCommandString() const
{
    return android::base::Join(args_, ' ');
std::string Command::BuildCommandString() const {
    return Join(args_, ' ');
}

std::string Action::Command::BuildSourceString() const
{
std::string Command::BuildSourceString() const {
    if (!filename_.empty()) {
        return android::base::StringPrintf(" (%s:%d)", filename_.c_str(), line_);
        return StringPrintf(" (%s:%d)", filename_.c_str(), line_);
    } else {
        return std::string();
    }
}

Action::Action()
{
Action::Action(bool oneshot) : oneshot_(oneshot) {
}

const KeywordMap<BuiltinFunction>* Action::function_map_ = nullptr;

bool Action::AddCommand(const std::vector<std::string>& args,
                        const std::string& filename, int line, std::string* err) {
    if (!function_map_) {
        *err = "no function map available";
        return false;
    }

    if (args.empty()) {
        *err = "command needed, but not provided";
        return false;
    }

void Action::AddCommand(int (*f)(const std::vector<std::string>& args),
    auto function = function_map_->FindFunction(args[0], args.size() - 1, err);
    if (!function) {
        return false;
    }

    AddCommand(function, args, filename, line);
    return true;
}

void Action::AddCommand(BuiltinFunction f,
                        const std::vector<std::string>& args,
                        const std::string& filename, int line)
{
    Action::Command* cmd = new Action::Command(f, args, filename, line);
    commands_.push_back(cmd);
                        const std::string& filename, int line) {
    commands_.emplace_back(f, args, filename, line);
}

std::size_t Action::NumCommands() const
{
void Action::CombineAction(const Action& action) {
    for (const auto& c : action.commands_) {
        commands_.emplace_back(c);
    }
}

std::size_t Action::NumCommands() const {
    return commands_.size();
}

void Action::ExecuteOneCommand(std::size_t command) const
{
    ExecuteCommand(*commands_[command]);
void Action::ExecuteOneCommand(std::size_t command) const {
    ExecuteCommand(commands_[command]);
}

void Action::ExecuteAllCommands() const
{
void Action::ExecuteAllCommands() const {
    for (const auto& c : commands_) {
        ExecuteCommand(*c);
        ExecuteCommand(c);
    }
}

void Action::ExecuteCommand(const Command& command) const
{
void Action::ExecuteCommand(const Command& command) const {
    Timer t;
    int result = command.InvokeFunc();

@@ -128,8 +129,7 @@ void Action::ExecuteCommand(const Command& command) const
    }
}

bool Action::ParsePropertyTrigger(const std::string& trigger, std::string* err)
{
bool Action::ParsePropertyTrigger(const std::string& trigger, std::string* err) {
    const static std::string prop_str("property:");
    std::string prop_name(trigger.substr(prop_str.length()));
    size_t equal_pos = prop_name.find('=');
@@ -149,8 +149,7 @@ bool Action::ParsePropertyTrigger(const std::string& trigger, std::string* err)
    return true;
}

bool Action::InitTriggers(const std::vector<std::string>& args, std::string* err)
{
bool Action::InitTriggers(const std::vector<std::string>& args, std::string* err) {
    const static std::string prop_str("property:");
    for (std::size_t i = 0; i < args.size(); ++i) {
        if (i % 2) {
@@ -179,21 +178,26 @@ bool Action::InitTriggers(const std::vector<std::string>& args, std::string* err
    return true;
}

bool Action::InitSingleTrigger(const std::string& trigger)
{
bool Action::InitSingleTrigger(const std::string& trigger) {
    std::vector<std::string> name_vector{trigger};
    std::string err;
    return InitTriggers(name_vector, &err);
}

// This function checks that all property triggers are satisfied, that is
// for each (name, value) in property_triggers_, check that the current
// value of the property 'name' == value.
//
// It takes an optional (name, value) pair, which if provided must
// be present in property_triggers_; it skips the check of the current
// property value for this pair.
bool Action::CheckPropertyTriggers(const std::string& name,
                                   const std::string& value) const
{
    bool found = name.empty();
                                   const std::string& value) const {
    if (property_triggers_.empty()) {
        return true;
    }

    bool found = name.empty();
    for (const auto& t : property_triggers_) {
        const auto& trigger_name = t.first;
        const auto& trigger_value = t.second;
@@ -214,27 +218,23 @@ bool Action::CheckPropertyTriggers(const std::string& name,
    return found;
}

bool Action::CheckEventTrigger(const std::string& trigger) const
{
bool Action::CheckEventTrigger(const std::string& trigger) const {
    return !event_trigger_.empty() &&
        trigger == event_trigger_ &&
        CheckPropertyTriggers();
}

bool Action::CheckPropertyTrigger(const std::string& name,
                                  const std::string& value) const
{
                                  const std::string& value) const {
    return event_trigger_.empty() && CheckPropertyTriggers(name, value);
}

bool Action::TriggersEqual(const class Action& other) const
{
bool Action::TriggersEqual(const Action& other) const {
    return property_triggers_ == other.property_triggers_ &&
        event_trigger_ == other.event_trigger_;
}

std::string Action::BuildTriggersString() const
{
std::string Action::BuildTriggersString() const {
    std::string result;

    for (const auto& t : property_triggers_) {
@@ -251,28 +251,26 @@ std::string Action::BuildTriggersString() const
    return result;
}

void Action::DumpState() const
{
void Action::DumpState() const {
    std::string trigger_name = BuildTriggersString();
    INFO("on %s\n", trigger_name.c_str());

    for (const auto& c : commands_) {
        std::string cmd_str = c->BuildCommandString();
        std::string cmd_str = c.BuildCommandString();
        INFO(" %s\n", cmd_str.c_str());
    }
    INFO("\n");
}


class EventTrigger : public Trigger {
public:
    EventTrigger(const std::string& trigger) : trigger_(trigger) {
    }
    bool CheckTriggers(const Action* action) override {
        return action->CheckEventTrigger(trigger_);
    bool CheckTriggers(const Action& action) const override {
        return action.CheckEventTrigger(trigger_);
    }
private:
    std::string trigger_;
    const std::string trigger_;
};

class PropertyTrigger : public Trigger {
@@ -280,27 +278,26 @@ public:
    PropertyTrigger(const std::string& name, const std::string& value)
        : name_(name), value_(value) {
    }
    bool CheckTriggers(const Action* action) override {
        return action->CheckPropertyTrigger(name_, value_);
    bool CheckTriggers(const Action& action) const override {
        return action.CheckPropertyTrigger(name_, value_);
    }
private:
    std::string name_;
    std::string value_;
    const std::string name_;
    const std::string value_;
};

class BuiltinTrigger : public Trigger {
public:
    BuiltinTrigger(Action* action) : action_(action) {
    }
    bool CheckTriggers(const Action* action) override {
        return action == action_;
    bool CheckTriggers(const Action& action) const override {
        return action_ == &action;
    }
private:
    Action* action_;
    const Action* action_;
};

ActionManager::ActionManager() : current_command_(0)
{
ActionManager::ActionManager() : current_command_(0) {
}

ActionManager& ActionManager::GetInstance() {
@@ -308,45 +305,56 @@ ActionManager& ActionManager::GetInstance() {
    return instance;
}

void ActionManager::QueueEventTrigger(const std::string& trigger)
{
void ActionManager::AddAction(std::unique_ptr<Action> action) {
    auto old_action_it =
        std::find_if(actions_.begin(), actions_.end(),
                     [&action] (std::unique_ptr<Action>& a) {
                         return action->TriggersEqual(*a);
                     });

    if (old_action_it != actions_.end()) {
        (*old_action_it)->CombineAction(*action);
    } else {
        actions_.emplace_back(std::move(action));
    }
}

void ActionManager::QueueEventTrigger(const std::string& trigger) {
    trigger_queue_.push(std::make_unique<EventTrigger>(trigger));
}

void ActionManager::QueuePropertyTrigger(const std::string& name,
                                         const std::string& value)
{
                                         const std::string& value) {
    trigger_queue_.push(std::make_unique<PropertyTrigger>(name, value));
}

void ActionManager::QueueAllPropertyTriggers()
{
void ActionManager::QueueAllPropertyTriggers() {
    QueuePropertyTrigger("", "");
}

void ActionManager::QueueBuiltinAction(int (*func)(const std::vector<std::string>& args),
                                       const std::string& name)
{
    Action* act = new Action();
void ActionManager::QueueBuiltinAction(BuiltinFunction func,
                                       const std::string& name) {
    auto action = std::make_unique<Action>(true);
    std::vector<std::string> name_vector{name};

    if (!act->InitSingleTrigger(name)) {
    if (!action->InitSingleTrigger(name)) {
        return;
    }

    act->AddCommand(func, name_vector);
    action->AddCommand(func, name_vector);

    actions_.push_back(act);
    trigger_queue_.push(std::make_unique<BuiltinTrigger>(act));
    trigger_queue_.push(std::make_unique<BuiltinTrigger>(action.get()));
    actions_.emplace_back(std::move(action));
}

void ActionManager::ExecuteOneCommand() {
    // Loop through the trigger queue until we have an action to execute
    while (current_executing_actions_.empty() && !trigger_queue_.empty()) {
        std::copy_if(actions_.begin(), actions_.end(),
                     std::back_inserter(current_executing_actions_),
                     [this] (Action* act) {
                         return trigger_queue_.front()->CheckTriggers(act);
                     });
        for (const auto& action : actions_) {
            if (trigger_queue_.front()->CheckTriggers(*action)) {
                current_executing_actions_.emplace(action.get());
            }
        }
        trigger_queue_.pop();
    }

@@ -354,59 +362,67 @@ void ActionManager::ExecuteOneCommand() {
        return;
    }

    Action* action = current_executing_actions_.back();
    if (!action->NumCommands()) {
        current_executing_actions_.pop_back();
        return;
    }
    auto action = current_executing_actions_.front();

    if (current_command_ == 0) {
        std::string trigger_name = action->BuildTriggersString();
        INFO("processing action %p (%s)\n", action, trigger_name.c_str());
        INFO("processing action (%s)\n", trigger_name.c_str());
    }

    action->ExecuteOneCommand(current_command_++);
    action->ExecuteOneCommand(current_command_);

    // If this was the last command in the current action, then remove
    // the action from the executing list.
    // If this action was oneshot, then also remove it from actions_.
    ++current_command_;
    if (current_command_ == action->NumCommands()) {
        current_executing_actions_.pop();
        current_command_ = 0;
        current_executing_actions_.pop_back();
        if (action->oneshot()) {
            auto eraser = [&action] (std::unique_ptr<Action>& a) {
                return a.get() == action;
            };
            actions_.erase(std::remove_if(actions_.begin(), actions_.end(), eraser));
        }
    }
}

bool ActionManager::HasMoreCommands() const
{
bool ActionManager::HasMoreCommands() const {
    return !current_executing_actions_.empty() || !trigger_queue_.empty();
}

Action* ActionManager::AddNewAction(const std::vector<std::string>& triggers,
                                    std::string* err)
{
    if (triggers.size() < 1) {
        *err = "actions must have a trigger\n";
        return nullptr;
void ActionManager::DumpState() const {
    for (const auto& a : actions_) {
        a->DumpState();
    }
    INFO("\n");
}

    Action* act = new Action();
    if (!act->InitTriggers(triggers, err)) {
        return nullptr;
bool ActionParser::ParseSection(const std::vector<std::string>& args,
                                std::string* err) {
    std::vector<std::string> triggers(args.begin() + 1, args.end());
    if (triggers.size() < 1) {
        *err = "actions must have a trigger";
        return false;
    }

    auto old_act_it =
        std::find_if(actions_.begin(), actions_.end(),
                     [&act] (Action* a) { return act->TriggersEqual(*a); });
    auto action = std::make_unique<Action>(false);
    if (!action->InitTriggers(triggers, err)) {
        return false;
    }

    if (old_act_it != actions_.end()) {
        delete act;
        return *old_act_it;
    action_ = std::move(action);
    return true;
}

    actions_.push_back(act);
    return act;
bool ActionParser::ParseLineSection(const std::vector<std::string>& args,
                                    const std::string& filename, int line,
                                    std::string* err) const {
    return action_ ? action_->AddCommand(args, filename, line, err) : false;
}

void ActionManager::DumpState() const
{
    for (const auto& a : actions_) {
        a->DumpState();
void ActionParser::EndSection() {
    if (action_ && action_->NumCommands() > 0) {
        ActionManager::GetInstance().AddAction(std::move(action_));
    }
    INFO("\n");
}
+57 −13
Original line number Diff line number Diff line
@@ -22,13 +22,36 @@
#include <string>
#include <vector>

#include "builtins.h"
#include "init_parser.h"
#include "keyword_map.h"

class Command {
public:
    Command(BuiltinFunction f, const std::vector<std::string>& args,
            const std::string& filename, int line);

    int InvokeFunc() const;
    std::string BuildCommandString() const;
    std::string BuildSourceString() const;

private:
    BuiltinFunction func_;
    std::vector<std::string> args_;
    std::string filename_;
    int line_;
};

class Action {
public:
    Action();
    Action(bool oneshot = false);

    void AddCommand(int (*f)(const std::vector<std::string>& args),
    bool AddCommand(const std::vector<std::string>& args,
                    const std::string& filename, int line, std::string* err);
    void AddCommand(BuiltinFunction f,
                    const std::vector<std::string>& args,
                    const std::string& filename = "", int line = 0);
    void CombineAction(const Action& action);
    bool InitTriggers(const std::vector<std::string>& args, std::string* err);
    bool InitSingleTrigger(const std::string& trigger);
    std::size_t NumCommands() const;
@@ -37,13 +60,17 @@ public:
    bool CheckEventTrigger(const std::string& trigger) const;
    bool CheckPropertyTrigger(const std::string& name,
                              const std::string& value) const;
    bool TriggersEqual(const class Action& other) const;
    bool TriggersEqual(const Action& other) const;
    std::string BuildTriggersString() const;
    void DumpState() const;

private:
    class Command;
    bool oneshot() const { return oneshot_; }
    static void set_function_map(const KeywordMap<BuiltinFunction>* function_map) {
        function_map_ = function_map;
    }


private:
    void ExecuteCommand(const Command& command) const;
    bool CheckPropertyTriggers(const std::string& name = "",
                               const std::string& value = "") const;
@@ -51,27 +78,28 @@ private:

    std::map<std::string, std::string> property_triggers_;
    std::string event_trigger_;
    std::vector<Command*> commands_;
    std::vector<Command> commands_;
    bool oneshot_;
    static const KeywordMap<BuiltinFunction>* function_map_;
};

class Trigger {
public:
    virtual ~Trigger() { }
    virtual bool CheckTriggers(const Action* action) = 0;
    virtual bool CheckTriggers(const Action& action) const = 0;
};

class ActionManager {
public:
    static ActionManager& GetInstance();

    void AddAction(std::unique_ptr<Action> action);
    void QueueEventTrigger(const std::string& trigger);
    void QueuePropertyTrigger(const std::string& name, const std::string& value);
    void QueueAllPropertyTriggers();
    void QueueBuiltinAction(int (*func)(const std::vector<std::string>& args),
                            const std::string& name);
    void QueueBuiltinAction(BuiltinFunction func, const std::string& name);
    void ExecuteOneCommand();
    bool HasMoreCommands() const;
    Action* AddNewAction(const std::vector<std::string>& triggers,
                         std::string* err);
    void DumpState() const;

private:
@@ -80,10 +108,26 @@ private:
    ActionManager(ActionManager const&) = delete;
    void operator=(ActionManager const&) = delete;

    std::vector<Action*> actions_;
    std::vector<std::unique_ptr<Action>> actions_;
    std::queue<std::unique_ptr<Trigger>> trigger_queue_;
    std::vector<Action*> current_executing_actions_;
    std::queue<const Action*> current_executing_actions_;
    std::size_t current_command_;
};

class ActionParser : public SectionParser {
public:
    ActionParser() : action_(nullptr) {
    }
    bool ParseSection(const std::vector<std::string>& args,
                      std::string* err) override;
    bool ParseLineSection(const std::vector<std::string>& args,
                          const std::string& filename, int line,
                          std::string* err) const override;
    void EndSection() override;
    void EndFile(const std::string&) override {
    }
private:
    std::unique_ptr<Action> action_;
};

#endif
+1 −1
Original line number Diff line number Diff line
@@ -15,7 +15,6 @@
 */

#include "bootchart.h"
#include "keywords.h"
#include "log.h"
#include "property_service.h"

@@ -32,6 +31,7 @@

#include <memory>
#include <string>
#include <vector>

#include <base/file.h>

+4 −0
Original line number Diff line number Diff line
@@ -17,6 +17,10 @@
#ifndef _BOOTCHART_H
#define _BOOTCHART_H

#include <string>
#include <vector>

int do_bootchart_init(const std::vector<std::string>& args);
void bootchart_sample(int* timeout);

#endif /* _BOOTCHART_H */
Loading