• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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