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