C++程序  |  366行  |  13 KB

/*
 * Copyright (C) 2012 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 <stdlib.h>
#include <string.h>

#include <memory>
#include <vector>

#include "Log.h"
#include "StringUtil.h"
#include "task/TaskProcess.h"
#include "SignalProcessingImpl.h"

TaskProcess::TaskProcess()
    : TaskGeneric(TaskGeneric::ETaskProcess)
{

}

TaskProcess::~TaskProcess()
{
}

TaskGeneric::ExecutionResult TaskProcess::run()
{
    if (mType == EBuiltin) {
        return doRun(true);
    } else {
        if (mSp.get() == NULL) {
            mSp.reset(new SignalProcessingImpl());
            if (!mSp->init(SignalProcessingImpl::MAIN_PROCESSING_SCRIPT)) {
                mSp.reset(NULL);
                return TaskGeneric::EResultError;
            }
        }
        return doRun(false);
    }
}

// Allocate Buffers and Values to pass to builtin functions
bool TaskProcess::prepareParams(std::vector<TaskProcess::Param>& list,
        const bool* paramTypes,
        std::unique_ptr<void_ptr[]>& ptrs,
        std::unique_ptr<UniqueValue[]>& values,
        std::unique_ptr<UniqueBuffer[]>& buffers,
        bool isInput)
{
    size_t N = list.size();

    LOGD("TaskProcess::prepareParams N = %d", N);
    ptrs.reset(new void_ptr[N]);
    if (ptrs.get() == NULL) {
        LOGE("alloc failed");
        return false;
    }
    // set to NULL to detect illegal access
    bzero(ptrs.get(), N * sizeof(void_ptr));
    values.reset(new UniqueValue[N]);
    if (values.get() == NULL) {
        LOGE("alloc failed");
        return false;
    }
    buffers.reset(new UniqueBuffer[N]);
    if (buffers.get() == NULL) {
        LOGE("alloc failed");
        return false;
    }

    void_ptr* voidPtrs = ptrs.get();
    UniqueValue* valuesPtr = values.get();
    UniqueBuffer* buffersPtr = buffers.get();
    for (size_t i = 0; i < N; i++) {
        if ((paramTypes != NULL) && paramTypes[i] && (list[i].getType() != EId)) {
            LOGE("mismatching types %d %d", paramTypes[i], list[i].getType());
            return false;
        }
        if ((paramTypes != NULL) && !paramTypes[i] && (list[i].getType() == EId)) {
            LOGE("mismatching types %d %d", paramTypes[i], list[i].getType());
            return false;
        }
        switch(list[i].getType()) {
        case EId: {
            std::unique_ptr<android::sp<Buffer> > buffer(new android::sp<Buffer>());
            if (buffer.get() == NULL) {
                LOGE("alloc failed");
                return false;
            }
            if (isInput) {
                *(buffer.get()) = getTestCase()->findBuffer(list[i].getParamString());
                if (buffer.get()->get() == NULL) {
                    LOGE("find failed");
                    return false;
                }
                LOGD("input buffer len %d stereo %d", (*buffer.get())->getSize(),
                        (*buffer.get())->isStereo());
            }
            buffersPtr[i].reset(buffer.release());
            voidPtrs[i] = buffersPtr[i].get();
        }
        break;
        case EVal: {
            valuesPtr[i].reset(new TaskCase::Value());
            if (isInput) {
                if (!getTestCase()->findValue(list[i].getParamString(), *(valuesPtr[i].get()))) {
                    LOGE("find %s failed", list[i].getParamString().string());
                    return false;
                }
            }
            voidPtrs[i] = valuesPtr[i].get();
        }
        break;
        case EConst: {
            if (!isInput) {
                LOGE("const for output");
                return false;
            }
            voidPtrs[i] = list[i].getValuePtr();

            if (list[i].getValue().getType() == TaskCase::Value::ETypeDouble) {
                LOGD(" %f", list[i].getValue().getDouble());
            } else {
                LOGD(" %lld", list[i].getValue().getInt64());
            }
        }
        break;
        }
        LOGD("TaskProcess::prepareParams %d-th, const 0x%x", i, voidPtrs[i]);
    }
    return true;
}

// run builtin function by searching BuiltinProcessing::BUINTIN_FN_TABLE
TaskGeneric::ExecutionResult TaskProcess::doRun(bool builtIn)
{
    BuiltinProcessing::BuiltinInfo* info = NULL;
    if (builtIn) {
        for (int i = 0; i < BuiltinProcessing::N_BUILTIN_FNS; i++) {
            if (StringUtil::compare(mName, BuiltinProcessing::BUINTIN_FN_TABLE[i].mName) == 0) {
                info = &BuiltinProcessing::BUINTIN_FN_TABLE[i];
                break;
            }
        }
        if (info == NULL) {
            LOGE("TaskProcess::runBuiltin no match for %s", mName.string());
            return TaskGeneric::EResultError;
        }
        if (mInput.size() != info->mNInput) {
            LOGE("TaskProcess::runBuiltin size mismatch %d vs %d", mInput.size(), info->mNInput);
            return TaskGeneric::EResultError;
        }
        if (mOutput.size() != info->mNOutput) {
            LOGE("TaskProcess::runBuiltin size mismatch %d vs %d", mOutput.size(), info->mNOutput);
            return TaskGeneric::EResultError;
        }
    }
    // This is for passing to builtin fns. Just void pts will be cleared in exit
    std::unique_ptr<void_ptr[]> inputs;
    // This is for holding Value instances. Will be destroyed in exit
    std::unique_ptr<UniqueValue[]> inputValues;
    // This is for holding android::sp<Buffer>. Buffer itself is from the global map.
    std::unique_ptr<UniqueBuffer[]> inputBuffers;

    std::unique_ptr<void_ptr[]> outputs;
    // Value is created here. Builtin function just need to set it.
    std::unique_ptr<UniqueValue[]> outputValues;
    // Buffer itself should be allocated by the builtin function itself.
    std::unique_ptr<UniqueBuffer[]> outputBuffers;

    if (!prepareParams(mInput, builtIn ? info->mInputTypes : NULL, inputs, inputValues,
            inputBuffers, true)) {
        return TaskGeneric::EResultError;
    }

    if (!prepareParams(mOutput, builtIn ? info->mOutputTypes : NULL, outputs, outputValues,
            outputBuffers, false)) {
        return TaskGeneric::EResultError;
    }

    TaskGeneric::ExecutionResult result;
    if (builtIn) {
        result = (mBuiltin.*(info->mFunction))(inputs.get(), outputs.get());
    } else {
        std::unique_ptr<bool[]> inputTypes(new bool[mInput.size()]);
        for (size_t i = 0; i < mInput.size(); i++) {
            (inputTypes.get())[i] = mInput[i].isIdType();
        }
        std::unique_ptr<bool[]> outputTypes(new bool[mOutput.size()]);
        for (size_t i = 0; i < mOutput.size(); i++) {
            (outputTypes.get())[i] = mOutput[i].isIdType();
        }
        result = mSp->run( mName,
                mInput.size(), inputTypes.get(), inputs.get(),
                mOutput.size(), outputTypes.get(), outputs.get());
    }
    if ((result == TaskGeneric::EResultOK) || (result == TaskGeneric::EResultFail)
            || (result == TaskGeneric::EResultPass)) {
        // try to save result
        bool saveResultFailed = false;
        for (size_t i = 0; i < mOutput.size(); i++) {
            if (mOutput[i].isIdType()) { // Buffer
                android::sp<Buffer>* bufferp =
                        reinterpret_cast<android::sp<Buffer>*>((outputs.get())[i]);
                if (!getTestCase()->registerBuffer(mOutput[i].getParamString(), *bufferp)) {
                    // maybe already there, try update
                    if (!getTestCase()->updateBuffer(mOutput[i].getParamString(), *bufferp)) {
                        LOGE("cannot register / update %d-th output Buffer for builtin fn %s",
                                i, mName.string());
                        saveResultFailed = true; // mark failure, but continue
                    }
                }
            } else { // Value
                TaskCase::Value* valuep =
                        reinterpret_cast<TaskCase::Value*>((outputs.get())[i]);
                if (!getTestCase()->registerValue(mOutput[i].getParamString(), *valuep)) {
                    if (!getTestCase()->updateValue(mOutput[i].getParamString(), *valuep)) {
                        LOGE("cannot register / update %d-th output Value for builtin fn %s",
                                i, mName.string());
                        saveResultFailed = true; // mark failure, but continue
                    }
                }
            }
        }
        if (saveResultFailed) {
            LOGE("TaskProcess::runBuiltin cannot save result");
            return TaskGeneric::EResultError;
        }
    }
    LOGV("TaskProcess::runBuiltin return %d", result);
    return result;
}

bool TaskProcess::parseParams(std::vector<TaskProcess::Param>& list, const char* str, bool isInput)
{
    LOGV("TaskProcess::parseParams will parse %s", str);
    android::String8 paramStr(str);
    std::unique_ptr<std::vector<android::String8>> paramTokens(StringUtil::split(paramStr, ','));
    if (paramTokens.get() == NULL) {
        LOGE("split failed");
        return false;
    }
    std::vector<android::String8>& tokens = *(paramTokens.get());
    for (size_t i = 0; i < tokens.size(); i++) {
        std::unique_ptr<std::vector<android::String8>> itemTokens(StringUtil::split(tokens[i],
                                                                                    ':'));
        if (itemTokens.get() == NULL) {
            LOGE("split failed");
            return false;
        }
        if (itemTokens->size() != 2) {
            LOGE("size mismatch %d", itemTokens->size());
            return false;
        }
        std::vector<android::String8>& item = *(itemTokens.get());
        if (StringUtil::compare(item[0], "id") == 0) {
            Param param(EId, item[1]);
            list.push_back(param);
            LOGD(" id %s", param.getParamString().string());
        } else if (StringUtil::compare(item[0], "val") == 0) {
            Param param(EVal, item[1]);
            list.push_back(param);
            LOGD(" val %s", param.getParamString().string());
        } else if (isInput && (StringUtil::compare(item[0], "consti") == 0)) {
            int64_t value = atoll(item[1].string());
            TaskCase::Value v(value);
            Param param(v);
            list.push_back(param);
            LOGD("consti %lld", value);
        } else if (isInput && (StringUtil::compare(item[0], "constf") == 0)) {
            double value = atof(item[1].string());
            TaskCase::Value v(value);
            Param param(v);
            list.push_back(param);
            LOGD("constf %f", value);
        } else {
            LOGE("unrecognized word %s", item[0].string());
            return false;
        }
        LOGV("TaskProcess::parseParams %d-th type %d", i, list[i].getType());
    }
   return true;
}

bool TaskProcess::parseAttribute(const android::String8& name, const android::String8& value)
{
    if (StringUtil::compare(name, "method") == 0) {
        std::unique_ptr<std::vector<android::String8> > tokenPtr(StringUtil::split(value, ':'));
        std::vector<android::String8>* tokens = tokenPtr.get();
        if (tokens == NULL) {
            LOGE("split failed");
            return false;
        }
        if (tokens->size() != 2) {
            LOGE("cannot parse attr %s %s", name.string(), value.string());
            return false;
        }
        if (StringUtil::compare(tokens->at(0), "builtin") == 0) {
            mType = EBuiltin;
        } else if (StringUtil::compare(tokens->at(0), "script") == 0) {
            mType = EScript;
        } else {
            LOGE("cannot parse attr %s %s", name.string(), value.string());
            return false;
        }
        mName.append(tokens->at(1));
        return true;
    } else if (StringUtil::compare(name, "input") == 0) {
        return parseParams(mInput, value, true);
    } else if (StringUtil::compare(name, "output") == 0) {
        return parseParams(mOutput, value, false);
    } else {
        LOGE("cannot parse attr %s %s", name.string(), value.string());
        return false;
    }
}

TaskProcess::Param::Param(TaskProcess::ParamType type, android::String8& string)
    : mType(type),
      mString(string)
{
    ASSERT((type == TaskProcess::EId) || (type == TaskProcess::EVal));

}

TaskProcess::Param::Param(TaskCase::Value& val)
    : mType(TaskProcess::EConst),
      mValue(val)
{

}

TaskProcess::ParamType TaskProcess::Param::getType()
{
    return mType;
}

android::String8& TaskProcess::Param::getParamString()
{
    ASSERT((mType == TaskProcess::EId) || (mType == TaskProcess::EVal));
    return mString;
}

TaskCase::Value& TaskProcess::Param::getValue()
{
    ASSERT(mType == TaskProcess::EConst);
    return mValue;
}

TaskCase::Value* TaskProcess::Param::getValuePtr()
{
    ASSERT(mType == TaskProcess::EConst);
    return &mValue;
}