1 /* 2 * Copyright (c) 2021 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 package ohos; 17 18 import ohos.restool.ResourcesParserFactory; 19 import ohos.restool.ResourcesParserV2; 20 21 import java.io.BufferedInputStream; 22 import java.io.BufferedReader; 23 import java.io.ByteArrayOutputStream; 24 import java.io.File; 25 import java.io.FileInputStream; 26 import java.io.FileNotFoundException; 27 import java.io.FileOutputStream; 28 import java.io.IOException; 29 import java.io.InputStream; 30 import java.io.InputStreamReader; 31 32 import java.nio.charset.StandardCharsets; 33 34 import java.util.ArrayList; 35 import java.util.Enumeration; 36 import java.util.HashMap; 37 import java.util.HashSet; 38 import java.util.List; 39 import java.util.Locale; 40 import java.util.stream.Collectors; 41 import java.util.Set; 42 import java.util.zip.CRC32; 43 import java.util.zip.CheckedOutputStream; 44 import java.util.zip.ZipEntry; 45 import java.util.zip.ZipFile; 46 import java.util.zip.ZipInputStream; 47 import java.util.zip.ZipOutputStream; 48 49 /** 50 * bundle uncompress. 51 * 52 */ 53 public class Uncompress { 54 private static final String HAP_SUFFIX = ".hap"; 55 private static final String APK_SUFFIX = ".apk"; 56 private static final String JSON_SUFFIX = ".json"; 57 58 private static final String PACK_INFO = "pack.info"; 59 private static final String HARMONY_PROFILE = "config.json"; 60 private static final String MODULE_JSON = "module.json"; 61 private static final String RESOURCE_INDEX = "resources.index"; 62 private static final String RPCID_SC = "rpcid.sc"; 63 private static final String LIBS = "libs"; 64 private static final String PACKAGEFILE = "packagefile"; 65 private static final String LINUX_FILE_SEPARATOR = "/"; 66 private static final String TEMP_PATH = "temp"; 67 private static final String HAP_SUFFIXI = ".hap"; 68 private static final String ENTRY_TYPE = "entry"; 69 private static final String SYSTEM_ACTION = "action.system.home"; 70 private static final String SYSTEM_WANT_HOME = "ohos.want.action.home"; 71 private static final String SYSTEM_ENTITY = "entity.system.home"; 72 private static final int READ_BUFFER_SIZE = 1024; 73 private static final int BUFFER_SIZE = 10 * 1024; 74 private static final String LIBS_DIR_NAME = "libs"; 75 private static final String CUT_ENTRY_FILENAME = "cut_entry.apk"; 76 private static final String SO_SUFFIX = ".so"; 77 private static final String RESOURCE_PATH = "resources/base/profile/"; 78 private static final String TRUE = "true"; 79 private static final String HQF_SUFFIX = ".hqf"; 80 private static final String PATCH_JSON = "patch.json"; 81 private static final String HAP_PREFIX = "HAP"; 82 private static final String HSP_SUFFIX = ".hsp"; 83 private static final int MAX_CPU_ABI_TYPE_NUM = 128; 84 85 private static final Log LOG = new Log(Uncompress.class.toString()); 86 87 /** 88 * unpackage entrance. 89 * 90 * @param utility common data 91 * @return unpackageProcess if unpackage succeed 92 */ unpackageProcess(Utility utility)93 static boolean unpackageProcess(Utility utility) { 94 if (utility == null) { 95 LOG.error("Uncompress::unpackageProcess utility is null."); 96 return false; 97 } 98 boolean unpackageResult = true; 99 File destFile = new File(utility.getOutPath()); 100 101 if (!destFile.exists()) { 102 if (!destFile.mkdirs()) { 103 LOG.error("Uncompress::unpackageProcess create out file directory failed!"); 104 return false; 105 } 106 } 107 try { 108 if (!Utility.MODE_HAP.equals(utility.getMode()) || !TRUE.equals(utility.getRpcid())) { 109 if (!utility.getForceRewrite().isEmpty() && "true".equals(utility.getForceRewrite())) { 110 File outPath = new File(utility.getOutPath()); 111 deleteFile(outPath); 112 outPath.mkdirs(); 113 } 114 } 115 switch (utility.getMode()) { 116 case Utility.MODE_HAP: 117 unpackageHapMode(utility); 118 break; 119 case Utility.MODE_HAR: 120 dataTransferAllFiles(utility.getHarPath(), utility.getOutPath()); 121 break; 122 case Utility.MODE_APP: 123 dataTransferFilesByApp(utility, utility.getAppPath(), utility.getOutPath()); 124 break; 125 case Utility.MODE_APPQF: 126 uncompressAPPQFFile(utility); 127 break; 128 case Utility.MODE_HSP: 129 unpackageHspMode(utility); 130 break; 131 default: 132 LOG.error("Uncompress::unpackageProcess input wrong type!"); 133 throw new BundleException("Uncompress::unpackageProcess input wrong type!"); 134 } 135 } catch (BundleException ignored) { 136 unpackageResult = false; 137 LOG.error("Uncompress::unpackageProcess Bundle exception"); 138 } 139 // return uncompress information. 140 if (!unpackageResult) { 141 LOG.error("Uncompress::unpackageProcess unpackage failed!"); 142 } 143 return unpackageResult; 144 } 145 146 /** 147 * unpack hap. 148 * 149 * @param utility common data 150 */ unpackageHapMode(Utility utility)151 static void unpackageHapMode(Utility utility) throws BundleException { 152 if (!Utility.MODE_HAP.equals(utility.getMode())) { 153 LOG.error("unpackageHapMode input wrong unpack mode: " + utility.getMode()); 154 throw new BundleException("Uncompress::unpackageHapMode input wrong unpack mode"); 155 } 156 try { 157 if (TRUE.equals(utility.getLibs())) { 158 unpackageLibsMode(utility.getHapPath(), utility.getOutPath(), utility.getFormattedCpuAbiList()); 159 return; 160 } 161 if (TRUE.equals(utility.getRpcid())) { 162 getRpcidFromHap(utility.getHapPath(), utility.getOutPath()); 163 return; 164 } 165 if (TRUE.equals(utility.getUnpackApk())) { 166 unzip(utility, utility.getHapPath(), utility.getOutPath(), APK_SUFFIX); 167 String[] temp = utility.getHapPath().replace("\\", "/").split("/"); 168 String hapName = temp[temp.length - 1]; 169 repackHap(utility.getHapPath(), utility.getOutPath(), hapName, utility.getUnpackApk()); 170 } else { 171 dataTransferAllFiles(utility.getHapPath(), utility.getOutPath()); 172 } 173 } catch (BundleException e) { 174 LOG.error("Uncompress::unpackageHapMode failed"); 175 throw new BundleException("Uncompress::unpackageHapMode failed"); 176 } 177 } 178 179 /** 180 * unpack hsp. 181 * 182 * @param utility common data 183 */ unpackageHspMode(Utility utility)184 static void unpackageHspMode(Utility utility) throws BundleException { 185 if (!Utility.MODE_HSP.equals(utility.getMode())) { 186 LOG.error("unpackageHspMode input wrong unpack mode: " + utility.getMode()); 187 throw new BundleException("Uncompress::unpackageHspMode input wrong unpack mode"); 188 } 189 try { 190 if (TRUE.equals(utility.getLibs())) { 191 List<String> cpuAbiList = utility.getFormattedCpuAbiList(); 192 unpackageLibsMode(utility.getHspPath(), utility.getOutPath(), cpuAbiList); 193 return; 194 } 195 dataTransferAllFiles(utility.getHspPath(), utility.getOutPath()); 196 } catch (BundleException e) { 197 LOG.error("Uncompress::unpackageHspMode failed"); 198 throw new BundleException("Uncompress::unpackageHspMode failed"); 199 } 200 } 201 202 /** 203 * uncompress app. 204 * 205 * @param utility common data 206 * @return the uncompress result 207 */ uncompressAppByPath(Utility utility)208 static UncompressResult uncompressAppByPath(Utility utility) { 209 UncompressResult compressResult = new UncompressResult(); 210 InputStream input = null; 211 String srcPath = utility.getAppPath(); 212 String parseMode = utility.getParseMode(); 213 214 try { 215 if (UncompressEntrance.PARSE_MODE_HAPLIST.equals(parseMode)) { 216 compressResult = uncompress(utility.getDeviceType(), srcPath, PACK_INFO); 217 } else if (UncompressEntrance.PARSE_MODE_HAPINFO.equals(parseMode)) { 218 compressResult = uncompressHapAndHspFromAppPath(srcPath, utility); 219 } else if (UncompressEntrance.PARSE_MODE_ALL.equals(parseMode)) { 220 compressResult = uncompressAllAppByPath(srcPath); 221 } else { 222 LOG.error("Uncompress::uncompressApp parseMode is invalid!"); 223 compressResult.setResult(false); 224 compressResult.setMessage("ParseApp parseMode is invalid"); 225 } 226 227 compressResult.setPackageSize(FileUtils.getFileSize(srcPath)); 228 } catch (BundleException e) { 229 LOG.error("Uncompress::uncompressApp Bundle exception"); 230 compressResult.setResult(false); 231 compressResult.setMessage("ParseApp Bundle exception"); 232 } finally { 233 Utility.closeStream(input); 234 } 235 return compressResult; 236 } 237 uncompressHapAndHspFromAppPath( String srcPath, Utility utility)238 private static UncompressResult uncompressHapAndHspFromAppPath( 239 String srcPath, Utility utility) throws BundleException { 240 UncompressResult result = new UncompressResult(); 241 String hapName = utility.getHapName(); 242 if (!hapName.toLowerCase(Locale.ENGLISH).endsWith(HAP_SUFFIX) 243 && !hapName.toLowerCase(Locale.ENGLISH).endsWith(HSP_SUFFIX)) { 244 hapName += HAP_SUFFIX; 245 } 246 ZipFile appFile = null; 247 ZipEntry entry = null; 248 InputStream stream = null; 249 try { 250 appFile = new ZipFile(srcPath); 251 Enumeration<? extends ZipEntry> entries = appFile.entries(); 252 while (entries.hasMoreElements()) { 253 entry = entries.nextElement(); 254 stream = appFile.getInputStream(entry); 255 if (!hapName.equals(entry.getName().toLowerCase(Locale.ENGLISH))) { 256 continue; 257 } 258 UncompressResult hapInfo = uncompressHapByStream("", stream, hapName); 259 if (hapInfo.getProfileInfos() != null && hapInfo.getProfileInfos().size() > 0) { 260 hapInfo.getProfileInfos().get(0).hapInfo.originalSize = entry.getSize(); 261 hapInfo.getProfileInfos().get(0).hapInfo.compressedSize = entry.getCompressedSize(); 262 result.addProfileInfo(hapInfo.getProfileInfos().get(0)); 263 result.addProfileInfoStr(hapInfo.getProfileInfosStr().get(0)); 264 } 265 break; 266 } 267 } catch (IOException | BundleException e) { 268 LOG.error("uncompressHapFromAppPath failed: " + e.getMessage()); 269 throw new BundleException("uncompressHapFromAppPath failed!"); 270 } finally { 271 Utility.closeStream(appFile); 272 Utility.closeStream(stream); 273 } 274 return result; 275 } 276 uncompressAllAppByPath(String srcPath)277 private static UncompressResult uncompressAllAppByPath(String srcPath) throws BundleException { 278 UncompressResult result = new UncompressResult(); 279 ZipFile appFile = null; 280 ZipEntry entry = null; 281 InputStream stream = null; 282 try { 283 appFile = new ZipFile(srcPath); 284 Enumeration<? extends ZipEntry> entries = appFile.entries(); 285 while (entries.hasMoreElements()) { 286 entry = entries.nextElement(); 287 stream = appFile.getInputStream(entry); 288 if (PACK_INFO.equals(entry.getName().toLowerCase(Locale.ENGLISH))) { 289 String packInfo = new BufferedReader(new InputStreamReader(stream, StandardCharsets.UTF_8)) 290 .lines().parallel().collect(Collectors.joining(System.lineSeparator())); 291 List<PackInfo> packInfos = JsonUtil.parseHapList("", packInfo); 292 result.setPackInfoStr(packInfo); 293 result.setPackInfos(packInfos); 294 } 295 if (entry.getName().toLowerCase(Locale.ENGLISH).endsWith(HAP_SUFFIX) 296 || entry.getName().toLowerCase(Locale.ENGLISH).endsWith(HSP_SUFFIX)) { 297 UncompressResult hapInfo = uncompressHapByStream("", stream, entry.getName()); 298 if (hapInfo.getProfileInfos() != null && hapInfo.getProfileInfos().size() > 0) { 299 hapInfo.getProfileInfos().get(0).hapInfo.originalSize = entry.getSize(); 300 hapInfo.getProfileInfos().get(0).hapInfo.compressedSize = entry.getCompressedSize(); 301 result.addProfileInfo(hapInfo.getProfileInfos().get(0)); 302 result.addProfileInfoStr(hapInfo.getProfileInfosStr().get(0)); 303 } 304 } 305 } 306 result = checkParseAllResult(result); 307 result = obtainLabelAndIcon(result); 308 } catch (IOException | BundleException e) { 309 LOG.error("uncompressAllAppByPath failed: " + e.getMessage()); 310 throw new BundleException("uncompressAllAppByPath failed!"); 311 } finally { 312 Utility.closeStream(appFile); 313 Utility.closeStream(stream); 314 } 315 return result; 316 } 317 318 319 /** 320 * uncompress app. 321 * 322 * @param utility common data 323 * @param input the InputStream about the app package. 324 * @return the uncompress result 325 */ uncompressAppByInput(Utility utility, InputStream input)326 static UncompressResult uncompressAppByInput(Utility utility, InputStream input) { 327 UncompressResult compressResult = new UncompressResult(); 328 String parseMode = utility.getParseMode(); 329 try { 330 if (!parseMode.isEmpty() && UncompressEntrance.PARSE_MODE_HAPLIST.equals(parseMode)) { 331 compressResult = uncompressByInput(utility.getDeviceType(), input, PACK_INFO, ""); 332 } else if (!parseMode.isEmpty() && UncompressEntrance.PARSE_MODE_HAPINFO.equals(parseMode)) { 333 compressResult = uncompressHapFromAppStream(utility.getDeviceType(), input, utility.getHapName()); 334 } else if (!parseMode.isEmpty() && UncompressEntrance.PARSE_MODE_ALL.equals(parseMode)) { 335 compressResult = uncompressAllFromAppStream(input); 336 } else { 337 LOG.error("Uncompress::uncompressAppByInput parseMode is invalid!"); 338 compressResult.setResult(false); 339 compressResult.setMessage("ParseApp parseMode is invalid"); 340 } 341 } catch (BundleException exception) { 342 LOG.error("Uncompress::uncompressAppByInput Bundle exception"); 343 compressResult.setResult(false); 344 compressResult.setMessage("ParseApp Bundle exception"); 345 } 346 return compressResult; 347 } 348 uncompressHapFromAppStream(String deviceType, InputStream stream, String fileName)349 private static UncompressResult uncompressHapFromAppStream(String deviceType, InputStream stream, String fileName) 350 throws BundleException { 351 String hapFile = fileName; 352 if (!fileName.toLowerCase(Locale.ENGLISH).endsWith(HAP_SUFFIX) 353 && !fileName.toLowerCase(Locale.ENGLISH).endsWith(HSP_SUFFIX)) { 354 hapFile += HAP_SUFFIX; 355 } 356 UncompressResult result = new UncompressResult(); 357 ZipInputStream zipInputStream = null; 358 try { 359 zipInputStream = new ZipInputStream(stream); 360 ZipEntry appEntry; 361 while ((appEntry = zipInputStream.getNextEntry()) != null) { 362 if (appEntry.getName().toLowerCase(Locale.ENGLISH).equals(hapFile)) { 363 result = uncompressHapByStream("", zipInputStream, appEntry.getName()); 364 } 365 366 if (result.getProfileInfos().size() > 0) { 367 result.getProfileInfos().get(0).hapInfo.originalSize = appEntry.getSize(); 368 result.getProfileInfos().get(0).hapInfo.compressedSize = appEntry.getCompressedSize(); 369 } 370 } 371 } catch (IOException e) { 372 LOG.error("uncompressHapFromAppStream failed: " + e.getMessage()); 373 throw new BundleException("uncompressHapFromAppStream failed!"); 374 } finally { 375 Utility.closeStream(zipInputStream); 376 } 377 return result; 378 } 379 uncompressAllFromAppStream(InputStream stream)380 private static UncompressResult uncompressAllFromAppStream(InputStream stream) throws BundleException { 381 UncompressResult result = new UncompressResult(); 382 ZipInputStream zipInputStream = null; 383 try { 384 zipInputStream = new ZipInputStream(stream); 385 ZipEntry entry; 386 while ((entry = zipInputStream.getNextEntry()) != null) { 387 if (PACK_INFO.equals(entry.getName().toLowerCase(Locale.ENGLISH))) { 388 String packInfo = new BufferedReader(new InputStreamReader(zipInputStream, 389 StandardCharsets.UTF_8)).lines().parallel() 390 .collect(Collectors.joining(System.lineSeparator())); 391 List<PackInfo> packInfos = JsonUtil.parseHapList("", packInfo); 392 result.setPackInfoStr(packInfo); 393 result.setPackInfos(packInfos); 394 } 395 if (entry.getName().toLowerCase(Locale.ENGLISH).endsWith(HAP_SUFFIX) 396 || entry.getName().toLowerCase(Locale.ENGLISH).endsWith(HSP_SUFFIX)) { 397 UncompressResult hapResult = uncompressHapByStream("", zipInputStream, entry.getName()); 398 if (hapResult.getProfileInfos() != null && hapResult.getProfileInfos().size() > 0) { 399 hapResult.getProfileInfos().get(0).hapInfo.originalSize = entry.getSize(); 400 hapResult.getProfileInfos().get(0).hapInfo.compressedSize = entry.getCompressedSize(); 401 result.addProfileInfo(hapResult.getProfileInfos().get(0)); 402 result.addProfileInfoStr(hapResult.getProfileInfosStr().get(0)); 403 } 404 } 405 } 406 result = checkParseAllResult(result); 407 result = obtainLabelAndIcon(result); 408 } catch (IOException | BundleException e) { 409 LOG.error("uncompressAllFromAppStream failed: " + e.getMessage()); 410 throw new BundleException("uncompressAllFromAppStream failed!"); 411 } finally { 412 Utility.closeStream(zipInputStream); 413 } 414 return result; 415 } 416 417 /** 418 * uncompress hap. 419 * 420 * @param utility common data 421 * @return the uncompress result 422 */ uncompressHap(Utility utility)423 static UncompressResult uncompressHap(Utility utility) { 424 UncompressResult compressResult = new UncompressResult(); 425 try { 426 compressResult = uncompressHapByPath(utility.getDeviceType(), utility.getHapPath()); 427 } catch (BundleException ignored) { 428 LOG.error("Uncompress::uncompressHap Bundle exception"); 429 compressResult.setResult(false); 430 compressResult.setMessage("uncompressHap Bundle exception"); 431 } 432 return compressResult; 433 } 434 435 /** 436 * uncompress hap by path, it can adapt stage module and fa module. 437 * 438 * @param deviceType indicates the device type of parse type. 439 * @param hapPath indicates the hap path of hap. 440 * @return the uncompress result 441 */ uncompressHapByPath(String deviceType, String hapPath)442 static UncompressResult uncompressHapByPath(String deviceType, String hapPath) throws BundleException { 443 UncompressResult compressResult = new UncompressResult(); 444 try { 445 if (isModuleHap(hapPath, compressResult)) { 446 compressResult = unCompressModuleHap(deviceType, hapPath, MODULE_JSON); 447 } else { 448 compressResult = uncompress(deviceType, hapPath, HARMONY_PROFILE); 449 compressResult = obtainLabelAndIcon(compressResult); 450 } 451 } catch (BundleException e) { 452 LOG.error("Uncompress::uncompressHapByPath Bundle exception"); 453 throw new BundleException("Uncompress::uncompressHapByPath failed"); 454 } 455 return compressResult; 456 } 457 458 /** 459 * uncompress hap. 460 * 461 * @param utility common data 462 * @param input the InputStream about the app package. 463 * @return the uncompress result 464 */ uncompressHapByInput(Utility utility, InputStream input)465 static UncompressResult uncompressHapByInput(Utility utility, InputStream input) { 466 UncompressResult compressResult = new UncompressResult(); 467 try { 468 compressResult = uncompressHapByStream(utility.getDeviceType(), input, ""); 469 } catch (BundleException ignored) { 470 LOG.error("Uncompress::uncompressHapByInput Bundle exception"); 471 compressResult.setResult(false); 472 compressResult.setMessage("uncompressHapByInput Bundle exception"); 473 } 474 return compressResult; 475 } 476 477 /** 478 * uncompress hap by InputStream, it can adapt stage module and fa module. 479 * 480 * @param deviceType indicates the device type of parse type. 481 * @param stream indicates the input stream of hap. 482 * @return the uncompress result 483 */ uncompressHapByStream(String deviceType, InputStream stream, String hapName)484 static UncompressResult uncompressHapByStream(String deviceType, InputStream stream, 485 String hapName) throws BundleException { 486 UncompressResult compressResult = new UncompressResult(); 487 compressResult = uncompressHapByBigStream(deviceType, stream, hapName); 488 return compressResult; 489 } 490 uncompressHapByBigStream(String deviceType, InputStream stream, String hapName)491 static UncompressResult uncompressHapByBigStream(String deviceType, InputStream stream, String hapName) 492 throws BundleException { 493 UncompressResult compressResult = new UncompressResult(); 494 InputStream fileStream = null; 495 InputStream parseStream = null; 496 File file = null; 497 try { 498 String releativePath = System.getProperty("user.dir"); 499 File directory = new File(releativePath); 500 file = File.createTempFile(HAP_PREFIX, HAP_SUFFIX, directory); 501 writeToTempFile(stream, file); 502 fileStream = new FileInputStream(file); 503 boolean isModule = false; 504 if (isModuleInput(fileStream)) { 505 isModule = true; 506 } 507 parseStream = new FileInputStream(file); 508 if (isModule) { 509 compressResult = uncompressModuleHapByInput(deviceType, parseStream, MODULE_JSON, hapName); 510 } else { 511 compressResult = uncompressByInput(deviceType, parseStream, HARMONY_PROFILE, hapName); 512 compressResult = obtainLabelAndIcon(compressResult); 513 } 514 } catch (IOException e) { 515 LOG.error("uncompressHapByBigStream failed for IO exception: " + e.getMessage()); 516 throw new BundleException("uncompressHapByBigStream failed for IO exception!"); 517 } finally { 518 Utility.closeStream(fileStream); 519 Utility.closeStream(parseStream); 520 if (file != null) { 521 FileUtils.deleteFile(file.getPath()); 522 } 523 } 524 return compressResult; 525 } 526 527 /** 528 * unzip process 529 * 530 * @param utility common data 531 * @param srcPath source file path 532 * @param destDirPath destination file path 533 * @param suffix suffix for judgment 534 * @throws BundleException FileNotFoundException|IOException. 535 */ unzip(Utility utility, String srcPath, String destDirPath, String suffix)536 private static void unzip(Utility utility, String srcPath, String destDirPath, String suffix) 537 throws BundleException { 538 if (utility == null) { 539 LOG.error("Uncompress::unzip utility is null!"); 540 throw new BundleException("Unzip failed, utility is null"); 541 } 542 543 if (srcPath.isEmpty() || !UncompressVerify.isPathValid(srcPath, true, "")) { 544 LOG.error("Uncompress::unzip srcPath is invalid!"); 545 throw new BundleException("Unzip failed, srcPath is invalid"); 546 } 547 548 if (destDirPath.isEmpty() || !UncompressVerify.isPathValid(destDirPath, false, null)) { 549 LOG.error("Uncompress::unzip destDirPath is invalid!"); 550 throw new BundleException("Unzip failed, destDirPath is invalid"); 551 } 552 unzipFromFile(utility, srcPath, destDirPath, suffix); 553 } 554 555 /** 556 * unzip process from the file 557 * 558 * @param utility common data 559 * @param srcPath source file path 560 * @param destDirPath destination file path 561 * @param suffix suffix for judgment 562 * @throws BundleException FileNotFoundException|IOException. 563 */ unzipFromFile(Utility utility, String srcPath, String destDirPath, String suffix)564 private static void unzipFromFile(Utility utility, String srcPath, String destDirPath, String suffix) 565 throws BundleException { 566 ZipFile zipFile = null; 567 String hapNames = ""; 568 try { 569 zipFile = new ZipFile(new File(srcPath)); 570 if (utility != null && !utility.getDeviceType().isEmpty() 571 && (HAP_SUFFIX.equals(suffix) || HSP_SUFFIX.equals(suffix))) { 572 List<PackInfo> packInfos = uncompress(utility.getDeviceType(), srcPath, PACK_INFO).getPackInfos(); 573 for (PackInfo packinfo : packInfos) { 574 hapNames += packinfo.name + ","; 575 } 576 } 577 578 int entriesNum = 0; 579 for (Enumeration<? extends ZipEntry> entries = zipFile.entries(); entries.hasMoreElements(); ) { 580 entriesNum++; 581 ZipEntry entry = entries.nextElement(); 582 String entryName = ""; 583 if (entry == null || entry.getName().isEmpty()) { 584 continue; 585 } 586 if (entry.getName().toLowerCase().endsWith(CUT_ENTRY_FILENAME) && 587 "false".equals(utility.getUnpackCutEntryApk())) { 588 continue; 589 } 590 entryName = entry.getName(); 591 if (!entryName.toLowerCase(Locale.ENGLISH).endsWith(suffix) || 592 (!hapNames.isEmpty() && !hapNames.contains(entryName.replace(suffix, "")))) { 593 continue; 594 } 595 String tempDir = destDirPath.replace(File.separator, LINUX_FILE_SEPARATOR); 596 if (HAP_SUFFIX.equals(suffix) && "true".equals(utility.getUnpackApk())) { 597 tempDir = tempDir + LINUX_FILE_SEPARATOR + entryName.replace(suffix, ""); 598 File destFileDir = new File(tempDir); 599 if (!destFileDir.exists()) { 600 destFileDir.mkdir(); 601 } 602 } 603 if (APK_SUFFIX.equals(suffix) && "true".equals(utility.getUnpackApk()) 604 && entryName.contains(LINUX_FILE_SEPARATOR)) { 605 // only unpack shell apk which in the root directory 606 continue; 607 } 608 String tempPath = tempDir + LINUX_FILE_SEPARATOR + entryName; 609 if (!FileUtils.matchPattern(tempPath)) { 610 LOG.error("Input invalid file: " + tempPath); 611 throw new BundleException("Input invalid file " + tempPath); 612 } 613 File destFile = new File(tempPath); 614 dataTransfer(zipFile, entry, destFile); 615 if (JSON_SUFFIX.equals(suffix)) { 616 break; 617 } else if (HAP_SUFFIX.equals(suffix) && "true".equals(utility.getUnpackApk())) { 618 unzip(utility, tempPath, tempDir, APK_SUFFIX); 619 repackHap(tempPath, tempDir, entryName, utility.getUnpackApk()); 620 } 621 } 622 } catch (IOException | BundleException exception) { 623 LOG.error("Uncompress::unzipInHapMode failed: " + exception.getMessage()); 624 throw new BundleException("Unzip in hap mode failed"); 625 } finally { 626 Utility.closeStream(zipFile); 627 } 628 } 629 630 /** 631 * uncompress dataTransfer 632 * 633 * @param zipFile input zip file 634 * @param entry input file in zip 635 * @param destFile output file path 636 * @throws BundleException FileNotFoundException|IOException. 637 */ dataTransfer(ZipFile zipFile, ZipEntry entry, File destFile)638 private static void dataTransfer(ZipFile zipFile, ZipEntry entry, File destFile) throws BundleException { 639 InputStream fileInputStream = null; 640 FileOutputStream fileOutStream = null; 641 try { 642 if (!FileUtils.matchPattern(destFile.getCanonicalPath())) { 643 LOG.error("Input invalid file " + destFile.getCanonicalPath()); 644 throw new BundleException("Input invalid file" + destFile.getCanonicalPath()); 645 } 646 fileInputStream = zipFile.getInputStream(entry); 647 fileOutStream = new FileOutputStream(destFile); 648 byte[] data = new byte[BUFFER_SIZE]; 649 int count = fileInputStream.read(data); 650 int total = 0; 651 while (count > 0) { 652 fileOutStream.write(data, 0, count); 653 total += count; 654 count = fileInputStream.read(data); 655 } 656 } catch (IOException | BundleException exception) { 657 LOG.error("Uncompress::dataTransfer file " + exception.getMessage()); 658 throw new BundleException("DataTransfer failed"); 659 } finally { 660 Utility.closeStream(fileOutStream); 661 Utility.closeStream(fileInputStream); 662 } 663 } 664 665 /** 666 * uncompress dataTransfer all files. 667 * 668 * @param srcPath source file path 669 * @param destDirPath destination file path 670 * @throws BundleException FileNotFoundException|IOException. 671 */ dataTransferAllFiles(String srcPath, String destDirPath)672 private static void dataTransferAllFiles(String srcPath, String destDirPath) throws BundleException { 673 ZipFile zipFile = null; 674 try { 675 if (!FileUtils.matchPattern(srcPath)) { 676 throw new BundleException("Input invalid file " + srcPath); 677 } 678 zipFile = new ZipFile(new File(srcPath)); 679 int entriesNum = 0; 680 for (Enumeration<? extends ZipEntry> entries = zipFile.entries(); entries.hasMoreElements(); ) { 681 entriesNum++; 682 ZipEntry entry = entries.nextElement(); 683 if (entry == null) { 684 continue; 685 } 686 String tempPath = destDirPath + LINUX_FILE_SEPARATOR + entry.getName(); 687 File destFile = new File(tempPath); 688 if (destFile != null && destFile.getParentFile() != null && !destFile.getParentFile().exists()) { 689 destFile.getParentFile().mkdirs(); 690 } 691 dataTransfer(zipFile, entry, destFile); 692 } 693 } catch (FileNotFoundException ignored) { 694 LOG.error("Uncompress::unzipApk file not found exception: " + ignored.getMessage()); 695 throw new BundleException("Unzip Apk failed"); 696 } catch (IOException exception) { 697 LOG.error("Uncompress::unzipApk io exception: " + exception.getMessage()); 698 throw new BundleException("Unzip Apk failed"); 699 } finally { 700 Utility.closeStream(zipFile); 701 } 702 } 703 dataTransferFilesByApp(Utility utility, String srcPath, String destDirPath)704 private static void dataTransferFilesByApp(Utility utility, String srcPath, String destDirPath) 705 throws BundleException { 706 ZipFile zipFile = null; 707 try { 708 zipFile = new ZipFile(new File(srcPath)); 709 int entriesNum = 0; 710 for (Enumeration<? extends ZipEntry> entries = zipFile.entries(); entries.hasMoreElements(); ) { 711 entriesNum++; 712 ZipEntry entry = entries.nextElement(); 713 if (entry == null) { 714 continue; 715 } 716 String filePath = destDirPath + LINUX_FILE_SEPARATOR + entry.getName(); 717 if (!FileUtils.matchPattern(filePath)) { 718 throw new BundleException("Input invalid path " + filePath); 719 } 720 File destFile = new File(filePath); 721 if (destFile != null && destFile.getParentFile() != null && !destFile.getParentFile().exists()) { 722 destFile.getParentFile().mkdirs(); 723 } 724 boolean isUnpackApk = "true".equals(utility.getUnpackApk()); 725 if (isUnpackApk && filePath.toLowerCase().endsWith(HAP_SUFFIX)) { 726 dataTransfer(zipFile, entry, destFile); 727 unzip(utility, filePath, destDirPath, APK_SUFFIX); 728 String[] temp = filePath.replace("\\", "/").split("/"); 729 String hapName = ""; 730 if (temp.length > 0) { 731 hapName = temp[temp.length - 1]; 732 } 733 repackHap(filePath, destDirPath, hapName, utility.getUnpackApk()); 734 } else { 735 dataTransfer(zipFile, entry, destFile); 736 } 737 } 738 } catch (IOException | BundleException exception) { 739 LOG.error("Uncompress::unzipApk file failed " + exception.getMessage()); 740 throw new BundleException("Unzip Apk failed"); 741 } finally { 742 Utility.closeStream(zipFile); 743 } 744 } 745 getResourceDataFromHap(ZipFile zipFile)746 private static byte[] getResourceDataFromHap(ZipFile zipFile) throws BundleException, IOException { 747 int entriesNum = 0; 748 InputStream indexInputStream = null; 749 try { 750 for (Enumeration<? extends ZipEntry> entries = zipFile.entries(); entries.hasMoreElements(); ) { 751 entriesNum++; 752 ZipEntry indexEntry = entries.nextElement(); 753 if (indexEntry == null) { 754 continue; 755 } 756 if (indexEntry != null && !"".equals(indexEntry.getName()) && 757 indexEntry.getName().toLowerCase().endsWith(RESOURCE_INDEX)) { 758 indexInputStream = zipFile.getInputStream(indexEntry); 759 return getByte(indexInputStream); 760 } 761 } 762 } finally { 763 Utility.closeStream(indexInputStream); 764 } 765 return null; 766 } 767 unZipHapFileFromHapFile(String srcPath)768 private static HapZipInfo unZipHapFileFromHapFile(String srcPath) 769 throws BundleException, IOException { 770 HapZipInfo hapZipInfo = new HapZipInfo(); 771 ZipFile zipFile = null; 772 if (!FileUtils.matchPattern(srcPath)) { 773 LOG.error("Input invalid path " + srcPath); 774 throw new BundleException("Input invalid path " + srcPath); 775 } 776 try { 777 File srcFile = new File(srcPath); 778 zipFile = new ZipFile(srcFile); 779 hapZipInfo.setHarmonyProfileJsonStr(FileUtils.getFileStringFromZip(HARMONY_PROFILE, zipFile)); 780 hapZipInfo.setResDataBytes(getResourceDataFromHap(zipFile)); 781 hapZipInfo.setPackInfoJsonStr(FileUtils.getFileStringFromZip(PACK_INFO, zipFile)); 782 hapZipInfo.setHapFileName(getHapNameWithoutSuffix(srcFile.getName())); 783 } finally { 784 Utility.closeStream(zipFile); 785 } 786 return hapZipInfo; 787 } 788 789 /** 790 * uncompress from specified file name 791 * 792 * @param deviceType device type 793 * @param srcPath source file path 794 * @param fileName uncompress file name 795 * @return the uncompress result 796 * @throws BundleException FileNotFoundException|IOException. 797 */ uncompress(String deviceType, String srcPath, String fileName)798 private static UncompressResult uncompress(String deviceType, String srcPath, String fileName) 799 throws BundleException { 800 if (srcPath.isEmpty() || fileName.isEmpty()) { 801 LOG.error("Uncompress::uncompress srcPath, fileName is empty!"); 802 throw new BundleException("Uncompress failed, srcPath or fileName is empty"); 803 } 804 805 UncompressResult result = new UncompressResult(); 806 try { 807 HapZipInfo hapZipInfo = unZipHapFileFromHapFile(srcPath); 808 if (isPackInfo(fileName)) { 809 uncompressPackInfo(deviceType, hapZipInfo, result); 810 } else { 811 uncompressProfileInfo(hapZipInfo, result); 812 } 813 } catch (IOException exception) { 814 LOG.error("Uncompress::uncompress io exception: " + exception.getMessage()); 815 throw new BundleException("Uncompress failed"); 816 } 817 return result; 818 } 819 uncompressPackInfo(String deviceType, HapZipInfo hapZipInfo, UncompressResult uncomperssResult)820 private static void uncompressPackInfo(String deviceType, HapZipInfo hapZipInfo, UncompressResult uncomperssResult) 821 throws BundleException { 822 List<PackInfo> packInfos = JsonUtil.parseHapList(deviceType, hapZipInfo.getPackInfoJsonStr()); 823 uncomperssResult.setPackInfoStr(hapZipInfo.getPackInfoJsonStr()); 824 uncomperssResult.setPackInfos(packInfos); 825 } 826 uncompressProfileInfo(HapZipInfo hapZipInfo, UncompressResult uncomperssResult)827 private static void uncompressProfileInfo(HapZipInfo hapZipInfo, UncompressResult uncomperssResult) 828 throws BundleException { 829 ProfileInfo profileInfo = JsonUtil.parseProfileInfo(hapZipInfo.getHarmonyProfileJsonStr(), 830 hapZipInfo.getResDataBytes(), hapZipInfo.getPackInfoJsonStr(), hapZipInfo.getHapFileName()); 831 profileInfo.hapName = hapZipInfo.getHapFileName(); 832 profileInfo.appInfo.setBundleType(getFABundleType(profileInfo)); 833 uncomperssResult.addProfileInfoStr(hapZipInfo.getHarmonyProfileJsonStr()); 834 uncomperssResult.addProfileInfo(profileInfo); 835 } 836 getFABundleType(ProfileInfo profileInfo)837 private static String getFABundleType(ProfileInfo profileInfo) { 838 String bundleType = "app"; 839 if (profileInfo.hapInfo.distro.installationFree == 1) { 840 bundleType = "atomicService"; 841 } 842 return bundleType; 843 } 844 unZipHapFileFromInputStream(InputStream input)845 private static HapZipInfo unZipHapFileFromInputStream(InputStream input) throws BundleException, IOException { 846 BufferedInputStream bufIn = null; 847 ZipInputStream zipIn = null; 848 BufferedReader bufferedReader = null; 849 HapZipInfo hapZipInfo = new HapZipInfo(); 850 try { 851 ZipEntry entry = null; 852 bufIn = new BufferedInputStream(input); 853 zipIn = new ZipInputStream(bufIn); 854 int entriesNum = 0; 855 while ((entry = zipIn.getNextEntry()) != null) { 856 entriesNum++; 857 if (entry.getName().toLowerCase().endsWith(RESOURCE_INDEX)) { 858 hapZipInfo.setResDataBytes(getByte(zipIn)); 859 continue; 860 } 861 if (isPackInfo(entry.getName())) { 862 bufferedReader = new BufferedReader(new InputStreamReader(zipIn)); 863 hapZipInfo.setPackInfoJsonStr(readStringFromInputStream(zipIn, bufferedReader)); 864 continue; 865 } 866 if (isHarmonyProfile(entry.getName())) { 867 bufferedReader = new BufferedReader(new InputStreamReader(zipIn)); 868 hapZipInfo.setHarmonyProfileJsonStr(readStringFromInputStream(zipIn, bufferedReader)); 869 } 870 } 871 } finally { 872 Utility.closeStream(bufferedReader); 873 Utility.closeStream(bufIn); 874 Utility.closeStream(zipIn); 875 } 876 return hapZipInfo; 877 } 878 readStringFromInputStream(ZipInputStream zipIn, BufferedReader bufferedReader)879 private static String readStringFromInputStream(ZipInputStream zipIn, BufferedReader bufferedReader) 880 throws IOException { 881 String line; 882 StringBuilder sb = new StringBuilder(); 883 while ((line = bufferedReader.readLine()) != null) { 884 sb.append(line); 885 } 886 return sb.toString(); 887 } 888 889 /** 890 * uncompress process by InputStream 891 * 892 * @param deviceType device type 893 * @param input the InputStream about the package. 894 * @param fileName uncompress file name 895 * @return the uncompress result 896 * @throws BundleException FileNotFoundException|IOException. 897 */ uncompressByInput(String deviceType, InputStream input, String fileName, String hapName)898 private static UncompressResult uncompressByInput(String deviceType, InputStream input, 899 String fileName, String hapName) throws BundleException { 900 UncompressResult result = new UncompressResult(); 901 try { 902 HapZipInfo hapZipInfo = unZipHapFileFromInputStream(input); 903 hapZipInfo.setHapFileName(hapName); 904 if (isPackInfo(fileName)) { 905 uncompressPackInfo(deviceType, hapZipInfo, result); 906 } else { 907 uncompressProfileInfo(hapZipInfo, result); 908 } 909 } catch (IOException exception) { 910 LOG.error("Uncompress::uncompressByInput io exception: " + exception.getMessage()); 911 throw new BundleException("Uncompress by input failed"); 912 } 913 return result; 914 } 915 916 /** 917 * uncompress process by InputStream 918 * 919 * @param deviceType device type 920 * @param input the InputStream about the package. 921 * @param fileName uncompress file name 922 * @return the module uncompress result 923 * @throws BundleException FileNotFoundException|IOException. 924 */ uncompressModuleByInput(String deviceType, InputStream input, String fileName, String hapName)925 private static ModuleResult uncompressModuleByInput(String deviceType, InputStream input, 926 String fileName, String hapName) throws BundleException { 927 ModuleResult result = new ModuleResult(); 928 try { 929 HapZipInfo hapZipInfo = unZipModuleHapFileFromInputStream(input); 930 hapZipInfo.setHapFileName(hapName); 931 if (isPackInfo(fileName)) { 932 // for parse app 933 } else { 934 uncompressModuleJsonInfo(hapZipInfo, result); 935 } 936 } catch (BundleException exception) { 937 LOG.error("Uncompress::uncompressByInput io exception: " + exception.getMessage()); 938 throw new BundleException("Uncompress by input failed"); 939 } 940 return result; 941 } 942 943 /** 944 * Get entry byte array. 945 * 946 * @param zis the InputStream about the entry. 947 * @return Return the entry byte array. 948 * @throws BundleException FileNotFoundException|IOException. 949 */ getByte(InputStream zis)950 private static byte[] getByte(InputStream zis) throws BundleException { 951 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 952 byte[] buf = null; 953 try { 954 byte[] temp = new byte[READ_BUFFER_SIZE]; 955 int length = 0; 956 957 while ((length = zis.read(temp, 0, READ_BUFFER_SIZE)) != -1) { 958 bos.write(temp, 0, length); 959 } 960 961 buf = bos.toByteArray(); 962 } catch (IOException e) { 963 LOG.error("Uncompress::getByte io exception: " + e.getMessage()); 964 throw new BundleException("Get byte failed"); 965 } finally { 966 Utility.closeStream(bos); 967 } 968 return buf; 969 } 970 971 /** 972 * repack hap 973 * 974 * @param srcPath source file path 975 * @param destDirPath destination file path 976 * @param fileName target file name 977 * @param unpackApk unpackApk flag 978 * @throws BundleException FileNotFoundException|IOException. 979 */ repackHap(String srcPath, String destDirPath, String fileName, String unpackApk)980 private static void repackHap(String srcPath, String destDirPath, String fileName, String unpackApk) 981 throws BundleException { 982 if (srcPath.isEmpty() || destDirPath.isEmpty() || fileName.isEmpty()) { 983 LOG.error("Uncompress::repackHap srcPath, destDirPath or fileName is empty!"); 984 throw new BundleException("Repack hap failed, srcPath, destDirPath or fileName is empty"); 985 } 986 987 if (!UncompressVerify.isPathValid(srcPath, true, "")) { 988 LOG.error("Uncompress::repackHap srcPath is invalid!"); 989 throw new BundleException("Repack hap failed, srcPath is invalid"); 990 } 991 992 if (!UncompressVerify.isPathValid(destDirPath, false, null)) { 993 LOG.error("Uncompress::repackHap destDirPath is invalid!"); 994 throw new BundleException("Repack hap failed, destDirPath is invalid"); 995 } 996 997 String tempDir = destDirPath.replace(File.separator, LINUX_FILE_SEPARATOR) + LINUX_FILE_SEPARATOR + 998 TEMP_PATH; 999 dataTransferAllFiles(srcPath, tempDir); 1000 packFilesByPath(tempDir, destDirPath, fileName, unpackApk); 1001 File deleteFile = new File(tempDir); 1002 deleteFile(deleteFile); 1003 } 1004 1005 /** 1006 * compress file directory. 1007 * 1008 * @param srcPath source file path 1009 * @param destDirPath destination file path 1010 * @param fileName target file name 1011 * @param unpackApk unpackApk flag 1012 * @throws BundleException FileNotFoundException|IOException. 1013 */ packFilesByPath(String srcPath, String destDirPath, String fileName, String unpackApk)1014 private static void packFilesByPath(String srcPath, String destDirPath, String fileName, String unpackApk) 1015 throws BundleException { 1016 if (srcPath.isEmpty() || destDirPath.isEmpty() || fileName.isEmpty()) { 1017 LOG.error("Uncompress::packFilesByPath srcPath, destDirPath or fileName is empty!"); 1018 throw new BundleException("Pack files by path failed, srcPath, destDirPath or fileName is empty"); 1019 } 1020 1021 if (!UncompressVerify.isPathValid(srcPath, false, null) || 1022 !UncompressVerify.isPathValid(destDirPath, false, null)) { 1023 LOG.error("Uncompress::packFilesByPath srcPath or destDirPath is invalid!"); 1024 throw new BundleException("Pack files by path failed, srcPath or destDirPath is invalid"); 1025 } 1026 1027 File srcDir = new File(srcPath); 1028 File[] srcFiles = srcDir.listFiles(); 1029 if (srcFiles == null) { 1030 return; 1031 } 1032 FileOutputStream fileOut = null; 1033 CheckedOutputStream checkedOut = null; 1034 ZipOutputStream zipOut = null; 1035 1036 try { 1037 String zipPath = destDirPath + LINUX_FILE_SEPARATOR + fileName; 1038 if (!FileUtils.matchPattern(zipPath)) { 1039 throw new BundleException("Input invalid file" + zipPath); 1040 } 1041 File zipFile = new File(zipPath); 1042 fileOut = new FileOutputStream(zipFile); 1043 checkedOut = new CheckedOutputStream(fileOut, new CRC32()); 1044 zipOut = new ZipOutputStream(checkedOut); 1045 for (int i = 0; i < srcFiles.length; i++) { 1046 File srcFile = srcFiles[i]; 1047 if (srcFile.isDirectory()) { 1048 if (srcFile.getPath().toLowerCase(Locale.ENGLISH).endsWith(LIBS_DIR_NAME)) { 1049 compressDirectory(srcFile, "", zipOut, true); 1050 } else { 1051 compressDirectory(srcFile, "", zipOut, false); 1052 } 1053 } else { 1054 if (srcFile.getPath().toLowerCase(Locale.ENGLISH).endsWith(APK_SUFFIX) && 1055 "true".equals(unpackApk)) { 1056 continue; 1057 } 1058 compressFile(srcFile, "", zipOut, false); 1059 } 1060 } 1061 } catch (FileNotFoundException | BundleException exception) { 1062 LOG.error("Uncompress::packFilesByPath " + exception.getMessage()); 1063 throw new BundleException("Pack files by path failed"); 1064 } finally { 1065 Utility.closeStream(zipOut); 1066 Utility.closeStream(checkedOut); 1067 Utility.closeStream(fileOut); 1068 } 1069 } 1070 1071 /** 1072 * compress file directory. 1073 * 1074 * @param dir file directory 1075 * @param baseDir base path for file 1076 * @param zipOut zip outPutStream 1077 * @param isCompression if need compression 1078 * @throws BundleException FileNotFoundException|IOException. 1079 */ compressDirectory(File dir, String baseDir, ZipOutputStream zipOut, boolean isCompression)1080 private static void compressDirectory(File dir, String baseDir, ZipOutputStream zipOut, boolean isCompression) 1081 throws BundleException { 1082 File[] files = dir.listFiles(); 1083 if (files == null) { 1084 return; 1085 } 1086 for (File file : files) { 1087 if (file.isDirectory()) { 1088 compressDirectory(file, baseDir + dir.getName() + File.separator, zipOut, isCompression); 1089 } else { 1090 compressFile(file, baseDir + dir.getName() + File.separator, zipOut, isCompression); 1091 } 1092 } 1093 } 1094 1095 /** 1096 * compress process. 1097 * 1098 * @param srcFile source file to zip 1099 * @param baseDir base path for file 1100 * @param zipOut zip outPutStream 1101 * @param isCompression if need compression 1102 * @throws BundleException FileNotFoundException|IOException. 1103 */ compressFile(File srcFile, String baseDir, ZipOutputStream zipOut, boolean isCompression)1104 private static void compressFile(File srcFile, String baseDir, ZipOutputStream zipOut, boolean isCompression) 1105 throws BundleException { 1106 FileInputStream fileInputStream = null; 1107 BufferedInputStream bufferedInputStream = null; 1108 1109 try { 1110 String entryName = (baseDir + srcFile.getName()).replace(File.separator, LINUX_FILE_SEPARATOR); 1111 ZipEntry zipEntry = new ZipEntry(entryName); 1112 boolean isNeedCompress = isCompression; 1113 if (srcFile.isFile() && srcFile.getName().toLowerCase(Locale.ENGLISH).endsWith(SO_SUFFIX)) { 1114 isNeedCompress = false; 1115 } 1116 if (isNeedCompress) { 1117 zipEntry.setMethod(ZipEntry.DEFLATED); 1118 } else { 1119 zipEntry.setMethod(ZipEntry.STORED); 1120 zipEntry.setCompressedSize(srcFile.length()); 1121 zipEntry.setSize(srcFile.length()); 1122 CRC32 crc = getCrcFromFile(srcFile); 1123 zipEntry.setCrc(crc.getValue()); 1124 } 1125 zipOut.putNextEntry(zipEntry); 1126 byte[] data = new byte[BUFFER_SIZE]; 1127 fileInputStream = new FileInputStream(srcFile); 1128 bufferedInputStream = new BufferedInputStream(fileInputStream); 1129 int count = bufferedInputStream.read(data); 1130 while (count > 0) { 1131 zipOut.write(data, 0, count); 1132 count = bufferedInputStream.read(data); 1133 } 1134 } catch (FileNotFoundException ignored) { 1135 LOG.error("Uncompress::compressFile file not found exception: " + ignored.getMessage()); 1136 throw new BundleException("Compress file failed"); 1137 } catch (IOException exception) { 1138 LOG.error("Uncompress::compressFile io exception: " + exception.getMessage()); 1139 throw new BundleException("Compress file failed"); 1140 } finally { 1141 Utility.closeStream(fileInputStream); 1142 Utility.closeStream(bufferedInputStream); 1143 } 1144 } 1145 1146 /** 1147 * get CRC32 from file. 1148 * 1149 * @param file source file 1150 * @return CRC32 1151 * @throws BundleException FileNotFoundException|IOException. 1152 */ getCrcFromFile(File file)1153 private static CRC32 getCrcFromFile(File file) throws BundleException { 1154 FileInputStream fileInputStream = null; 1155 CRC32 crc = new CRC32(); 1156 try { 1157 fileInputStream = new FileInputStream(file); 1158 byte[] buffer = new byte[BUFFER_SIZE]; 1159 1160 int count = fileInputStream.read(buffer); 1161 while (count > 0) { 1162 crc.update(buffer, 0, count); 1163 count = fileInputStream.read(buffer); 1164 } 1165 } catch (FileNotFoundException ignored) { 1166 LOG.error("Uncompressor::getCrcFromFile file not found exception"); 1167 throw new BundleException("Get Crc from file failed"); 1168 } catch (IOException exception) { 1169 LOG.error("Uncompressor::getCrcFromFile io exception: " + exception.getMessage()); 1170 throw new BundleException("Get Crc from file failed"); 1171 } finally { 1172 Utility.closeStream(fileInputStream); 1173 } 1174 return crc; 1175 } 1176 1177 /** 1178 * delete file 1179 * 1180 * @param file the file to be deleted 1181 */ deleteFile(File file)1182 private static void deleteFile(File file) { 1183 if (file.exists()) { 1184 if (file.isDirectory()) { 1185 File[] files = file.listFiles(); 1186 for (int i = 0; i < files.length; i++) { 1187 deleteFile(files[i]); 1188 } 1189 } 1190 file.delete(); 1191 } 1192 } 1193 1194 /** 1195 * check 1196 * 1197 * @param result the result of parse app all mode 1198 * @return return the result of checkParseAllResult. 1199 */ checkParseAllResult(UncompressResult result)1200 private static UncompressResult checkParseAllResult(UncompressResult result) { 1201 UncompressResult errorResult = new UncompressResult(); 1202 errorResult.setResult(false); 1203 errorResult.setMessage("App package is invalid."); 1204 if (result == null || result.getPackInfos() == null || result.getProfileInfos() == null) { 1205 return errorResult; 1206 } 1207 1208 List<PackInfo> packInfos = result.getPackInfos(); 1209 List<ProfileInfo> profileInfos = result.getProfileInfos(); 1210 int packInfoSize = packInfos.size(); 1211 int profileInfoSize = profileInfos.size(); 1212 if (packInfoSize == 0 || profileInfoSize == 0 || packInfoSize != profileInfoSize) { 1213 LOG.error("Uncompress::checkParseAllResult error, hapNum is invalid in app"); 1214 return errorResult; 1215 } 1216 1217 for (int i = 0; i < packInfoSize; i++) { 1218 if (packInfos.get(i) == null || packInfos.get(i).name.isEmpty()) { 1219 return errorResult; 1220 } 1221 boolean isHave = false; 1222 for (int j = 0; j < profileInfoSize; j++) { 1223 if (profileInfos.get(j) == null || profileInfos.get(j).hapName.isEmpty()) { 1224 return errorResult; 1225 } 1226 if (comparePackAndProfile(packInfos.get(i), profileInfos.get(j))) { 1227 isHave = true; 1228 break; 1229 } 1230 } 1231 if (!isHave) { 1232 return errorResult; 1233 } 1234 } 1235 1236 return result; 1237 } 1238 1239 /** 1240 * get label and icon for application 1241 * 1242 * @param result the result of parse app all mode 1243 * @return return the result which contains icon and label 1244 */ obtainLabelAndIcon(UncompressResult result)1245 private static UncompressResult obtainLabelAndIcon(UncompressResult result) { 1246 List<ProfileInfo> profileInfos = result.getProfileInfos(); 1247 if (profileInfos.isEmpty()) { 1248 return result; 1249 } 1250 for (ProfileInfo profileInfo : profileInfos) { 1251 if (profileInfo == null) { 1252 continue; 1253 } 1254 HapInfo hapInfo = profileInfo.hapInfo; 1255 if (hapInfo == null) { 1256 continue; 1257 } 1258 Distro distro = hapInfo.distro; 1259 if (distro == null) { 1260 continue; 1261 } 1262 String moduleType = distro.moduleType; 1263 if (ENTRY_TYPE.equals(moduleType.toLowerCase(Locale.ENGLISH))) { 1264 return obtainInnerLabelAndIcon(result, hapInfo, distro); 1265 } 1266 } 1267 return result; 1268 } 1269 1270 /** 1271 * get label and icon for application 1272 * 1273 * @param result the result of parse app all mode 1274 * @param hapInfo hap info of entry hap 1275 * @return return the result which contains icon and label 1276 */ obtainInnerLabelAndIcon(UncompressResult result, HapInfo hapInfo, Distro distro)1277 private static UncompressResult obtainInnerLabelAndIcon(UncompressResult result, HapInfo hapInfo, Distro distro) { 1278 List<AbilityInfo> abilities = hapInfo.abilities; 1279 if ((abilities == null) || (abilities.isEmpty())) { 1280 result.setLabel(distro.moduleName); 1281 return result; 1282 } 1283 int size = 0; 1284 for (AbilityInfo info : abilities) { 1285 if (info == null) { 1286 size++; 1287 continue; 1288 } 1289 if ((info.skills == null) || (info.skills.isEmpty())) { 1290 continue; 1291 } 1292 for (SkillInfo skill : info.skills) { 1293 if (skill == null) { 1294 continue; 1295 } 1296 List<String> actions = skill.actions; 1297 List<String> entities = skill.entities; 1298 if ((!actions.isEmpty()) && (actions.contains(SYSTEM_ACTION) || actions.contains(SYSTEM_WANT_HOME))) { 1299 if ((!entities.isEmpty()) && (entities.contains(SYSTEM_ENTITY))) { 1300 result.setLabel(info.label); 1301 result.setIcon(info.icon); 1302 return result; 1303 } 1304 } 1305 } 1306 } 1307 if (size == abilities.size()) { 1308 result.setLabel(distro.moduleName); 1309 return result; 1310 } 1311 for (AbilityInfo info : abilities) { 1312 if (info != null) { 1313 result.setLabel(info.label); 1314 result.setIcon(info.icon); 1315 break; 1316 } 1317 } 1318 return result; 1319 } 1320 1321 isHarmonyProfile(String fileName)1322 private static boolean isHarmonyProfile(String fileName) { 1323 return HARMONY_PROFILE.equals(fileName); 1324 } 1325 isPackInfo(String fileName)1326 private static boolean isPackInfo(String fileName) { 1327 return PACK_INFO.equals(fileName); 1328 } 1329 getHapNameWithoutSuffix(String hapFileName)1330 private static String getHapNameWithoutSuffix(String hapFileName) { 1331 if (hapFileName == null || hapFileName.isEmpty() || hapFileName.lastIndexOf(".") == -1) { 1332 return ""; 1333 } 1334 return hapFileName.substring(0, hapFileName.lastIndexOf(".")); 1335 } 1336 unZipModuleHapFile(String srcPath)1337 private static HapZipInfo unZipModuleHapFile(String srcPath) 1338 throws BundleException, IOException { 1339 HapZipInfo hapZipInfo = new HapZipInfo(); 1340 ZipFile zipFile = null; 1341 try { 1342 File srcFile = new File(srcPath); 1343 zipFile = new ZipFile(srcFile); 1344 getProfileJson(zipFile, hapZipInfo.resourcemMap); 1345 hapZipInfo.setHarmonyProfileJsonStr(FileUtils.getFileStringFromZip(MODULE_JSON, zipFile)); 1346 hapZipInfo.setPackInfoJsonStr(FileUtils.getFileStringFromZip(PACK_INFO, zipFile)); 1347 hapZipInfo.setResDataBytes(getResourceDataFromHap(zipFile)); 1348 hapZipInfo.setHapFileName(getHapNameWithoutSuffix(srcFile.getName())); 1349 } finally { 1350 Utility.closeStream(zipFile); 1351 } 1352 return hapZipInfo; 1353 } 1354 1355 /** 1356 * uncompress from HapZipInfo 1357 * 1358 * @param hapZipInfo hap zip info 1359 * @return the parse moduleResult 1360 * @throws BundleException FileNotFoundException|IOException. 1361 */ uncompressModuleJsonInfo(HapZipInfo hapZipInfo, ModuleResult moduleResult)1362 private static void uncompressModuleJsonInfo(HapZipInfo hapZipInfo, ModuleResult moduleResult) 1363 throws BundleException { 1364 ModuleProfileInfo moduleProfileInfo = JsonUtil.parseModuleProfileInfo(hapZipInfo.getHarmonyProfileJsonStr(), 1365 hapZipInfo.getResDataBytes(), hapZipInfo.getPackInfoJsonStr(), hapZipInfo.getHapFileName(), 1366 hapZipInfo.resourcemMap); 1367 moduleProfileInfo.hapName = hapZipInfo.getHapFileName(); 1368 moduleResult.addModuleProfileInfo(moduleProfileInfo); 1369 moduleResult.moduleProfileStr.add(hapZipInfo.getHarmonyProfileJsonStr()); 1370 } 1371 1372 /** 1373 * uncompress from specified file name 1374 * 1375 * @param deviceType device type 1376 * @param srcPath source file path 1377 * @param fileName uncompress file name 1378 * @return the uncompress result 1379 * @throws BundleException FileNotFoundException|IOException. 1380 */ uncompressModule(String deviceType, String srcPath, String fileName)1381 private static ModuleResult uncompressModule(String deviceType, String srcPath, String fileName) 1382 throws BundleException { 1383 if (srcPath.isEmpty() || fileName.isEmpty()) { 1384 LOG.error("Uncompress::uncompressModule srcPath, fileName is empty!"); 1385 throw new BundleException("uncompressModule failed, srcPath or fileName is empty"); 1386 } 1387 ModuleResult moduleResult = new ModuleResult(); 1388 try { 1389 HapZipInfo hapZipInfo = unZipModuleHapFile(srcPath); 1390 uncompressModuleJsonInfo(hapZipInfo, moduleResult); 1391 if (moduleResult.packInfos.isEmpty() && !hapZipInfo.getPackInfoJsonStr().isEmpty()) { 1392 moduleResult.packInfos = JsonUtil.parsePackInfos(hapZipInfo.getPackInfoJsonStr()); 1393 } 1394 } catch (IOException exception) { 1395 moduleResult.setResult(false); 1396 LOG.error("Uncompress::uncompressModule parseMode is invalid!"); 1397 } 1398 return moduleResult; 1399 } 1400 1401 /** 1402 * uncompress module hap. 1403 * 1404 * @param deviceType indicates the device type of uncompress mode. 1405 * @param srcPath indicates the path type of hap. 1406 * @param fileName indicates json file name. 1407 * @return the uncompress result 1408 */ unCompressModuleHap(String deviceType, String srcPath, String fileName)1409 static UncompressResult unCompressModuleHap(String deviceType, String srcPath, String fileName) 1410 throws BundleException{ 1411 if (srcPath.isEmpty() || fileName.isEmpty()) { 1412 LOG.error("Uncompress::uncompress srcPath, fileName is empty!"); 1413 throw new BundleException("Uncompress failed, srcPath or fileName is empty"); 1414 } 1415 UncompressResult uncomperssResult = new UncompressResult(); 1416 ModuleResult moduleResult = new ModuleResult(); 1417 try { 1418 moduleResult = uncompressModule(deviceType, srcPath, fileName); 1419 ModuleAdaption moduleAdaption = new ModuleAdaption(); 1420 uncomperssResult = moduleAdaption.convertToUncompressResult(moduleResult); 1421 } catch (BundleException ignored) { 1422 LOG.error("Uncompress::uncompressHap Bundle exception"); 1423 uncomperssResult.setResult(false); 1424 uncomperssResult.setMessage("uncompressHap Bundle exception"); 1425 } 1426 return uncomperssResult; 1427 } 1428 /** 1429 * get all resource in profile. 1430 * 1431 * @param zipFile is the hap file 1432 * @return the parse resource result 1433 */ getProfileJson(ZipFile zipFile, HashMap<String, String> resourceMap)1434 static void getProfileJson(ZipFile zipFile, HashMap<String, String> resourceMap) throws BundleException { 1435 try { 1436 final Enumeration<? extends ZipEntry> entries = zipFile.entries(); 1437 while (entries.hasMoreElements()) { 1438 final ZipEntry entry = entries.nextElement(); 1439 if (entry.getName().contains(RESOURCE_PATH)) { 1440 String filePath = entry.getName(); 1441 String fileName = filePath.replaceAll(RESOURCE_PATH, ""); 1442 String fileContent = FileUtils.getFileStringFromZip(filePath, zipFile); 1443 resourceMap.put(fileName, fileContent); 1444 } 1445 } 1446 } catch (IOException e) { 1447 LOG.error("Uncompress::getProfileJson IOException"); 1448 throw new BundleException("Uncompress::getProfileJson failed"); 1449 } 1450 } 1451 1452 /** 1453 * uncompress module hap. 1454 * 1455 * @param deviceType indicates the deviceType of parse hap. 1456 * @param input the InputStream about the app package. 1457 * @param fileName the file name of json file. 1458 * @return the uncompress result 1459 */ uncompressModuleHapByInput(String deviceType, InputStream input, String fileName, String hapName)1460 static UncompressResult uncompressModuleHapByInput(String deviceType, 1461 InputStream input, String fileName, String hapName) { 1462 UncompressResult uncompressResult = new UncompressResult(); 1463 ModuleResult moduleResult = new ModuleResult(); 1464 try { 1465 moduleResult = uncompressModuleByInput(deviceType, input, MODULE_JSON, hapName); 1466 ModuleAdaption moduleAdaption = new ModuleAdaption(); 1467 uncompressResult = moduleAdaption.convertToUncompressResult(moduleResult); 1468 } catch (BundleException ignored) { 1469 LOG.error("Uncompress::uncompressHapByInput Bundle exception"); 1470 uncompressResult.setResult(false); 1471 uncompressResult.setMessage("uncompressHapByInput Bundle exception"); 1472 } 1473 return uncompressResult; 1474 } 1475 1476 /** 1477 * unzip module hap from zip file. 1478 * 1479 * @param input Indicates the InputStream about the package. 1480 * @return Return the uncomperss result of parseHap 1481 */ unZipModuleHapFileFromInputStream(InputStream input)1482 private static HapZipInfo unZipModuleHapFileFromInputStream(InputStream input) throws BundleException { 1483 BufferedInputStream bufIn = null; 1484 ZipInputStream zipIn = null; 1485 BufferedReader bufferedReader = null; 1486 HapZipInfo hapZipInfo = new HapZipInfo(); 1487 try { 1488 ZipEntry entry = null; 1489 bufIn = new BufferedInputStream(input); 1490 zipIn = new ZipInputStream(bufIn); 1491 while ((entry = zipIn.getNextEntry()) != null) { 1492 if (entry.getName().toLowerCase().endsWith(RESOURCE_INDEX)) { 1493 hapZipInfo.setResDataBytes(getByte(zipIn)); 1494 continue; 1495 } 1496 if (isPackInfo(entry.getName())) { 1497 bufferedReader = new BufferedReader(new InputStreamReader(zipIn)); 1498 hapZipInfo.setPackInfoJsonStr(readStringFromInputStream(zipIn, bufferedReader)); 1499 continue; 1500 } 1501 if (MODULE_JSON.equals(entry.getName())) { 1502 bufferedReader = new BufferedReader(new InputStreamReader(zipIn)); 1503 hapZipInfo.setHarmonyProfileJsonStr(readStringFromInputStream(zipIn, bufferedReader)); 1504 } 1505 if (entry.getName().contains(RESOURCE_PATH)) { 1506 bufferedReader = new BufferedReader(new InputStreamReader(zipIn)); 1507 String filePath = entry.getName(); 1508 String fileName = filePath.replaceAll(RESOURCE_PATH, ""); 1509 String fileContent = readStringFromInputStream(zipIn, bufferedReader); 1510 hapZipInfo.pushResourceMap(fileName, fileContent); 1511 } 1512 } 1513 } catch (BundleException | IOException e) { 1514 LOG.error("unZipModuleHapFileFromInputStream failed!"); 1515 throw new BundleException("unZipModuleHapFileFromInputStream failed!"); 1516 } finally { 1517 Utility.closeStream(bufferedReader); 1518 Utility.closeStream(bufIn); 1519 Utility.closeStream(zipIn); 1520 } 1521 return hapZipInfo; 1522 } 1523 1524 /** 1525 * Parse the hap type. 1526 * 1527 * @param hapPath Indicates the hap path. 1528 * @param compressResult Indicates the result of parse hap. 1529 * @return Return the type result of isModuleHap 1530 */ isModuleHap(String hapPath, UncompressResult compressResult)1531 public static boolean isModuleHap(String hapPath, UncompressResult compressResult) { 1532 ZipFile zipFile = null; 1533 try { 1534 zipFile = new ZipFile(new File(hapPath)); 1535 final Enumeration<? extends ZipEntry> entries = zipFile.entries(); 1536 while (entries.hasMoreElements()) { 1537 final ZipEntry entry = entries.nextElement(); 1538 if (MODULE_JSON.equals(entry.getName())) { 1539 return true; 1540 } 1541 } 1542 } catch (FileNotFoundException ignored) { 1543 LOG.error("Uncompress::isModuleHap file not found exception"); 1544 compressResult.setResult(false); 1545 compressResult.setMessage("judge is module failed"); 1546 } catch (IOException exception) { 1547 LOG.error("Uncompress::isModuleHap io exception: " + exception.getMessage()); 1548 compressResult.setResult(false); 1549 compressResult.setMessage("judge is module failed"); 1550 } finally { 1551 Utility.closeStream(zipFile); 1552 } 1553 return false; 1554 } 1555 1556 /** 1557 * Parse the hap type. 1558 * 1559 * @param input Indicates the hap FileInputStream. 1560 * @return Return the type result of isModuleHap. 1561 */ isModuleInput(InputStream input)1562 public static boolean isModuleInput(InputStream input) throws BundleException { 1563 BufferedInputStream bufIn = null; 1564 ZipInputStream zipIn = null; 1565 BufferedReader bufferedReader = null; 1566 try { 1567 ZipEntry entry = null; 1568 bufIn = new BufferedInputStream(input); 1569 zipIn = new ZipInputStream(bufIn); 1570 while((entry = zipIn.getNextEntry()) != null) { 1571 if (entry.getName().toLowerCase().endsWith(MODULE_JSON)) { 1572 return true; 1573 } 1574 } 1575 } catch (IOException ignored) { 1576 LOG.error("Uncompress::isModuleHap judge failed!"); 1577 throw new BundleException("Uncompress::isModuleHap judge failed!"); 1578 } finally { 1579 Utility.closeStream(bufferedReader); 1580 Utility.closeStream(bufIn); 1581 Utility.closeStream(zipIn); 1582 } 1583 return false; 1584 } 1585 1586 /** 1587 * create file output stream from InputStream . 1588 * 1589 * @param stream Indicates the input stream of hap. 1590 * @param file Indicates the temp file to save input stream. 1591 */ writeToTempFile(InputStream stream, File file)1592 static void writeToTempFile(InputStream stream, File file) throws BundleException { 1593 FileOutputStream fileOutputStream = null; 1594 try { 1595 if (file == null) { 1596 LOG.error("file not exist!"); 1597 } 1598 fileOutputStream = new FileOutputStream(file); 1599 int bytesRead = 0; 1600 byte[] buffer = new byte[1024]; 1601 while ((bytesRead = stream.read(buffer)) != -1) { 1602 fileOutputStream.write(buffer, 0, bytesRead); 1603 } 1604 } catch (IOException e) { 1605 LOG.error("writeToTempFile failed!"); 1606 throw new BundleException("writeToTempFile failed!"); 1607 } finally { 1608 Utility.closeStream(fileOutputStream); 1609 } 1610 } 1611 1612 /** 1613 * copy rpcid.sc file. 1614 * 1615 * @param srcFile Indicates the path of hap. 1616 * @param rpcidPath Indicates the output path of rpcid.sc file. 1617 */ getRpcidFromHap(String srcFile, String rpcidPath)1618 static void getRpcidFromHap(String srcFile, String rpcidPath) throws BundleException { 1619 ZipFile zipFile = null; 1620 InputStream inputStream = null; 1621 FileOutputStream outputStream = null; 1622 try { 1623 zipFile = new ZipFile(srcFile); 1624 String filePath = null; 1625 final Enumeration<? extends ZipEntry> entries = zipFile.entries(); 1626 while (entries.hasMoreElements()) { 1627 final ZipEntry entry = entries.nextElement(); 1628 if (RPCID_SC.equals(entry.getName())) { 1629 filePath = entry.getName(); 1630 break; 1631 } 1632 } 1633 if (filePath != null) { 1634 File rpcidFile = new File(rpcidPath, RPCID_SC); 1635 if (rpcidFile.getParentFile() != null && !rpcidFile.getParentFile().exists()) { 1636 rpcidFile.getParentFile().mkdirs(); 1637 } 1638 ZipEntry rpcidEntry = zipFile.getEntry(filePath); 1639 inputStream = zipFile.getInputStream(rpcidEntry); 1640 byte[] buffer = new byte[1024]; 1641 int noBytes = 0; 1642 outputStream = new FileOutputStream(rpcidFile); 1643 while((noBytes = inputStream.read(buffer)) != -1) { 1644 outputStream.write(buffer, 0, noBytes); 1645 } 1646 } else { 1647 LOG.error("Uncompress::getRpcidFromHap hap has no rpcid.sc file"); 1648 throw new BundleException("Uncompress::getRpcidFromHap hap has no rpcid.sc file"); 1649 } 1650 } catch (IOException e) { 1651 LOG.error("Uncompress::getRpcidFromHap IOException " + e.getMessage()); 1652 throw new BundleException("Uncompress::getRpcidFromHap failed"); 1653 } finally { 1654 Utility.closeStream(zipFile); 1655 Utility.closeStream(inputStream); 1656 Utility.closeStream(outputStream); 1657 } 1658 } 1659 1660 /** 1661 * unpacking according to the architecture 1662 * 1663 * @param srcFile Indicates the path of hap or hsp. 1664 * @param outPath Indicates the output path of unpacking target path. 1665 * @param cpuAbiList Indicates the designated cpuAbi. 1666 */ unpackageLibsMode(String srcFile, String outPath, List<String> cpuAbiList)1667 static void unpackageLibsMode(String srcFile, String outPath, List<String> cpuAbiList) throws BundleException { 1668 String normalizedSrcFilePath = srcFile.replace("\\", LINUX_FILE_SEPARATOR); 1669 String normalizedOutFilePath = outPath.replace("\\", LINUX_FILE_SEPARATOR); 1670 String tempDir = normalizedOutFilePath + LINUX_FILE_SEPARATOR + TEMP_PATH; 1671 try { 1672 List<String> cpuAbiListRes = getLibsFromPackageAndUnpackage(normalizedSrcFilePath, tempDir, cpuAbiList); 1673 repackPackage(normalizedSrcFilePath, normalizedOutFilePath, tempDir, cpuAbiListRes); 1674 } catch (BundleException e) { 1675 LOG.error("Uncompress::unpackageLibsMode failed."); 1676 throw new BundleException("Uncompress::unpackageLibsMode failed"); 1677 } finally { 1678 File deleteFile = new File(tempDir); 1679 deleteFile(deleteFile); 1680 } 1681 } 1682 1683 /** 1684 * get libs directory and unpack other files. 1685 * 1686 * @param srcFile Indicates the path of hap or hsp. 1687 * @param tempDirPath Indicates the temporary directory path. 1688 * @param cpuAbiList Indicates the Designated cpuAbi. 1689 */ getLibsFromPackageAndUnpackage(String srcFile, String tempDirPath, List<String> cpuAbiList)1690 static List<String> getLibsFromPackageAndUnpackage(String srcFile, String tempDirPath, List<String> cpuAbiList) 1691 throws BundleException { 1692 try (ZipFile zipFile = new ZipFile(srcFile)) { 1693 final Enumeration<? extends ZipEntry> entries = zipFile.entries(); 1694 Set<String> cpuAbiSetRes = new HashSet<>(); 1695 while (entries.hasMoreElements()) { 1696 final ZipEntry entry = entries.nextElement(); 1697 if (entry.getName().startsWith(LIBS + LINUX_FILE_SEPARATOR)) { 1698 String cpuAbi = entry.getName().substring(LIBS.length() + 1).split(LINUX_FILE_SEPARATOR)[0]; 1699 if (!cpuAbiList.isEmpty() && !cpuAbiList.contains(cpuAbi)) { 1700 continue; 1701 } 1702 cpuAbiSetRes.add(cpuAbi); 1703 File tempFile = new File(tempDirPath, entry.getName().substring(LIBS.length() + 1)); 1704 FileUtils.createParentDir(tempFile); 1705 try (InputStream inputStream = zipFile.getInputStream(entry); 1706 FileOutputStream outputStream = new FileOutputStream(tempFile)) { 1707 FileUtils.copyStream(inputStream, outputStream); 1708 } catch (IOException e) { 1709 LOG.error("Uncompress::getLibsFromPackageAndUnpackage IOException " + e.getMessage()); 1710 throw new BundleException("Uncompress::getLibsFromPackageAndUnpackage failed"); 1711 } 1712 } else { 1713 String tempPath = tempDirPath + LINUX_FILE_SEPARATOR + PACKAGEFILE + LINUX_FILE_SEPARATOR 1714 + entry.getName(); 1715 File destFile = new File(tempPath); 1716 FileUtils.createParentDir(destFile); 1717 dataTransfer(zipFile, entry, destFile); 1718 } 1719 } 1720 if (cpuAbiSetRes.size() != cpuAbiList.size() && !cpuAbiList.isEmpty()) { 1721 List<String> notExistAbi = cpuAbiList.stream() 1722 .filter(item -> !cpuAbiSetRes.contains(item)) 1723 .collect(Collectors.toList()); 1724 LOG.error("The specified abi does not exist, " + notExistAbi); 1725 throw new BundleException("Uncompress::getLibsFromPackageAndUnpackage failed"); 1726 } 1727 if (cpuAbiSetRes.size() > MAX_CPU_ABI_TYPE_NUM && cpuAbiList.isEmpty()) { 1728 LOG.error("Uncompress::getLibsFromPackageAndUnpackage failed: the architecture type exceeds the " + 1729 "limit and must be less than or equal to 128"); 1730 throw new BundleException("Uncompress::getLibsFromPackageAndUnpackage failed"); 1731 } 1732 if (cpuAbiSetRes.isEmpty()) { 1733 LOG.error("Uncompress::getLibsFromPackageAndUnpackage failed: libs has no CPU ABI"); 1734 throw new BundleException("Uncompress::getLibsFromPackageAndUnpackage failed"); 1735 } 1736 return new ArrayList<>(cpuAbiSetRes); 1737 } catch (IOException e) { 1738 LOG.error("Uncompress::getLibsFromPackageAndUnpackage IOException " + e.getMessage()); 1739 throw new BundleException("Uncompress::getLibsFromPackageAndUnpackage failed"); 1740 } 1741 } 1742 1743 /** 1744 * repack Package 1745 * 1746 * @param srcPath source file path 1747 * @param outPath out file path 1748 * @param tempDir temp file name 1749 * @param cpuAbiList cpuAbi list 1750 * @throws BundleException FileNotFoundException|IOException. 1751 */ repackPackage(String srcPath, String outPath, String tempDir, List<String> cpuAbiList)1752 private static void repackPackage(String srcPath, String outPath, String tempDir, List<String> cpuAbiList) 1753 throws BundleException { 1754 File srcDir = new File(tempDir + LINUX_FILE_SEPARATOR + PACKAGEFILE); 1755 File[] srcFiles = srcDir.listFiles(); 1756 if (srcFiles == null) { 1757 return; 1758 } 1759 String[] srcPathItem = srcPath.split(LINUX_FILE_SEPARATOR); 1760 if (srcPathItem.length == 0) { 1761 LOG.error("Uncompress::repackPackage failed: Wrong file path"); 1762 throw new BundleException("Uncompress::repackPackage failed"); 1763 } 1764 String hapName = srcPathItem[srcPathItem.length - 1]; 1765 for (String cpuAbi : cpuAbiList) { 1766 processCpuAbi(outPath, hapName, cpuAbi, srcFiles, tempDir); 1767 } 1768 } 1769 processCpuAbi(String outPath, String hapName, String cpuAbi, File[] srcFiles, String tempDir)1770 private static void processCpuAbi(String outPath, String hapName, String cpuAbi, File[] srcFiles, String tempDir) 1771 throws BundleException { 1772 String targetZipPath = outPath + LINUX_FILE_SEPARATOR + cpuAbi + LINUX_FILE_SEPARATOR + hapName; 1773 File targetZipFile = new File(targetZipPath); 1774 if (targetZipFile.getParentFile() != null && !targetZipFile.getParentFile().exists()) { 1775 targetZipFile.getParentFile().mkdirs(); 1776 } 1777 try (ZipOutputStream targetZipOutputStream = new ZipOutputStream(new FileOutputStream(targetZipPath))) { 1778 compressSourceFiles(srcFiles, targetZipOutputStream); 1779 File libsDir = new File(tempDir + LINUX_FILE_SEPARATOR + cpuAbi); 1780 compressDirectory(libsDir, LIBS + LINUX_FILE_SEPARATOR, targetZipOutputStream, true); 1781 } catch (IOException e) { 1782 LOG.error("Uncompress::processCpuAbi IOException for path: " + targetZipPath + " - " + e.getMessage()); 1783 throw new BundleException("Uncompress::processCpuAbi failed for path: " + targetZipPath); 1784 } 1785 } 1786 compressSourceFiles(File[] srcFiles, ZipOutputStream targetZipOutputStream)1787 private static void compressSourceFiles(File[] srcFiles, ZipOutputStream targetZipOutputStream) 1788 throws IOException, BundleException{ 1789 for (File srcFile : srcFiles) { 1790 if (srcFile.isDirectory()) { 1791 compressDirectory(srcFile, "", targetZipOutputStream, false); 1792 } else { 1793 compressFile(srcFile, "", targetZipOutputStream, false); 1794 } 1795 } 1796 } 1797 1798 /** 1799 * parse resource.index file. 1800 * 1801 * @param srcPath Indicates the path of hap. 1802 */ getResourceFromHap(String srcPath)1803 static List<ResourceIndexResult> getResourceFromHap(String srcPath) throws BundleException, IOException { 1804 ZipFile zipFile = null; 1805 try { 1806 File srcFile = new File(srcPath); 1807 zipFile = new ZipFile(srcFile); 1808 byte[] data = getResourceDataFromHap(zipFile); 1809 return ResourcesParserFactory.createParser(data).getAllDataItem(data); 1810 } finally { 1811 Utility.closeStream(zipFile); 1812 } 1813 } 1814 1815 /** 1816 * uncompress appqf file. 1817 * 1818 * @param utility is the common args for input. 1819 * @throws BundleException if uncompress failed. 1820 */ uncompressAPPQFFile(Utility utility)1821 private static void uncompressAPPQFFile(Utility utility) throws BundleException { 1822 ZipFile zipFile = null; 1823 try { 1824 zipFile = new ZipFile(new File(utility.getAPPQFPath())); 1825 int entriesNum = 0; 1826 for (Enumeration<? extends ZipEntry> entries = zipFile.entries(); entries.hasMoreElements();) { 1827 entriesNum++; 1828 ZipEntry entry = entries.nextElement(); 1829 if (entry == null) { 1830 continue; 1831 } 1832 String filePath = utility.getOutPath() + File.separator + entry.getName(); 1833 if (!FileUtils.matchPattern(filePath)) { 1834 LOG.error("uncompressAPPQFFile: Input invalid file" + filePath); 1835 throw new BundleException("uncompressAPPQFFile: Input invalid file" + filePath); 1836 } 1837 File destFile = new File(filePath); 1838 if (destFile != null && destFile.getParentFile() != null && !destFile.getParentFile().exists()) { 1839 destFile.getParentFile().mkdirs(); 1840 } 1841 dataTransfer(zipFile, entry, destFile); 1842 } 1843 } catch (FileNotFoundException ignored) { 1844 LOG.error("Uncompress::uncompressAPPQFFile file not found exception"); 1845 throw new BundleException("Uncompress::uncompressAPPQFFile file not found"); 1846 } catch (IOException exception) { 1847 LOG.error("Uncompress::uncompressAPPQFFile io exception"); 1848 throw new BundleException("Uncompress::uncompressAPPQFFile io exception"); 1849 } finally { 1850 Utility.closeStream(zipFile); 1851 } 1852 } 1853 1854 /** 1855 * parse appqf file, . 1856 * 1857 * @param appqfPath is the path of appqf file. 1858 * @throws BundleException if uncompress failed. 1859 * @throws IOException if IOException happened. 1860 */ parseAPPQFFile(String appqfPath)1861 public static List<HQFInfo> parseAPPQFFile(String appqfPath) throws BundleException { 1862 List<String> patchList = new ArrayList<>(); 1863 ZipFile zipFile = null; 1864 InputStream stream = null; 1865 ZipInputStream zipInputStream = null; 1866 try { 1867 zipFile = new ZipFile(appqfPath); 1868 Enumeration<? extends ZipEntry> entries = zipFile.entries(); 1869 while (entries.hasMoreElements()) { 1870 ZipEntry appqfEntry = entries.nextElement(); 1871 stream = zipFile.getInputStream(appqfEntry); 1872 if (!appqfEntry.getName().endsWith(HQF_SUFFIX)) { 1873 continue; 1874 } 1875 zipInputStream = new ZipInputStream(stream); 1876 String patchJson = readPatchJson(zipInputStream); 1877 if (patchJson == null) { 1878 continue; 1879 } 1880 patchList.add(patchJson); 1881 } 1882 } catch (IOException e) { 1883 LOG.error("parseAPPQFFile failed!"); 1884 throw new BundleException("parseAPPQFFile failed!"); 1885 } finally { 1886 Utility.closeStream(zipFile); 1887 Utility.closeStream(stream); 1888 Utility.closeStream(zipInputStream); 1889 } 1890 return parsePatchJson(patchList); 1891 } 1892 readPatchJson(ZipInputStream zipInputStream)1893 private static String readPatchJson(ZipInputStream zipInputStream) throws BundleException { 1894 String patchJson = null; 1895 ZipEntry hqfEntry; 1896 try { 1897 while ((hqfEntry = zipInputStream.getNextEntry()) != null) { 1898 if (!PATCH_JSON.equals(hqfEntry.getName())) { 1899 continue; 1900 } 1901 patchJson = new BufferedReader(new InputStreamReader(zipInputStream, 1902 StandardCharsets.UTF_8)).lines().parallel() 1903 .collect(Collectors.joining(System.lineSeparator())); 1904 } 1905 } catch (IOException e) { 1906 LOG.error("readPatchJson failed!"); 1907 throw new BundleException("readPatchJson failed!"); 1908 } 1909 return patchJson; 1910 } 1911 parsePatchJson(List<String> patchList)1912 private static List<HQFInfo> parsePatchJson(List<String> patchList) throws BundleException { 1913 List<HQFInfo> hqfInfoList = new ArrayList<>(); 1914 for (String patchJson : patchList) { 1915 hqfInfoList.add(JsonUtil.parsePatch(patchJson)); 1916 } 1917 return hqfInfoList; 1918 } 1919 comparePackAndProfile(PackInfo packInfo, ProfileInfo profileInfo)1920 private static boolean comparePackAndProfile(PackInfo packInfo, ProfileInfo profileInfo) { 1921 if (profileInfo.hapName.replace(HAP_SUFFIXI, "").equals(packInfo.name.replace(HAP_SUFFIXI, ""))) { 1922 return true; 1923 } 1924 if (profileInfo.hapName.replace(HSP_SUFFIX, "").equals(packInfo.name.replace(HSP_SUFFIX, ""))) { 1925 return true; 1926 } 1927 return false; 1928 } 1929 } 1930