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