• 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     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