1 /*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "ptable_manager.h"
17
18 #include "log/log.h"
19 #include "securec.h"
20
21 namespace Updater {
22 // class PtableManager
PtableManager()23 PtableManager::PtableManager() : pPtable_(nullptr)
24 {
25 InitPtablePtr();
26 }
27
GetDeviceStorageType() const28 PtableManager::StorageType PtableManager::GetDeviceStorageType() const
29 {
30 return storage_;
31 }
32
SetDeviceStorageType()33 void PtableManager::SetDeviceStorageType()
34 {
35 if (storage_ != StorageType::STORAGE_UNKNOWN) {
36 return;
37 }
38 if (IsUfsDevice()) {
39 storage_ = StorageType::STORAGE_UFS;
40 LOG(INFO) << "is UFS DEVICE";
41 } else {
42 storage_ = StorageType::STORAGE_EMMC;
43 LOG(INFO) << "is EMMC DEVICE";
44 }
45 }
46
IsUfsDevice()47 bool PtableManager::IsUfsDevice()
48 {
49 return true;
50 }
51
ReloadDevicePartition(Hpackage::PkgManager * pkgManager)52 void PtableManager::ReloadDevicePartition(Hpackage::PkgManager *pkgManager)
53 {
54 return LoadPartitionInfo(pkgManager);
55 }
56
InitPtablePtr()57 void PtableManager::InitPtablePtr()
58 {
59 SetDeviceStorageType();
60 if (pPtable_ == nullptr) {
61 if (GetDeviceStorageType() == StorageType::STORAGE_UFS) {
62 pPtable_ = std::make_unique<UfsPtable>();
63 } else {
64 pPtable_ = nullptr;
65 }
66 }
67 }
68
InitPtableManager()69 bool PtableManager::InitPtableManager()
70 {
71 if (pPtable_ == nullptr) {
72 LOG(ERROR) << "pPtable_ is nullptr";
73 return false;
74 }
75 if (!pPtable_->InitPtable()) {
76 LOG(ERROR) << "init ptable error";
77 return false;
78 }
79 return true;
80 }
81
GetPartitionInfoIndexByName(const std::vector<Ptable::PtnInfo> & ptnInfo,const std::string & name)82 int32_t PtableManager::GetPartitionInfoIndexByName(const std::vector<Ptable::PtnInfo> &ptnInfo,
83 const std::string &name)
84 {
85 if (ptnInfo.empty() || name.size() == 0) {
86 LOG(ERROR) << "invalid input: ptnInfo is empty or name is null";
87 return -1;
88 }
89
90 for (size_t i = 0; i < ptnInfo.size(); i++) {
91 if (ptnInfo[i].dispName == name) {
92 return i;
93 }
94 }
95 return -1;
96 }
97
IsPartitionChanged(const std::vector<Ptable::PtnInfo> & devicePtnInfo,const std::vector<Ptable::PtnInfo> & pkgPtnInfo,const std::string & partitionName)98 bool PtableManager::IsPartitionChanged(const std::vector<Ptable::PtnInfo> &devicePtnInfo,
99 const std::vector<Ptable::PtnInfo> &pkgPtnInfo, const std::string &partitionName)
100 {
101 if (pkgPtnInfo.empty()) {
102 LOG(INFO) << "No ptable in package. Ptable no changed!";
103 return false;
104 }
105 if (devicePtnInfo.empty()) {
106 LOG(WARNING) << "ptable sizes in device and package are different, partition is changed";
107 return true;
108 }
109 int32_t deviceIndex = GetPartitionInfoIndexByName(devicePtnInfo, partitionName);
110 if (deviceIndex < 0) {
111 LOG(ERROR) << "can't find the " << partitionName << " partition in device ptable!";
112 return true;
113 }
114 int32_t updateIndex = GetPartitionInfoIndexByName(pkgPtnInfo, partitionName);
115 if (updateIndex < 0) {
116 LOG(ERROR) << "can't find the " << partitionName << " partition in package ptable!";
117 return true;
118 }
119 bool ret = false;
120 if (devicePtnInfo[deviceIndex].startAddr != pkgPtnInfo[updateIndex].startAddr) {
121 LOG(INFO) << partitionName << " start address is changed:";
122 LOG(INFO) << "[" << partitionName << "]: device ptable[" << deviceIndex << "] startAddr = 0x" <<
123 devicePtnInfo[deviceIndex].startAddr << ", in package ptable[" << updateIndex << "] startAddr is 0x" <<
124 pkgPtnInfo[updateIndex].startAddr;
125 ret = true;
126 }
127 if (devicePtnInfo[deviceIndex].partitionSize != pkgPtnInfo[updateIndex].partitionSize) {
128 LOG(INFO) << partitionName << " partition size is changed:";
129 LOG(INFO) << "[" << partitionName << "]: device ptable[" << deviceIndex << "] partitionSize = 0x" <<
130 devicePtnInfo[deviceIndex].partitionSize << ", in package ptable[" << updateIndex <<
131 "] partitionSize is 0x" << pkgPtnInfo[updateIndex].partitionSize;
132 ret = true;
133 }
134 return ret;
135 }
136
IsPtableChanged(const std::vector<Ptable::PtnInfo> & devicePtnInfo,const std::vector<Ptable::PtnInfo> & pkgPtnInfo)137 bool PtableManager::IsPtableChanged(const std::vector<Ptable::PtnInfo> &devicePtnInfo,
138 const std::vector<Ptable::PtnInfo> &pkgPtnInfo)
139 {
140 if (pkgPtnInfo.empty()) {
141 LOG(INFO) << "No ptable in package. Ptable no changed!";
142 return false;
143 }
144 if (devicePtnInfo.empty() || pkgPtnInfo.size() != devicePtnInfo.size()) {
145 LOG(WARNING) << "ptable sizes in device and package are different, ptable is changed";
146 return true;
147 }
148 for (size_t i = 0; i < pkgPtnInfo.size(); i++) {
149 if (devicePtnInfo[i].dispName != pkgPtnInfo[i].dispName) {
150 LOG(WARNING) << "module_name in ptable is different:";
151 LOG(WARNING) << "ptable NAME in device is " << devicePtnInfo[i].dispName <<
152 ", in package is " << pkgPtnInfo[i].dispName;
153 return true;
154 }
155 if (devicePtnInfo[i].startAddr != pkgPtnInfo[i].startAddr) {
156 LOG(WARNING) << pkgPtnInfo[i].dispName << " start address is different:";
157 LOG(WARNING) << "Device ptable [" << devicePtnInfo[i].dispName << "] startAddr is 0x" <<
158 devicePtnInfo[i].startAddr;
159 LOG(WARNING) << "Package ptable [" << pkgPtnInfo[i].dispName << "] startAddr is 0x" <<
160 pkgPtnInfo[i].startAddr;
161 return true;
162 }
163 if (devicePtnInfo[i].partitionSize != pkgPtnInfo[i].partitionSize) {
164 LOG(WARNING) << pkgPtnInfo[i].dispName << " partition size is different:";
165 LOG(WARNING) << "Device ptable [" << devicePtnInfo[i].dispName << "] partitionSize is 0x" <<
166 devicePtnInfo[i].partitionSize;
167 LOG(WARNING) << "Package ptable [" << pkgPtnInfo[i].dispName << "] partitionSize is 0x" <<
168 pkgPtnInfo[i].partitionSize;
169 return true;
170 }
171 }
172 return false;
173 }
174
WritePtableToDevice()175 bool PtableManager::WritePtableToDevice()
176 {
177 if (pPtable_ == nullptr) {
178 LOG(ERROR) << "Write ptable to device failed! pPtable_ is nullptr";
179 return false;
180 }
181 if (!pPtable_->WritePartitionTable()) {
182 LOG(ERROR) << "Write ptable to device failed! Please load ptable first!";
183 return false;
184 }
185 LOG(INFO) << "Write ptable to device success!";
186 return true;
187 }
188
PrintPtableInfo()189 void PtableManager::PrintPtableInfo()
190 {
191 if (pPtable_ != nullptr) {
192 LOG(ERROR) << "print partition info:";
193 pPtable_->PrintPtableInfo();
194 return;
195 }
196
197 LOG(INFO) << "print partition info failed!";
198 return;
199 }
200
GetPartionInfoByName(const std::string & partitionName,Ptable::PtnInfo & ptnInfo,int32_t & index)201 bool PtableManager::GetPartionInfoByName(const std::string &partitionName, Ptable::PtnInfo &ptnInfo, int32_t &index)
202 {
203 if (pPtable_ == nullptr) {
204 LOG(ERROR) << "GetPartionInfoByName failed! pPtable_ is nullptr";
205 return false;
206 }
207 std::string standardPtnName = partitionName;
208 standardPtnName.erase(std::remove(standardPtnName.begin(), standardPtnName.end(), '/'), standardPtnName.end());
209 if (pPtable_->GetPartionInfoByName(standardPtnName, ptnInfo, index)) {
210 LOG(INFO) << "GetPartionInfoByName success!";
211 return true;
212 }
213 LOG(ERROR) << "GetPartionInfoByName failed! Not found " << standardPtnName;
214 return false;
215 }
216
GetPartionInfoByName(const std::string & partitionName,Ptable::PtnInfo & ptnInfo)217 bool PtableManager::GetPartionInfoByName(const std::string &partitionName, Ptable::PtnInfo &ptnInfo)
218 {
219 int32_t index = -1;
220 return GetPartionInfoByName(partitionName, ptnInfo, index);
221 }
222
223 // class PackagePtable
PackagePtable()224 PackagePtable::PackagePtable() : PtableManager() {}
225
LoadPartitionInfo(Hpackage::PkgManager * pkgManager)226 void PackagePtable::LoadPartitionInfo([[maybe_unused]] Hpackage::PkgManager *pkgManager)
227 {
228 if (pkgManager == nullptr) {
229 LOG(ERROR) << "pkgManager is nullptr";
230 return;
231 }
232 if (!InitPtableManager()) {
233 LOG(ERROR) << "init ptable manager error";
234 return;
235 }
236
237 uint32_t imgBufSize = pPtable_->GetDefaultImageSize();
238 if (imgBufSize <= 0) {
239 LOG(ERROR) << "Invalid imgBufSize";
240 return;
241 }
242 uint8_t *imageBuf = new(std::nothrow) uint8_t[imgBufSize]();
243
244 if (imageBuf == nullptr) {
245 LOG(ERROR) << "new ptable_buffer error";
246 return;
247 }
248 if (!GetPtableBufferFromPkg(pkgManager, imageBuf, imgBufSize)) {
249 LOG(ERROR) << "get ptable buffer failed";
250 delete [] imageBuf;
251 return;
252 }
253
254 if (!pPtable_->ParsePartitionFromBuffer(imageBuf, imgBufSize)) {
255 LOG(ERROR) << "get ptable from ptable image buffer failed";
256 delete [] imageBuf;
257 return;
258 }
259 delete [] imageBuf;
260 LOG(INFO) << "print package partition info:";
261 pPtable_->PrintPtableInfo();
262 return;
263 }
264
GetPtableBufferFromPkg(Hpackage::PkgManager * pkgManager,uint8_t * & imageBuf,uint32_t size)265 bool PackagePtable::GetPtableBufferFromPkg(Hpackage::PkgManager *pkgManager, uint8_t *&imageBuf, uint32_t size)
266 {
267 if (pkgManager == nullptr) {
268 LOG(ERROR) << "pkgManager is nullptr";
269 return false;
270 }
271
272 std::string ptableName = "/ptable";
273 const Hpackage::FileInfo *info = pkgManager->GetFileInfo(ptableName);
274 if (info == nullptr) {
275 LOG(ERROR) << "Can not get file info " << ptableName;
276 return false;
277 }
278 Hpackage::PkgManager::StreamPtr outStream = nullptr;
279 (void)pkgManager->CreatePkgStream(outStream, ptableName, info->unpackedSize,
280 Hpackage::PkgStream::PkgStreamType_MemoryMap);
281 if (outStream == nullptr) {
282 LOG(ERROR) << "Error to create output stream";
283 return false;
284 }
285
286 if (pkgManager->ExtractFile(ptableName, outStream) != Hpackage::PKG_SUCCESS) {
287 LOG(ERROR) << "Error to extract ptable";
288 pkgManager->ClosePkgStream(outStream);
289 return false;
290 }
291
292 size_t bufSize = 0;
293 uint8_t* buffer = nullptr;
294 outStream->GetBuffer(buffer, bufSize);
295 if (memcpy_s(imageBuf, size, buffer, std::min(static_cast<size_t>(size), bufSize))) {
296 LOG(ERROR) << "memcpy to imageBuf fail";
297 pkgManager->ClosePkgStream(outStream);
298 return false;
299 }
300 pkgManager->ClosePkgStream(outStream);
301 return true;
302 }
303
304 // class DevicePtable
DevicePtable()305 DevicePtable::DevicePtable() : PtableManager() {}
306
LoadPartitionInfo(Hpackage::PkgManager * pkgManager)307 void DevicePtable::LoadPartitionInfo([[maybe_unused]] Hpackage::PkgManager *pkgManager)
308 {
309 (void)pkgManager;
310 if (!InitPtableManager()) {
311 LOG(ERROR) << "init ptable manager error";
312 return;
313 }
314 if (!pPtable_->LoadPtableFromDevice()) {
315 LOG(ERROR) << "load device parititon to ram fail";
316 return;
317 }
318
319 LOG(INFO) << "print device partition info:";
320 pPtable_->PrintPtableInfo();
321 return;
322 }
323
ComparePartition(PtableManager & newPtbManager,const std::string partitionName)324 bool DevicePtable::ComparePartition(PtableManager &newPtbManager, const std::string partitionName)
325 {
326 if (pPtable_ == nullptr || newPtbManager.pPtable_ == nullptr) {
327 LOG(ERROR) << "input pPtable point is nullptr, compare failed!";
328 return false;
329 }
330 if (IsPartitionChanged(pPtable_->GetPtablePartitionInfo(),
331 newPtbManager.pPtable_->GetPtablePartitionInfo(), partitionName)) {
332 LOG(INFO) << partitionName << " are different";
333 return true;
334 }
335 LOG(INFO) << partitionName << " are the same";
336 return false;
337 }
338
ComparePtable(PtableManager & newPtbManager)339 bool DevicePtable::ComparePtable(PtableManager &newPtbManager)
340 {
341 if (pPtable_ == nullptr || newPtbManager.pPtable_ == nullptr) {
342 LOG(ERROR) << "input pPtable point is nullptr, compare failed!";
343 return false;
344 }
345 if (IsPtableChanged(pPtable_->GetPtablePartitionInfo(),
346 newPtbManager.pPtable_->GetPtablePartitionInfo())) {
347 LOG(INFO) << "two ptables are different";
348 return true;
349 }
350 LOG(INFO) << "two ptables are the same";
351 return false;
352 }
353 } // namespace Updater
354