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