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 "composite_ptable.h"
19 #include "log/log.h"
20 #include "securec.h"
21 #include "updater/updater_const.h"
22 #include "utils.h"
23
24 namespace Updater {
25 std::string PtableManager::ptbImgTag_ = "";
26 // class PtableManager
PtableManager()27 PtableManager::PtableManager() : pPtable_(nullptr)
28 {
29 InitPtablePtr();
30 PtableManager::ptbImgTag_ = "ptable.img";
31 }
32
GetDeviceStorageType()33 PtableManager::StorageType PtableManager::GetDeviceStorageType()
34 {
35 return storage_;
36 }
37
SetDeviceStorageType()38 void PtableManager::SetDeviceStorageType()
39 {
40 if (storage_ != StorageType::STORAGE_UNKNOWN) {
41 return;
42 }
43 if (IsUfsDevice()) {
44 storage_ = StorageType::STORAGE_UFS;
45 LOG(INFO) << "is UFS DEVICE";
46 } else {
47 storage_ = StorageType::STORAGE_EMMC;
48 LOG(INFO) << "is EMMC DEVICE";
49 }
50 }
51
IsUfsDevice()52 bool PtableManager::IsUfsDevice()
53 {
54 return GetBootdevType() != 0;
55 }
56
ReloadDevicePartition(Hpackage::PkgManager * pkgManager)57 bool PtableManager::ReloadDevicePartition(Hpackage::PkgManager *pkgManager)
58 {
59 return LoadPartitionInfo(pkgManager);
60 }
61
InitPtablePtr()62 void PtableManager::InitPtablePtr()
63 {
64 if (IsCompositePtable()) {
65 LOG(INFO) << "init composite ptable";
66 return InitCompositePtable();
67 }
68
69 SetDeviceStorageType();
70 if (pPtable_ == nullptr) {
71 if (GetDeviceStorageType() == StorageType::STORAGE_UFS) {
72 pPtable_ = std::make_unique<UfsPtable>();
73 } else {
74 pPtable_ = std::make_unique<EmmcPtable>();
75 }
76 }
77 }
78
InitPtableManager()79 bool PtableManager::InitPtableManager()
80 {
81 if (pPtable_ == nullptr) {
82 LOG(ERROR) << "pPtable_ is nullptr";
83 return false;
84 }
85 if (!pPtable_->InitPtable()) {
86 LOG(ERROR) << "init ptable error";
87 return false;
88 }
89 return true;
90 }
91
GetPartitionInfoIndexByName(const std::vector<Ptable::PtnInfo> & ptnInfo,const std::string & name)92 int32_t PtableManager::GetPartitionInfoIndexByName(const std::vector<Ptable::PtnInfo> &ptnInfo,
93 const std::string &name)
94 {
95 if (ptnInfo.empty() || name.size() == 0) {
96 LOG(ERROR) << "invalid input: ptnInfo is empty or name is null";
97 return -1;
98 }
99
100 for (size_t i = 0; i < ptnInfo.size(); i++) {
101 if (ptnInfo[i].dispName == name) {
102 return i;
103 }
104 }
105 return -1;
106 }
107
IsPartitionChanged(const std::vector<Ptable::PtnInfo> & devicePtnInfo,const std::vector<Ptable::PtnInfo> & pkgPtnInfo,const std::string & partitionName)108 bool PtableManager::IsPartitionChanged(const std::vector<Ptable::PtnInfo> &devicePtnInfo,
109 const std::vector<Ptable::PtnInfo> &pkgPtnInfo, const std::string &partitionName)
110 {
111 if (pkgPtnInfo.empty()) {
112 LOG(INFO) << "No ptable in package. Ptable no changed!";
113 return false;
114 }
115 if (devicePtnInfo.empty()) {
116 LOG(WARNING) << "ptable sizes in device and package are different, partition is changed";
117 return true;
118 }
119 int32_t deviceIndex = GetPartitionInfoIndexByName(devicePtnInfo, partitionName);
120 if (deviceIndex < 0) {
121 LOG(ERROR) << "can't find the " << partitionName << " partition in device ptable!";
122 return true;
123 }
124 int32_t updateIndex = GetPartitionInfoIndexByName(pkgPtnInfo, partitionName);
125 if (updateIndex < 0) {
126 LOG(ERROR) << "can't find the " << partitionName << " partition in package ptable!";
127 return true;
128 }
129 bool ret = false;
130 if (devicePtnInfo[deviceIndex].startAddr != pkgPtnInfo[updateIndex].startAddr) {
131 LOG(INFO) << partitionName << " start address is changed:";
132 LOG(INFO) << "[" << partitionName << "]: device ptable[" << deviceIndex << "] startAddr = 0x" <<
133 devicePtnInfo[deviceIndex].startAddr << ", in package ptable[" << updateIndex << "] startAddr is 0x" <<
134 pkgPtnInfo[updateIndex].startAddr;
135 ret = true;
136 }
137 if (devicePtnInfo[deviceIndex].partitionSize != pkgPtnInfo[updateIndex].partitionSize) {
138 LOG(INFO) << partitionName << " partition size is changed:";
139 LOG(INFO) << "[" << partitionName << "]: device ptable[" << deviceIndex << "] partitionSize = 0x" <<
140 devicePtnInfo[deviceIndex].partitionSize << ", in package ptable[" << updateIndex <<
141 "] partitionSize is 0x" << pkgPtnInfo[updateIndex].partitionSize;
142 ret = true;
143 }
144 return ret;
145 }
146
IsPtableChanged(const std::vector<Ptable::PtnInfo> & devicePtnInfo,const std::vector<Ptable::PtnInfo> & pkgPtnInfo)147 bool PtableManager::IsPtableChanged(const std::vector<Ptable::PtnInfo> &devicePtnInfo,
148 const std::vector<Ptable::PtnInfo> &pkgPtnInfo)
149 {
150 if (pkgPtnInfo.empty()) {
151 LOG(INFO) << "No ptable in package. Ptable no changed!";
152 return false;
153 }
154 if (devicePtnInfo.empty() || pkgPtnInfo.size() != devicePtnInfo.size()) {
155 LOG(WARNING) << "ptable sizes in device and package are different, ptable is changed";
156 return true;
157 }
158 for (size_t i = 0; i < pkgPtnInfo.size(); i++) {
159 if (devicePtnInfo[i].dispName != pkgPtnInfo[i].dispName) {
160 LOG(WARNING) << "module_name in ptable is different:";
161 LOG(WARNING) << "ptable NAME in device is " << devicePtnInfo[i].dispName <<
162 ", in package is " << pkgPtnInfo[i].dispName;
163 return true;
164 }
165 if (devicePtnInfo[i].startAddr != pkgPtnInfo[i].startAddr) {
166 LOG(WARNING) << pkgPtnInfo[i].dispName << " start address is different:";
167 LOG(WARNING) << "Device ptable [" << devicePtnInfo[i].dispName << "] startAddr is 0x" <<
168 devicePtnInfo[i].startAddr;
169 LOG(WARNING) << "Package ptable [" << pkgPtnInfo[i].dispName << "] startAddr is 0x" <<
170 pkgPtnInfo[i].startAddr;
171 return true;
172 }
173 if (devicePtnInfo[i].partitionSize != pkgPtnInfo[i].partitionSize) {
174 LOG(WARNING) << pkgPtnInfo[i].dispName << " partition size is different:";
175 LOG(WARNING) << "Device ptable [" << devicePtnInfo[i].dispName << "] partitionSize is 0x" <<
176 devicePtnInfo[i].partitionSize;
177 LOG(WARNING) << "Package ptable [" << pkgPtnInfo[i].dispName << "] partitionSize is 0x" <<
178 pkgPtnInfo[i].partitionSize;
179 return true;
180 }
181 }
182 return false;
183 }
184
WritePtableToDevice()185 bool PtableManager::WritePtableToDevice()
186 {
187 if (pPtable_ == nullptr) {
188 LOG(ERROR) << "Write ptable to device failed! pPtable_ is nullptr";
189 return false;
190 }
191 if (!pPtable_->WritePartitionTable()) {
192 LOG(ERROR) << "Write ptable to device failed! Please load ptable first!";
193 return false;
194 }
195 LOG(INFO) << "Write ptable to device success!";
196 return true;
197 }
198
PrintPtableInfo()199 void PtableManager::PrintPtableInfo()
200 {
201 if (pPtable_ != nullptr) {
202 LOG(ERROR) << "print partition info:";
203 pPtable_->PrintPtableInfo();
204 return;
205 }
206
207 LOG(INFO) << "print partition info failed!";
208 return;
209 }
210
GetPartionInfoByName(const std::string & partitionName,Ptable::PtnInfo & ptnInfo,int32_t & index)211 bool PtableManager::GetPartionInfoByName(const std::string &partitionName, Ptable::PtnInfo &ptnInfo, int32_t &index)
212 {
213 if (pPtable_ == nullptr) {
214 LOG(ERROR) << "GetPartionInfoByName failed! pPtable_ is nullptr";
215 return false;
216 }
217 std::string standardPtnName = partitionName;
218 standardPtnName.erase(std::remove(standardPtnName.begin(), standardPtnName.end(), '/'), standardPtnName.end());
219 std::string::size_type position = standardPtnName.find("_es");
220 if (position != standardPtnName.npos) {
221 standardPtnName = standardPtnName.substr(0, position);
222 }
223 if (pPtable_->GetPartionInfoByName(standardPtnName, ptnInfo, index)) {
224 return true;
225 }
226 LOG(ERROR) << "GetPartionInfoByName failed! Not found " << standardPtnName;
227 return false;
228 }
229
GetPartionInfoByName(const std::string & partitionName,Ptable::PtnInfo & ptnInfo)230 bool PtableManager::GetPartionInfoByName(const std::string &partitionName, Ptable::PtnInfo &ptnInfo)
231 {
232 int32_t index = -1;
233 return GetPartionInfoByName(partitionName, ptnInfo, index);
234 }
235
RegisterPtable(uint32_t bitIndex,PtableConstructor constructor)236 void PtableManager::RegisterPtable(uint32_t bitIndex, PtableConstructor constructor)
237 {
238 if (constructor == nullptr) {
239 LOG(ERROR) << "invalid input";
240 return;
241 }
242 ptableMap_.emplace(bitIndex, constructor);
243 }
244
IsCompositePtable()245 bool PtableManager::IsCompositePtable()
246 {
247 uint32_t type = GetBootdevType();
248 uint32_t cnt = 0;
249 while (type != 0) {
250 type &= (type - 1);
251 cnt++;
252 }
253 return cnt > 1;
254 }
255
GetBootdevType()256 uint32_t PtableManager::GetBootdevType()
257 {
258 uint32_t ret = 0;
259 std::ifstream fin(BOOTDEV_TYPE, std::ios::in);
260 if (!fin.is_open()) {
261 LOG(ERROR) << "open bootdev failed";
262 return ret;
263 }
264 fin >> ret;
265 fin.close();
266 LOG(INFO) << "bootdev type is " << ret;
267 return ret;
268 }
269
InitCompositePtable()270 void PtableManager::InitCompositePtable()
271 {
272 pPtable_ = std::make_unique<CompositePtable>();
273 if (pPtable_ == nullptr) {
274 LOG(ERROR) << "make composite ptable failed";
275 return;
276 }
277 std::bitset<32> type {GetBootdevType()}; // uint32_t type init as 32 bit
278 for (uint32_t i = type.size(); i > 0; i--) {
279 if (type[i - 1] == 0) {
280 continue;
281 }
282 if (auto iter = ptableMap_.find(i - 1); iter != ptableMap_.end()) {
283 LOG(INFO) << "add child ptable: " << (i - 1);
284 pPtable_->AddChildPtable(iter->second());
285 }
286 }
287 }
288
LoadPartitionInfoWithFile()289 bool PtableManager::LoadPartitionInfoWithFile()
290 {
291 if (!Utils::IsFileExist(PTABLE_TEMP_PATH)) {
292 LOG(ERROR) << "ptable file is not exist, no need write";
293 return false;
294 }
295
296 if (!InitPtableManager()) {
297 LOG(ERROR) << "init ptable manager error";
298 return false;
299 }
300 uint32_t imgBufSize = pPtable_->GetDefaultImageSize();
301 if (imgBufSize <= 0) {
302 LOG(ERROR) << "Invalid imgBufSize";
303 return false;
304 }
305 uint8_t *imageBuf = new(std::nothrow) uint8_t[imgBufSize]();
306 if (imageBuf == nullptr) {
307 LOG(ERROR) << "new ptable_buffer error";
308 return false;
309 }
310
311 if (!pPtable_->ReadPartitionFileToBuffer(imageBuf, imgBufSize)) {
312 LOG(ERROR) << "ptable file read fail";
313 delete [] imageBuf;
314 imageBuf = nullptr;
315 return false;
316 }
317
318 if (!pPtable_->ParsePartitionFromBuffer(imageBuf, imgBufSize)) {
319 LOG(ERROR) << "parse ptable buff fail";
320 delete [] imageBuf;
321 imageBuf = nullptr;
322 return false;
323 }
324
325 delete [] imageBuf;
326 imageBuf = nullptr;
327 LOG(INFO) << "print package partition info:";
328 pPtable_->PrintPtableInfo();
329 return true;
330 }
331
WritePtableWithFile()332 bool PtableManager::WritePtableWithFile()
333 {
334 if (pPtable_ == nullptr) {
335 LOG(ERROR) << "pPtable_ is nullptr";
336 pPtable_->DeletePartitionTmpFile();
337 return true;
338 }
339
340 if (!LoadPartitionInfoWithFile()) {
341 LOG(ERROR) << "load partition info with file fail";
342 pPtable_->DeletePartitionTmpFile();
343 return true;
344 }
345
346 #ifndef UPDATER_UT
347 if (!pPtable_->WritePartitionTable()) {
348 LOG(ERROR) << "Write ptable to device failed! Please load ptable first!";
349 pPtable_->DeletePartitionTmpFile();
350 return false;
351 }
352 #endif
353 pPtable_->DeletePartitionTmpFile();
354 LOG(INFO) << "write patble with file success";
355 return true;
356 }
357
358 // class PackagePtable
PackagePtable()359 PackagePtable::PackagePtable() : PtableManager() {}
360
LoadPartitionInfo(Hpackage::PkgManager * pkgManager)361 bool PackagePtable::LoadPartitionInfo([[maybe_unused]] Hpackage::PkgManager *pkgManager)
362 {
363 if (pkgManager == nullptr) {
364 LOG(ERROR) << "pkgManager is nullptr";
365 return false;
366 }
367 if (!InitPtableManager()) {
368 LOG(ERROR) << "init ptable manager error";
369 return false;
370 }
371
372 uint32_t imgBufSize = pPtable_->GetDefaultImageSize();
373 if (imgBufSize <= 0) {
374 LOG(ERROR) << "Invalid imgBufSize";
375 return false;
376 }
377 uint8_t *imageBuf = new(std::nothrow) uint8_t[imgBufSize]();
378
379 if (imageBuf == nullptr) {
380 LOG(ERROR) << "new ptable_buffer error";
381 return false;
382 }
383 if (!GetPtableBufferFromPkg(pkgManager, imageBuf, imgBufSize)) {
384 LOG(ERROR) << "get ptable buffer failed";
385 delete [] imageBuf;
386 return false;
387 }
388
389 if (!pPtable_->ParsePartitionFromBuffer(imageBuf, imgBufSize)) {
390 LOG(ERROR) << "get ptable from ptable image buffer failed";
391 delete [] imageBuf;
392 return false;
393 }
394 delete [] imageBuf;
395 LOG(INFO) << "print package partition info:";
396 pPtable_->PrintPtableInfo();
397 return true;
398 }
399
GetPtableBufferFromPkg(Hpackage::PkgManager * pkgManager,uint8_t * & imageBuf,uint32_t size)400 bool PackagePtable::GetPtableBufferFromPkg(Hpackage::PkgManager *pkgManager, uint8_t *&imageBuf, uint32_t size)
401 {
402 if (pkgManager == nullptr) {
403 LOG(ERROR) << "pkgManager is nullptr";
404 return false;
405 }
406
407 const Hpackage::FileInfo *info = pkgManager->GetFileInfo(PtableManager::ptbImgTag_);
408 if (info == nullptr) {
409 info = pkgManager->GetFileInfo("/ptable");
410 if (info == nullptr) {
411 LOG(ERROR) << "Can not get file info " << PtableManager::ptbImgTag_;
412 return false;
413 }
414 }
415
416 Hpackage::PkgManager::StreamPtr outStream = nullptr;
417 (void)pkgManager->CreatePkgStream(outStream, PtableManager::ptbImgTag_, info->unpackedSize,
418 Hpackage::PkgStream::PkgStreamType_MemoryMap);
419 if (outStream == nullptr) {
420 LOG(ERROR) << "Error to create output stream";
421 return false;
422 }
423
424 if (pkgManager->ExtractFile(PtableManager::ptbImgTag_, outStream) != Hpackage::PKG_SUCCESS) {
425 LOG(ERROR) << "Error to extract ptable";
426 pkgManager->ClosePkgStream(outStream);
427 return false;
428 }
429
430 size_t bufSize = 0;
431 uint8_t* buffer = nullptr;
432 outStream->GetBuffer(buffer, bufSize);
433 if (memcpy_s(imageBuf, size, buffer, std::min(static_cast<size_t>(size), bufSize))) {
434 LOG(ERROR) << "memcpy to imageBuf fail";
435 pkgManager->ClosePkgStream(outStream);
436 return false;
437 }
438 pkgManager->ClosePkgStream(outStream);
439 return true;
440 }
441
442 // class DevicePtable
DevicePtable()443 DevicePtable::DevicePtable() : PtableManager() {}
444
LoadPartitionInfo(Hpackage::PkgManager * pkgManager)445 bool DevicePtable::LoadPartitionInfo([[maybe_unused]] Hpackage::PkgManager *pkgManager)
446 {
447 (void)pkgManager;
448 if (!InitPtableManager()) {
449 LOG(ERROR) << "init ptable manager error";
450 return false;
451 }
452 if (!pPtable_->LoadPtableFromDevice()) {
453 LOG(ERROR) << "load device parititon to ram fail";
454 return false;
455 }
456
457 LOG(INFO) << "print device partition info:";
458 pPtable_->PrintPtableInfo();
459 return true;
460 }
461
ComparePartition(PtableManager & newPtbManager,const std::string partitionName)462 bool DevicePtable::ComparePartition(PtableManager &newPtbManager, const std::string partitionName)
463 {
464 if (pPtable_ == nullptr || newPtbManager.pPtable_ == nullptr) {
465 LOG(ERROR) << "input pPtable point is nullptr, compare failed!";
466 return false;
467 }
468 if (IsPartitionChanged(pPtable_->GetPtablePartitionInfo(),
469 newPtbManager.pPtable_->GetPtablePartitionInfo(), partitionName)) {
470 LOG(INFO) << partitionName << " are different";
471 return true;
472 }
473 LOG(INFO) << partitionName << " are the same";
474 return false;
475 }
476
ComparePtable(PtableManager & newPtbManager)477 bool DevicePtable::ComparePtable(PtableManager &newPtbManager)
478 {
479 if (pPtable_ == nullptr || newPtbManager.pPtable_ == nullptr) {
480 LOG(ERROR) << "input pPtable point is nullptr, compare failed!";
481 return false;
482 }
483 if (IsPtableChanged(pPtable_->GetPtablePartitionInfo(),
484 newPtbManager.pPtable_->GetPtablePartitionInfo())) {
485 LOG(INFO) << "two ptables are different";
486 return true;
487 }
488 LOG(INFO) << "two ptables are the same";
489 return false;
490 }
491 } // namespace Updater
492