First implementation of the Neural Networks API.

This first version can run a simple query on the CPU either
via the fallback path or through a simulated driver.

This code has many deficiencies: single threaded, not all
validation are done, not going through HIDL, and not
enough unit tests.  Expect more changes!

Test: Compiled and ran the unit tests

Change-Id: I9f6a485a2e7207aeb5f91a2904dcb4b7fd8a6f65
diff --git a/runtime/NeuralNetworks.cpp b/runtime/NeuralNetworks.cpp
new file mode 100644
index 0000000..73b2346
--- /dev/null
+++ b/runtime/NeuralNetworks.cpp
@@ -0,0 +1,377 @@
+/*
+ * 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.
+ */
+
+// Contains all the entry points to the C Neural Networks API.
+// We do basic validation of the operands and then call the class
+// that implements the functionality.
+
+#define LOG_TAG "NeuralNetworks"
+
+#include "NeuralNetworks.h"
+#include "Manager.h"
+#include "ModelBuilder.h"
+#include "Request.h"
+
+#include <vector>
+
+using namespace android::nn;
+
+// Validates the type. The used dimensions can be underspecified.
+static int ValidateOperandType(const ANeuralNetworksOperandType& type, const char* tag,
+                               bool allowPartial) {
+    if (!allowPartial) {
+        for (uint32_t i = 0; i < type.dimensions.count; i++) {
+            if (type.dimensions.data[i] == 0) {
+                ALOGE("%s OperandType invalid dimensions[%u] = %u", tag, i,
+                      type.dimensions.data[i]);
+                return ANEURALNETWORKS_BAD_DATA;
+            }
+        }
+    }
+    if (type.type >= ANEURALNETWORKS_NUMBER_DATA_TYPES) {
+        ALOGE("%s OperandType invalid type %u", tag, type.type);
+        return ANEURALNETWORKS_BAD_DATA;
+    }
+    /* TODO validate the quantization info.
+    if (type.offset != 0.f && type.scale == 0.f) {
+        ALOGE("%s OperandType invalid offset %f and scale %f", tag, type.offset,
+    type.scale); return ANEURALNETWORKS_BAD_DATA;
+    }
+    if (type.scale != 0.f &&
+        (type.type == ANEURALNETWORKS_FLOAT16 ||
+         type.type != ANEURALNETWORKS_FLOAT32)) {
+            ALOGE("%s OperandType scale %f with float type %u", tag, type.scale,
+    type.type); return ANEURALNETWORKS_BAD_DATA;
+        }
+     */
+    return ANEURALNETWORKS_NO_ERROR;
+}
+
+static int ValidateOperandList(const ANeuralNetworksIntList& list, uint32_t count,
+                               const char* tag) {
+    for (uint32_t i = 0; i < list.count; i++) {
+        if (list.data[i] >= count) {
+            ALOGE("%s invalid operand index at %u = %u, count %u", tag, i, list.data[i], count);
+            return ANEURALNETWORKS_BAD_DATA;
+        }
+    }
+    return ANEURALNETWORKS_NO_ERROR;
+}
+
+int ANeuralNetworksInitialize() {
+    DriverManager::get()->initialize();
+    return ANEURALNETWORKS_NO_ERROR;
+}
+
+void ANeuralNetworksShutdown() {
+    DriverManager::get()->shutdown();
+}
+
+int ANeuralNetworksModel_create(ANeuralNetworksModel** model) {
+    if (!model) {
+        ALOGE("ANeuralNetworksModel_create passed a nullptr");
+        return ANEURALNETWORKS_UNEXPECTED_NULL;
+    }
+    ModelBuilder* m = new ModelBuilder();
+    if (m == nullptr) {
+        *model = nullptr;
+        return ANEURALNETWORKS_OUT_OF_MEMORY;
+    }
+    *model = reinterpret_cast<ANeuralNetworksModel*>(m);
+    return ANEURALNETWORKS_NO_ERROR;
+}
+
+int ANeuralNetworksModel_createBaselineModel(ANeuralNetworksModel** model, uint32_t modelId) {
+    if (!model) {
+        ALOGE("ANeuralNetworksModel_create passed a nullptr");
+        return ANEURALNETWORKS_UNEXPECTED_NULL;
+    }
+    if (modelId >= ANEURALNETWORKS_NUMBER_BASELINE_MODELS) {
+        ALOGE("ANeuralNetworksModel_createBaselineModel invalid modelId %u", modelId);
+        return ANEURALNETWORKS_BAD_DATA;
+    }
+
+    ModelBuilder* m = new ModelBuilder();
+    if (m == nullptr) {
+        *model = nullptr;
+        return ANEURALNETWORKS_OUT_OF_MEMORY;
+    }
+    /* TODO uint32_t n = m->loadBaseLineModel(modelId);
+    if (n != ANEURALNETWORKS_NO_ERROR) {
+        delete m;
+        return n;
+    }
+     */
+    *model = reinterpret_cast<ANeuralNetworksModel*>(m);
+    return ANEURALNETWORKS_NO_ERROR;
+}
+
+void ANeuralNetworksModel_free(ANeuralNetworksModel* model) {
+    // No validation.  Free of nullptr is valid.
+    ModelBuilder* m = reinterpret_cast<ModelBuilder*>(model);
+    delete m;
+}
+
+int ANeuralNetworksModel_addOperand(ANeuralNetworksModel* model,
+                                    const ANeuralNetworksOperandType* type) {
+    if (!model || !type) {
+        ALOGE("ANeuralNetworksModel_addOperand passed a nullptr");
+        return ANEURALNETWORKS_UNEXPECTED_NULL;
+    }
+    ModelBuilder* m = reinterpret_cast<ModelBuilder*>(model);
+    int n = ValidateOperandType(*type, "ANeuralNetworksModel_addOperand", true);
+    if (n != ANEURALNETWORKS_NO_ERROR) {
+        return n;
+    }
+    return m->addOperand(*type);
+}
+
+int ANeuralNetworksModel_setOperandValue(ANeuralNetworksModel* model, int32_t index,
+                                         const void* buffer, size_t length) {
+    if (!model || !buffer) {
+        ALOGE("ANeuralNetworksModel_setOperandValue passed a nullptr");
+        return ANEURALNETWORKS_UNEXPECTED_NULL;
+    }
+    ModelBuilder* m = reinterpret_cast<ModelBuilder*>(model);
+    return m->setOperandValue(index, buffer, length);
+}
+
+int ANeuralNetworksModel_addOperation(ANeuralNetworksModel* model,
+                                      ANeuralNetworksOperationType type,
+                                      ANeuralNetworksIntList* inputs,
+                                      ANeuralNetworksIntList* outputs) {
+    if (!model || !inputs || !outputs) {
+        ALOGE("ANeuralNetworksModel_addOperation passed a nullptr");
+        return ANEURALNETWORKS_UNEXPECTED_NULL;
+    }
+    ModelBuilder* m = reinterpret_cast<ModelBuilder*>(model);
+    if (type >= ANEURALNETWORKS_NUMBER_OPERATION_TYPES) {
+        ALOGE("ANeuralNetworksModel_addOperation invalid operations type %u", type);
+        return ANEURALNETWORKS_BAD_DATA;
+    }
+    int n = ValidateOperandList(*inputs, m->operandCount(),
+                                "ANeuralNetworksModel_addOperation inputs");
+    if (n != ANEURALNETWORKS_NO_ERROR) {
+        return n;
+    }
+    n = ValidateOperandList(*outputs, m->operandCount(),
+                            "ANeuralNetworksModel_addOperation outputs");
+    if (n != ANEURALNETWORKS_NO_ERROR) {
+        return n;
+    }
+
+    return m->addOperation(type, inputs, outputs);
+}
+
+int ANeuralNetworksModel_setInputsAndOutputs(ANeuralNetworksModel* model,
+                                             ANeuralNetworksIntList* inputs,
+                                             ANeuralNetworksIntList* outputs) {
+    if (!model || !inputs || !outputs) {
+        ALOGE("ANeuralNetworksModel_setInputsAndOutputs passed a nullptr");
+        return ANEURALNETWORKS_UNEXPECTED_NULL;
+    }
+    ModelBuilder* m = reinterpret_cast<ModelBuilder*>(model);
+    int n = ValidateOperandList(*inputs, m->operandCount(),
+                                "ANeuralNetworksModel_setInputsAndOutputs inputs");
+    if (n != ANEURALNETWORKS_NO_ERROR) {
+        return n;
+    }
+    n = ValidateOperandList(*outputs, m->operandCount(),
+                            "ANeuralNetworksModel_setInputsAndOutputs outputs");
+    if (n != ANEURALNETWORKS_NO_ERROR) {
+        return n;
+    }
+
+    return m->setInputsAndOutputs(inputs, outputs);
+}
+
+int ANeuralNetworksModel_addSubModel(ANeuralNetworksModel* model,
+                                     const ANeuralNetworksModel* submodel,
+                                     ANeuralNetworksIntList* inputs,
+                                     ANeuralNetworksIntList* outputs) {
+    if (!model || !submodel) {
+        ALOGE("ANeuralNetworksModel_addSubModel passed a nullptr");
+        return ANEURALNETWORKS_UNEXPECTED_NULL;
+    }
+    ModelBuilder* m = reinterpret_cast<ModelBuilder*>(model);
+    int n = ValidateOperandList(*inputs, m->operandCount(),
+                                "ANeuralNetworksModel_addSubModel inputs");
+    if (n != ANEURALNETWORKS_NO_ERROR) {
+        return n;
+    }
+    n = ValidateOperandList(*outputs, m->operandCount(),
+                            "ANeuralNetworksModel_addSubModel outputs");
+    if (n != ANEURALNETWORKS_NO_ERROR) {
+        return n;
+    }
+    return ANEURALNETWORKS_NOT_IMPLEMENTED;
+}
+
+int ANeuralNetworksModel_setBaselineId(ANeuralNetworksModel* model, uint32_t baseLineId) {
+    if (!model) {
+        ALOGE("ANeuralNetworksModel_setBaselineId passed a nullptr");
+        return ANEURALNETWORKS_UNEXPECTED_NULL;
+    }
+    if (baseLineId >= ANEURALNETWORKS_NUMBER_BASELINE_MODELS) {
+        ALOGE("ANeuralNetworksModel_setBaselineId invalid baselineId %u", baseLineId);
+        return ANEURALNETWORKS_BAD_DATA;
+    }
+    // TODO implement
+    return ANEURALNETWORKS_NOT_IMPLEMENTED;
+}
+
+int ANeuralNetworksRequest_create(ANeuralNetworksModel* model, ANeuralNetworksRequest** request) {
+    if (!model || !request) {
+        ALOGE("ANeuralNetworksRequest_create passed a nullptr");
+        return ANEURALNETWORKS_UNEXPECTED_NULL;
+    }
+
+    ModelBuilder* m = reinterpret_cast<ModelBuilder*>(model);
+    Request* r = m->createRequest();
+    if (r == nullptr) {
+        *request = nullptr;
+        return ANEURALNETWORKS_OUT_OF_MEMORY;
+    }
+    *request = reinterpret_cast<ANeuralNetworksRequest*>(r);
+    return ANEURALNETWORKS_NO_ERROR;
+}
+
+void ANeuralNetworksRequest_free(ANeuralNetworksRequest* request) {
+    // No validation.  Free of nullptr is valid.
+    Request* r = reinterpret_cast<Request*>(request);
+    delete r;
+}
+
+int ANeuralNetworksRequest_setPreference(ANeuralNetworksRequest* request, uint32_t preference) {
+    if (!request) {
+        ALOGE("ANeuralNetworksRequest_setPreference passed a nullptr");
+        return ANEURALNETWORKS_UNEXPECTED_NULL;
+    }
+    if (preference >= ANEURALNETWORKS_NUMBER_PREFERENCES) {
+        ALOGE("ANeuralNetworksRequest_setPreference invalid preference %u", preference);
+        return ANEURALNETWORKS_BAD_DATA;
+    }
+
+    Request* r = reinterpret_cast<Request*>(request);
+    r->setPreference(preference);
+    return ANEURALNETWORKS_NO_ERROR;
+}
+
+int ANeuralNetworksRequest_setInput(ANeuralNetworksRequest* request, int32_t index,
+                                    const ANeuralNetworksOperandType* type, const void* buffer,
+                                    size_t length) {
+    if (!request || !buffer) {
+        ALOGE("ANeuralNetworksRequest_setInput passed a nullptr");
+        return ANEURALNETWORKS_UNEXPECTED_NULL;
+    }
+    if (type != nullptr) {
+        int n = ValidateOperandType(*type, "ANeuralNetworksRequest_setInput", false);
+        if (n != ANEURALNETWORKS_NO_ERROR) {
+            return n;
+        }
+    }
+    if (length > 0xFFFFFFFF) {
+        ALOGE("ANeuralNetworksRequest_setInput input exceeds max length %zu", length);
+    }
+    uint32_t l = static_cast<uint32_t>(length);
+    Request* r = reinterpret_cast<Request*>(request);
+    return r->setInput(index, type, buffer, l);
+}
+
+int ANeuralNetworksRequest_setInputFromHardwareBuffer(ANeuralNetworksRequest* request,
+                                                      int32_t index,
+                                                      const ANeuralNetworksOperandType* type,
+                                                      const AHardwareBuffer* buffer) {
+    if (!request || !type || !buffer) {
+        ALOGE("ANeuralNetworksRequest_setInputFromHardwareBuffer passed a nullptr");
+        return ANEURALNETWORKS_UNEXPECTED_NULL;
+    }
+    // TODO validate the rest
+
+    Request* r = reinterpret_cast<Request*>(request);
+    return r->setInputFromHardwareBuffer(index, type, buffer);
+}
+
+int ANeuralNetworksRequest_setOutput(ANeuralNetworksRequest* request, int32_t index,
+                                     const ANeuralNetworksOperandType* type, void* buffer,
+                                     size_t length) {
+    if (!request || !buffer) {
+        ALOGE("ANeuralNetworksRequest_setOutput passed a nullptr");
+        return ANEURALNETWORKS_UNEXPECTED_NULL;
+    }
+    if (type != nullptr) {
+        int n = ValidateOperandType(*type, "ANeuralNetworksRequest_setOutput", false);
+        if (n != ANEURALNETWORKS_NO_ERROR) {
+            return n;
+        }
+    }
+    if (length > 0xFFFFFFFF) {
+        ALOGE("ANeuralNetworksRequest_setOutput input exceeds max length %zu", length);
+    }
+    uint32_t l = static_cast<uint32_t>(length);
+
+    Request* r = reinterpret_cast<Request*>(request);
+    return r->setOutput(index, type, buffer, l);
+}
+
+int ANeuralNetworksRequest_setOutputFromHardwareBuffer(ANeuralNetworksRequest* request,
+                                                       int32_t index,
+                                                       const ANeuralNetworksOperandType* type,
+                                                       const AHardwareBuffer* buffer) {
+    if (!request || !type || !buffer) {
+        ALOGE("ANeuralNetworksRequest_setOutputFromHardwareBuffer passed a nullptr");
+        return ANEURALNETWORKS_UNEXPECTED_NULL;
+    }
+    // TODO validate the rest
+
+    Request* r = reinterpret_cast<Request*>(request);
+    return r->setOutputFromHardwareBuffer(index, type, buffer);
+}
+
+int ANeuralNetworksRequest_startCompute(ANeuralNetworksRequest* request,
+                                        ANeuralNetworksEvent** event) {
+    if (!request || !event) {
+        ALOGE("ANeuralNetworksRequest_startCompute passed a nullptr");
+        return ANEURALNETWORKS_UNEXPECTED_NULL;
+    }
+    // TODO validate the rest
+
+    Request* r = reinterpret_cast<Request*>(request);
+    Event* e = nullptr;
+    int n = r->startCompute(&e);
+    if (n != ANEURALNETWORKS_NO_ERROR) {
+        return n;
+    }
+    *event = reinterpret_cast<ANeuralNetworksEvent*>(e);
+    return ANEURALNETWORKS_NO_ERROR;
+}
+
+int ANeuralNetworksEvent_wait(ANeuralNetworksEvent* event) {
+    if (event == nullptr) {
+        ALOGE("ANeuralNetworksEvent_wait passed a nullptr");
+        return ANEURALNETWORKS_UNEXPECTED_NULL;
+    }
+
+    Event* e = reinterpret_cast<Event*>(event);
+    e->wait();
+    return ANEURALNETWORKS_NO_ERROR;
+}
+
+void ANeuralNetworksEvent_free(ANeuralNetworksEvent* event) {
+    // No validation.  Free of nullptr is valid.
+    Event* e = reinterpret_cast<Event*>(event);
+    delete e;
+}