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