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_SLPI_NANOAPP_LOAD_MANAGER_H_
18 #define CHRE_PLATFORM_SLPI_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 totalBinaryLen the total nanoapp binary length
56     *
57     * @return true if the preparation was successful, false otherwise
58     */
59   bool prepareForLoad(
60       uint16_t hostClientId, uint32_t transactionId, uint64_t appId,
61       uint32_t appVersion, size_t totalBinaryLen);
62 
63   /**
64    * Copies a fragment of a nanoapp binary. If the parameters do not match the
65    * expected load transaction, the transaction is marked as a failure.
66    *
67    * @param hostClientId the ID of client that originated this transaction
68    * @param transactionId the ID of the transaction
69    * @param fragmentId the ID of the fragment
70    * @param buffer the pointer to the buffer binary
71    * @param bufferLen the size of the buffer in bytes
72    *
73    * @return true if the copy was successful, false otherwise
74    */
75   bool copyNanoappFragment(
76       uint16_t hostClientId, uint32_t transactionId, uint32_t fragmentId,
77       const void *buffer, size_t bufferLen);
78 
79   /**
80    * Invalidates an ongoing load transaction. After this method is invoked,
81    * hasPendingLoadTransaction() will return false, and a new transaction must
82    * be started by invoking prepareForLoad.
83    */
markFailure()84   void markFailure() {
85     mNanoapp.reset(nullptr);
86   }
87 
88   /**
89    * @return true if a pending transaction exists, false otherwise
90    */
hasPendingLoadTransaction()91   bool hasPendingLoadTransaction() const {
92     return !mNanoapp.isNull();
93   }
94 
95   /**
96    * @return true if a pending transaction exists and the nanoapp is fully
97    *         loaded, false otherwise
98    */
isLoadComplete()99   bool isLoadComplete() const {
100     return hasPendingLoadTransaction() && mNanoapp->isLoaded();
101   }
102 
103   /**
104    * @return the currently ongoing load transaction, invalid if
105    *         hasPendingLoadTransaction() returns false
106    */
getTransactionInfo()107   FragmentedLoadInfo getTransactionInfo() const {
108     return mCurrentLoadInfo;
109   }
110 
111   /**
112    * Releases the underlying nanoapp of a currently ongoing load transaction,
113    * regardless of completion status. After this method is called, the ownership
114    * of the nanoapp is transferred to the caller. This method should only be
115    * called if hasPendingLoadTransaction() is true.
116    *
117    * @return the UniquePtr<Nanoapp> of the ongoing transaction, or null if no
118    *             transaction exists
119    */
releaseNanoapp()120   UniquePtr<Nanoapp> releaseNanoapp() {
121     return mNanoapp.release();
122   }
123 
124  private:
125   //! The currently managed fragmented load.
126   FragmentedLoadInfo mCurrentLoadInfo;
127 
128   //! The underlying nanoapp that is being loaded.
129   UniquePtr<Nanoapp> mNanoapp;
130 
131   /**
132    * Validates an incoming fragment against the next expected one. An error is
133    * logged if invalid arguments are passed.
134    *
135    * @return true if the arguments represent the next fragment, false otherwise
136    */
137   bool validateFragment(
138       uint16_t hostClientId, uint32_t transactionId, uint32_t fragmentId) const;
139 };
140 
141 }  // namespace chre
142 
143 #endif  // CHRE_PLATFORM_SLPI_NANOAPP_LOAD_MANAGER_H_
144