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

Commit b7349902 authored by Tom Cherry's avatar Tom Cherry
Browse files

init: Use classes for parsing and clean up memory allocations

Create a Parser class that uses multiple SectionParser interfaces to
handle parsing the different sections of an init rc.

Create an ActionParser and ServiceParser that implement SectionParser
and parse the sections corresponding to Action and Service
classes.

Remove the legacy keyword structure and replace it with std::map's
that map keyword -> (minimum args, maximum args, function pointer) for
Commands and Service Options.

Create an ImportParser that implements SectionParser and handles the
import 'section'.

Clean up the unsafe memory handling of the Action class by using
std::unique_ptr.

Change-Id: Ic5ea5510cb956dbc3f78745a35096ca7d6da7085
parent e13fd9aa
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