1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef CHRE_PLATFORM_SHARED_NANOAPP_LOAD_MANAGER_H_
18 #define CHRE_PLATFORM_SHARED_NANOAPP_LOAD_MANAGER_H_
19 
20 #include <cstddef>
21 #include <cstdint>
22 
23 #include "chre/core/nanoapp.h"
24 #include "chre/util/non_copyable.h"
25 #include "chre/util/unique_ptr.h"
26 
27 namespace chre {
28 
29 /**
30  * A struct that holds metadata of a fragmented nanoapp load transaction.
31  */
32 struct FragmentedLoadInfo {
33   //! The ID of the client that initiated this transaction.
34   uint16_t hostClientId;
35   //! The unique ID of this load transaction.
36   uint32_t transactionId;
37   //! The next fragment ID that is expected to be received for this transaction.
38   uint32_t nextFragmentId;
39 };
40 
41 /**
42  * A class which handles loading a (possibly fragmented) nanoapp binary.
43  */
44 class NanoappLoadManager : public NonCopyable {
45  public:
46   /**
47    * Prepares for a (possibly fragmented) load transaction. If an ongoing
48    * transaction exists, the transaction will be overwritten by the new
49    * incoming transaction.
50    *
51    * @param hostClientId the ID of client that originated this transaction
52    * @param transactionId the ID of the transaction
53    * @param appId the ID of the app to load
54    * @param appVersion the version of the app to load
55    * @param appFlags the flags provided by the app being loaded
56    * @param totalBinaryLen the total nanoapp binary length
57    * @param targetApiVersion the target API version of the nanoapp to load
58    *
59    * @return true if the preparation was successful, false otherwise
60    */
61   bool prepareForLoad(uint16_t hostClientId, uint32_t transactionId,
62                       uint64_t appId, uint32_t appVersion, uint32_t appFlags,
63                       size_t totalBinaryLen, uint32_t targetApiVersion);
64 
65   /**
66    * Copies a fragment of a nanoapp binary. If the parameters do not match the
67    * expected load transaction, the transaction is marked as a failure.
68    *
69    * @param hostClientId the ID of client that originated this transaction
70    * @param transactionId the ID of the transaction
71    * @param fragmentId the ID of the fragment
72    * @param buffer the pointer to the buffer binary
73    * @param bufferLen the size of the buffer in bytes
74    *
75    * @return true if the copy was successful, false otherwise
76    */
77   bool copyNanoappFragment(uint16_t hostClientId, uint32_t transactionId,
78                            uint32_t fragmentId, const void *buffer,
79                            size_t bufferLen);
80 
81   /**
82    * Invalidates an ongoing load transaction. After this method is invoked,
83    * hasPendingLoadTransaction() will return false, and a new transaction must
84    * be started by invoking prepareForLoad.
85    */
markFailure()86   void markFailure() {
87     mNanoapp.reset(nullptr);
88   }
89 
90   /**
91    * @return true if a pending transaction exists, false otherwise
92    */
hasPendingLoadTransaction()93   bool hasPendingLoadTransaction() const {
94     return !mNanoapp.isNull();
95   }
96 
97   /**
98    * @return true if a pending transaction exists and the nanoapp is fully
99    *         loaded, false otherwise
100    */
isLoadComplete()101   bool isLoadComplete() const {
102     return hasPendingLoadTransaction() && mNanoapp->isLoaded();
103   }
104 
105   /**
106    * @return the currently ongoing load transaction, invalid if
107    *         hasPendingLoadTransaction() returns false
108    */
getTransactionInfo()109   FragmentedLoadInfo getTransactionInfo() const {
110     return mCurrentLoadInfo;
111   }
112 
113   /**
114    * Releases the underlying nanoapp of a currently ongoing load transaction,
115    * regardless of completion status. After this method is called, the ownership
116    * of the nanoapp is transferred to the caller. This method should only be
117    * called if hasPendingLoadTransaction() is true.
118    *
119    * @return the UniquePtr<Nanoapp> of the ongoing transaction, or null if no
120    *             transaction exists
121    */
releaseNanoapp()122   UniquePtr<Nanoapp> releaseNanoapp() {
123     return mNanoapp.release();
124   }
125 
126  private:
127   //! The currently managed fragmented load.
128   FragmentedLoadInfo mCurrentLoadInfo;
129 
130   //! The underlying nanoapp that is being loaded.
131   UniquePtr<Nanoapp> mNanoapp;
132 
133   /**
134    * Validates an incoming fragment against the next expected one. An error is
135    * logged if invalid arguments are passed.
136    *
137    * @return true if the arguments represent the next fragment, false otherwise
138    */
139   bool validateFragment(uint16_t hostClientId, uint32_t transactionId,
140                         uint32_t fragmentId) const;
141 };
142 
143 }  // namespace chre
144 
145 #endif  // CHRE_PLATFORM_SHARED_NANOAPP_LOAD_MANAGER_H_
146