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 const char *ptablePath = Utils::IsUpdaterMode() ? PTABLE_TEMP_PATH : PTABLE_NORMAL_PATH;
292 if (!Utils::IsFileExist(ptablePath)) {
293 LOG(ERROR) << "ptable file is not exist, no need write";
294 return false;
295 }
296
297 if (!InitPtableManager()) {
298 LOG(ERROR) << "init ptable manager error";
299 return false;
300 }
301 uint32_t imgBufSize = pPtable_->GetDefaultImageSize();
302 if (imgBufSize <= 0) {
303 LOG(ERROR) << "Invalid imgBufSize";
304 return false;
305 }
306 uint8_t *imageBuf = new(std::nothrow) uint8_t[imgBufSize]();
307 if (imageBuf == nullptr) {
308 LOG(ERROR) << "new ptable_buffer error";
309 return false;
310 }
311
312 if (!pPtable_->ReadPartitionFileToBuffer(imageBuf, imgBufSize)) {
313 LOG(ERROR) << "ptable file read fail";
314 delete [] imageBuf;
315 imageBuf = nullptr;
316 return false;
317 }
318
319 if (!pPtable_->ParsePartitionFromBuffer(imageBuf, imgBufSize)) {
320 LOG(ERROR) << "parse ptable buff fail";
321 delete [] imageBuf;
322 imageBuf = nullptr;
323 return false;
324 }
325
326 delete [] imageBuf;
327 imageBuf = nullptr;
328 LOG(INFO) << "print package partition info:";
329 pPtable_->PrintPtableInfo();
330 return true;
331 }
332
WritePtableWithFile()333 bool PtableManager::WritePtableWithFile()
334 {
335 if (pPtable_ == nullptr) {
336 LOG(ERROR) << "pPtable_ is nullptr";
337 pPtable_->DeletePartitionTmpFile();
338 return true;
339 }
340
341 if (!LoadPartitionInfoWithFile()) {
342 LOG(ERROR) << "load partition info with file fail";
343 pPtable_->DeletePartitionTmpFile();
344 return true;
345 }
346
347 #ifndef UPDATER_UT
348 if (!pPtable_->WritePartitionTable()) {
349 LOG(ERROR) << "Write ptable to device failed! Please load ptable first!";
350 pPtable_->DeletePartitionTmpFile();
351 return false;
352 }
353 #endif
354 pPtable_->DeletePartitionTmpFile();
355 LOG(INFO) << "write patble with file success";
356 return true;
357 }
358
359 // class PackagePtable
PackagePtable()360 PackagePtable::PackagePtable() : PtableManager() {}
361
LoadPartitionInfo(Hpackage::PkgManager * pkgManager)362 bool PackagePtable::LoadPartitionInfo([[maybe_unused]] Hpackage::PkgManager *pkgManager)
363 {
364 if (pkgManager == nullptr) {
365 LOG(ERROR) << "pkgManager is nullptr";
366 return false;
367 }
368 if (!InitPtableManager()) {
369 LOG(ERROR) << "init ptable manager error";
370 return false;
371 }
372
373 uint32_t imgBufSize = pPtable_->GetDefaultImageSize();
374 if (imgBufSize <= 0) {
375 LOG(ERROR) << "Invalid imgBufSize";
376 return false;
377 }
378 uint8_t *imageBuf = new(std::nothrow) uint8_t[imgBufSize]();
379
380 if (imageBuf == nullptr) {
381 LOG(ERROR) << "new ptable_buffer error";
382 return false;
383 }
384 if (!GetPtableBufferFromPkg(pkgManager, imageBuf, imgBufSize)) {
385 LOG(ERROR) << "get ptable buffer failed";
386 delete [] imageBuf;
387 return false;
388 }
389
390 if (!pPtable_->ParsePartitionFromBuffer(imageBuf, imgBufSize)) {
391 LOG(ERROR) << "get ptable from ptable image buffer failed";
392 delete [] imageBuf;
393 return false;
394 }
395 delete [] imageBuf;
396 LOG(INFO) << "print package partition info:";
397 pPtable_->PrintPtableInfo();
398 return true;
399 }
400
GetPtableBufferFromPkg(Hpackage::PkgManager * pkgManager,uint8_t * & imageBuf,uint32_t size)401 bool PackagePtable::GetPtableBufferFromPkg(Hpackage::PkgManager *pkgManager, uint8_t *&imageBuf, uint32_t size)
402 {
403 if (pkgManager == nullptr) {
404 LOG(ERROR) << "pkgManager is nullptr";
405 return false;
406 }
407
408 const Hpackage::FileInfo *info = pkgManager->GetFileInfo(PtableManager::ptbImgTag_);
409 if (info == nullptr) {
410 info = pkgManager->GetFileInfo("/ptable");
411 if (info == nullptr) {
412 LOG(ERROR) << "Can not get file info " << PtableManager::ptbImgTag_;
413 return false;
414 }
415 }
416
417 Hpackage::PkgManager::StreamPtr outStream = nullptr;
418 (void)pkgManager->CreatePkgStream(outStream, PtableManager::ptbImgTag_, info->unpackedSize,
419 Hpackage::PkgStream::PkgStreamType_MemoryMap);
420 if (outStream == nullptr) {
421 LOG(ERROR) << "Error to create output stream";
422 return false;
423 }
424
425 if (pkgManager->ExtractFile(PtableManager::ptbImgTag_, outStream) != Hpackage::PKG_SUCCESS) {
426 LOG(ERROR) << "Error to extract ptable";
427 pkgManager->ClosePkgStream(outStream);
428 return false;
429 }
430
431 size_t bufSize = 0;
432 uint8_t* buffer = nullptr;
433 outStream->GetBuffer(buffer, bufSize);
434 if (memcpy_s(imageBuf, size, buffer, std::min(static_cast<size_t>(size), bufSize))) {
435 LOG(ERROR) << "memcpy to imageBuf fail";
436 pkgManager->ClosePkgStream(outStream);
437 return false;
438 }
439 pkgManager->ClosePkgStream(outStream);
440 return true;
441 }
442
443 // class DevicePtable
DevicePtable()444 DevicePtable::DevicePtable() : PtableManager() {}
445
LoadPartitionInfo(Hpackage::PkgManager * pkgManager)446 bool DevicePtable::LoadPartitionInfo([[maybe_unused]] Hpackage::PkgManager *pkgManager)
447 {
448 (void)pkgManager;
449 if (!InitPtableManager()) {
450 LOG(ERROR) << "init ptable manager error";
451 return false;
452 }
453 if (!pPtable_->LoadPtableFromDevice()) {
454 LOG(ERROR) << "load device parititon to ram fail";
455 return false;
456 }
457
458 LOG(INFO) << "print device partition info:";
459 pPtable_->PrintPtableInfo();
460 return true;
461 }
462
ComparePartition(PtableManager & newPtbManager,const std::string partitionName)463 bool DevicePtable::ComparePartition(PtableManager &newPtbManager, const std::string partitionName)
464 {
465 if (pPtable_ == nullptr || newPtbManager.pPtable_ == nullptr) {
466 LOG(ERROR) << "input pPtable point is nullptr, compare failed!";
467 return false;
468 }
469 if (IsPartitionChanged(pPtable_->GetPtablePartitionInfo(),
470 newPtbManager.pPtable_->GetPtablePartitionInfo(), partitionName)) {
471 LOG(INFO) << partitionName << " are different";
472 return true;
473 }
474 LOG(INFO) << partitionName << " are the same";
475 return false;
476 }
477
ComparePtable(PtableManager & newPtbManager)478 bool DevicePtable::ComparePtable(PtableManager &newPtbManager)
479 {
480 if (pPtable_ == nullptr || newPtbManager.pPtable_ == nullptr) {
481 LOG(ERROR) << "input pPtable point is nullptr, compare failed!";
482 return false;
483 }
484 if (IsPtableChanged(pPtable_->GetPtablePartitionInfo(),
485 newPtbManager.pPtable_->GetPtablePartitionInfo())) {
486 LOG(INFO) << "two ptables are different";
487 return true;
488 }
489 LOG(INFO) << "two ptables are the same";
490 return false;
491 }
492 } // namespace Updater
493