Impose more discipline on uses of ModelArgumentInfo

Change ModelArgumentInfo from a struct to a class.  Fields are no
longer public, and initialization uses a factory method (e.g.,
createFromPointer) rather than a setter (e.g.,
setFromPointer). Accessor methods are guarded by a check against the
(already existing) state (POINTER, MEMORY, or both).

Calling ANeuralNetworksExecution_setInput*() or
ANeuralNetworksExecution_setOutput*() multiple times on the same
operand of the same execution is now an error.

Bug: 147850002
Test: NeuralNetworksTest_static
Change-Id: Idebe6b4df79bff5c62e56860e42463d610d91085
diff --git a/nn/runtime/ModelArgumentInfo.h b/nn/runtime/ModelArgumentInfo.h
index 61dfc1e..22dd34c 100644
--- a/nn/runtime/ModelArgumentInfo.h
+++ b/nn/runtime/ModelArgumentInfo.h
@@ -17,36 +17,93 @@
 #ifndef ANDROID_FRAMEWORKS_ML_NN_RUNTIME_MODEL_ARGUMENT_INFO_H
 #define ANDROID_FRAMEWORKS_ML_NN_RUNTIME_MODEL_ARGUMENT_INFO_H
 
+#include <utility>
 #include <vector>
 
 #include "HalInterfaces.h"
 #include "NeuralNetworks.h"
+#include "Utils.h"
 
 namespace android {
 namespace nn {
 
 // TODO move length out of DataLocation
-struct ModelArgumentInfo {
+//
+// NOTE: The primary usage pattern is that a ModelArgumentInfo instance
+//       is not modified once it is created (unless it is reassigned to).
+//       There are a small number of use cases where it NEEDS to be modified,
+//       and we have a limited number of methods that support this.
+class ModelArgumentInfo {
+   public:
+    ModelArgumentInfo() {}
+
+    static std::pair<int, ModelArgumentInfo> createFromPointer(
+            const hal::Operand& operand, const ANeuralNetworksOperandType* type,
+            void* data /* nullptr means HAS_NO_VALUE */, uint32_t length);
+    static std::pair<int, ModelArgumentInfo> createFromMemory(
+            const hal::Operand& operand, const ANeuralNetworksOperandType* type, uint32_t poolIndex,
+            uint32_t offset, uint32_t length);
+
+    enum State { POINTER, MEMORY, HAS_NO_VALUE, UNSPECIFIED };
+
+    State state() const { return mState; }
+
+    bool unspecified() const { return mState == UNSPECIFIED; }
+
+    void* buffer() const {
+        CHECK_EQ(mState, POINTER);
+        return mBuffer;
+    }
+
+    const std::vector<uint32_t>& dimensions() const {
+        CHECK(mState == POINTER || mState == MEMORY);
+        return mDimensions;
+    }
+    std::vector<uint32_t>& dimensions() {
+        CHECK(mState == POINTER || mState == MEMORY);
+        return mDimensions;
+    }
+
+    bool isSufficient() const {
+        CHECK(mState == POINTER || mState == MEMORY);
+        return mIsSufficient;
+    }
+    bool& isSufficient() {
+        CHECK(mState == POINTER || mState == MEMORY);
+        return mIsSufficient;
+    }
+
+    uint32_t length() const {
+        CHECK(mState == POINTER || mState == MEMORY);
+        return mLocationAndLength.length;
+    }
+
+    const hal::DataLocation& locationAndLength() const {
+        CHECK_EQ(mState, MEMORY);
+        return mLocationAndLength;
+    }
+    hal::DataLocation& locationAndLength() {
+        CHECK_EQ(mState, MEMORY);
+        return mLocationAndLength;
+    }
+
+   private:
+    int updateDimensionInfo(const hal::Operand& operand, const ANeuralNetworksOperandType* newType);
+
     // Whether the argument was specified as being in a Memory, as a pointer,
     // has no value, or has not been specified.
     // If POINTER then:
-    //   locationAndLength.length is valid.
-    //   dimensions is valid.
-    //   buffer is valid
+    //   mLocationAndLength.length is valid.
+    //   mDimensions is valid.
+    //   mBuffer is valid.
     // If MEMORY then:
-    //   locationAndLength.{poolIndex, offset, length} is valid.
-    //   dimensions is valid.
-    enum { POINTER, MEMORY, HAS_NO_VALUE, UNSPECIFIED } state = UNSPECIFIED;
-    hal::DataLocation locationAndLength;
-    std::vector<uint32_t> dimensions;
-    void* buffer;
-    bool isSufficient = true;
-
-    int setFromPointer(const hal::Operand& operand, const ANeuralNetworksOperandType* type,
-                       void* buffer, uint32_t length);
-    int setFromMemory(const hal::Operand& operand, const ANeuralNetworksOperandType* type,
-                      uint32_t poolIndex, uint32_t offset, uint32_t length);
-    int updateDimensionInfo(const hal::Operand& operand, const ANeuralNetworksOperandType* newType);
+    //   mLocationAndLength.{poolIndex, offset, length} is valid.
+    //   mDimensions is valid.
+    State mState = UNSPECIFIED;            // fixed at creation
+    void* mBuffer = nullptr;               // fixed at creation
+    hal::DataLocation mLocationAndLength;  // can be updated after creation
+    std::vector<uint32_t> mDimensions;     // can be updated after creation
+    bool mIsSufficient = true;             // can be updated after creation
 };
 
 // Convert ModelArgumentInfo to HIDL RequestArgument. For pointer arguments, use the location