private void saveSignatures(PackageInfo pkgInfo) { if (pkgInfo != null && pkgInfo.signatures != null) { int i = 0; for (Signature signature : pkgInfo.signatures) { File file = new File(PluginDirHelper.getPluginSignatureFile(mContext, pkgInfo.packageName, i)); try { Utils.writeToFile(file, signature.toByteArray()); Log.i( TAG, "Save %s signature of %s,md5=%s", pkgInfo.packageName, i, Utils.md5(signature.toByteArray())); } catch (Exception e) { e.printStackTrace(); Log.w(TAG, "Save signatures fail", e); file.delete(); Utils.deleteDir(PluginDirHelper.getPluginSignatureDir(mContext, pkgInfo.packageName)); break; } i++; } } }
private void loadAllPlugin(Context context) { long b = System.currentTimeMillis(); ArrayList<File> apkfiles = new ArrayList<File>(); File baseDir = new File(PluginDirHelper.getBaseDir(context)); File[] dirs = baseDir.listFiles(); for (File dir : dirs) { if (dir.isDirectory()) { File file = new File(dir, "apk/base-1.apk"); if (file.exists()) { apkfiles.add(file); } } } Log.i(TAG, "Search apk cost %s ms", (System.currentTimeMillis() - b)); b = System.currentTimeMillis(); if (apkfiles != null && apkfiles.size() > 0) { for (File pluginFile : apkfiles) { long b1 = System.currentTimeMillis(); try { PluginPackageParser pluginPackageParser = new PluginPackageParser(mContext, pluginFile); Signature[] signatures = readSignatures(pluginPackageParser.getPackageName()); if (signatures == null || signatures.length <= 0) { pluginPackageParser.collectCertificates(0); PackageInfo info = pluginPackageParser.getPackageInfo(PackageManager.GET_SIGNATURES); saveSignatures(info); } else { mSignatureCache.put(pluginPackageParser.getPackageName(), signatures); pluginPackageParser.writeSignature(signatures); } if (!mPluginCache.containsKey(pluginPackageParser.getPackageName())) { mPluginCache.put(pluginPackageParser.getPackageName(), pluginPackageParser); } } catch (Throwable e) { Log.e(TAG, "parse a apk file error %s", e, pluginFile.getPath()); } finally { Log.i( TAG, "Parse %s apk cost %s ms", pluginFile.getPath(), (System.currentTimeMillis() - b1)); } } } Log.i(TAG, "Parse all apk cost %s ms", (System.currentTimeMillis() - b)); b = System.currentTimeMillis(); try { mActivityManagerService.onCreate(IPluginManagerImpl.this); } catch (Exception e) { Log.e(TAG, "mActivityManagerService.onCreate", e); } Log.i(TAG, "ActivityManagerService.onCreate %s ms", (System.currentTimeMillis() - b)); }
private Signature[] readSignatures(String packageName) { List<String> fils = PluginDirHelper.getPluginSignatureFiles(mContext, packageName); List<Signature> signatures = new ArrayList<Signature>(fils.size()); int i = 0; for (String file : fils) { try { byte[] data = Utils.readFromFile(new File(file)); if (data != null) { Signature sin = new Signature(data); signatures.add(sin); Log.i( TAG, "Read %s signature of %s,md5=%s", packageName, i, Utils.md5(sin.toByteArray())); } else { Log.i(TAG, "Read %s signature of %s FAIL", packageName, i); return null; } i++; } catch (Exception e) { Log.i(TAG, "Read %s signature of %s FAIL", e, packageName, i); return null; } } return signatures.toArray(new Signature[signatures.size()]); }
@Override public boolean killBackgroundProcesses(String pluginPackageName) throws RemoteException { ActivityManager am = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE); List<RunningAppProcessInfo> infos = am.getRunningAppProcesses(); boolean success = false; for (RunningAppProcessInfo info : infos) { if (info.pkgList != null && Arrays.binarySearch(info.pkgList, pluginPackageName) >= 0 && info.pid != android.os.Process.myPid()) { Log.i( TAG, "killBackgroundProcesses(%s),pkgList=%s,pid=%s", pluginPackageName, Arrays.toString(info.pkgList), info.pid); android.os.Process.killProcess(info.pid); success = true; } } return success; }
@Override public int installPackage(String filepath, int flags) throws RemoteException { // install plugin String apkfile = null; try { PackageManager pm = mContext.getPackageManager(); PackageInfo info = pm.getPackageArchiveInfo(filepath, 0); if (info == null) { return PackageManagerCompat.INSTALL_FAILED_INVALID_APK; } apkfile = PluginDirHelper.getPluginApkFile(mContext, info.packageName); if ((flags & PackageManagerCompat.INSTALL_REPLACE_EXISTING) != 0) { forceStopPackage(info.packageName); if (mPluginCache.containsKey(info.packageName)) { deleteApplicationCacheFiles(info.packageName, null); } new File(apkfile).delete(); Utils.copyFile(filepath, apkfile); PluginPackageParser parser = new PluginPackageParser(mContext, new File(apkfile)); parser.collectCertificates(0); PackageInfo pkgInfo = parser.getPackageInfo(PackageManager.GET_PERMISSIONS | PackageManager.GET_SIGNATURES); if (pkgInfo != null && pkgInfo.requestedPermissions != null && pkgInfo.requestedPermissions.length > 0) { for (String requestedPermission : pkgInfo.requestedPermissions) { boolean b = false; try { b = pm.getPermissionInfo(requestedPermission, 0) != null; } catch (NameNotFoundException e) { } if (!mHostRequestedPermission.contains(requestedPermission) && b) { Log.e(TAG, "No Permission %s", requestedPermission); new File(apkfile).delete(); return PluginManager.INSTALL_FAILED_NO_REQUESTEDPERMISSION; } } } saveSignatures(pkgInfo); // if (pkgInfo.reqFeatures != null && pkgInfo.reqFeatures.length > 0) { // for (FeatureInfo reqFeature : pkgInfo.reqFeatures) { // Log.e(TAG, "reqFeature name=%s,flags=%s,glesVersion=%s", // reqFeature.name, reqFeature.flags, reqFeature.getGlEsVersion()); // } // } copyNativeLibs(mContext, apkfile, parser.getApplicationInfo(0)); dexOpt(mContext, apkfile, parser); mPluginCache.put(parser.getPackageName(), parser); mActivityManagerService.onPkgInstalled(mPluginCache, parser, parser.getPackageName()); sendInstalledBroadcast(info.packageName); return PackageManagerCompat.INSTALL_SUCCEEDED; } else { if (mPluginCache.containsKey(info.packageName)) { return PackageManagerCompat.INSTALL_FAILED_ALREADY_EXISTS; } else { forceStopPackage(info.packageName); new File(apkfile).delete(); Utils.copyFile(filepath, apkfile); PluginPackageParser parser = new PluginPackageParser(mContext, new File(apkfile)); parser.collectCertificates(0); PackageInfo pkgInfo = parser.getPackageInfo(PackageManager.GET_PERMISSIONS | PackageManager.GET_SIGNATURES); if (pkgInfo != null && pkgInfo.requestedPermissions != null && pkgInfo.requestedPermissions.length > 0) { for (String requestedPermission : pkgInfo.requestedPermissions) { boolean b = false; try { b = pm.getPermissionInfo(requestedPermission, 0) != null; } catch (NameNotFoundException e) { } if (!mHostRequestedPermission.contains(requestedPermission) && b) { Log.e(TAG, "No Permission %s", requestedPermission); new File(apkfile).delete(); return PluginManager.INSTALL_FAILED_NO_REQUESTEDPERMISSION; } } } saveSignatures(pkgInfo); // if (pkgInfo.reqFeatures != null && pkgInfo.reqFeatures.length > 0) { // for (FeatureInfo reqFeature : pkgInfo.reqFeatures) { // Log.e(TAG, "reqFeature name=%s,flags=%s,glesVersion=%s", // reqFeature.name, reqFeature.flags, reqFeature.getGlEsVersion()); // } // } copyNativeLibs(mContext, apkfile, parser.getApplicationInfo(0)); dexOpt(mContext, apkfile, parser); mPluginCache.put(parser.getPackageName(), parser); mActivityManagerService.onPkgInstalled(mPluginCache, parser, parser.getPackageName()); sendInstalledBroadcast(info.packageName); return PackageManagerCompat.INSTALL_SUCCEEDED; } } } catch (Exception e) { if (apkfile != null) { new File(apkfile).delete(); } handleException(e); return PackageManagerCompat.INSTALL_FAILED_INTERNAL_ERROR; } }
private void copyNativeLibs(Context context, String apkfile, ApplicationInfo applicationInfo) throws Exception { String nativeLibraryDir = PluginDirHelper.getPluginNativeLibraryDir(context, applicationInfo.packageName); ZipFile zipFile = null; try { zipFile = new ZipFile(apkfile); Enumeration<? extends ZipEntry> entries = zipFile.entries(); Map<String, ZipEntry> libZipEntries = new HashMap<String, ZipEntry>(); Map<String, Set<String>> soList = new HashMap<String, Set<String>>(1); while (entries.hasMoreElements()) { ZipEntry entry = entries.nextElement(); String name = entry.getName(); if (name.contains("../")) { Log.d(TAG, "Path traversal attack prevented"); continue; } if (name.startsWith("lib/") && !entry.isDirectory()) { libZipEntries.put(name, entry); String soName = new File(name).getName(); Set<String> fs = soList.get(soName); if (fs == null) { fs = new TreeSet<String>(); soList.put(soName, fs); } fs.add(name); } } for (String soName : soList.keySet()) { Log.e(TAG, "==========so name=" + soName); Set<String> soPaths = soList.get(soName); String soPath = findSoPath(soPaths); if (soPath != null) { File file = new File(nativeLibraryDir, soName); if (file.exists()) { file.delete(); } InputStream in = null; FileOutputStream ou = null; try { in = zipFile.getInputStream(libZipEntries.get(soPath)); ou = new FileOutputStream(file); byte[] buf = new byte[8192]; int read = 0; while ((read = in.read(buf)) != -1) { ou.write(buf, 0, read); } ou.flush(); ou.getFD().sync(); Log.i(TAG, "copy so(%s) for %s to %s ok!", soName, soPath, file.getPath()); } catch (Exception e) { if (file.exists()) { file.delete(); } throw e; } finally { if (in != null) { try { in.close(); } catch (Exception e) { } } if (ou != null) { try { ou.close(); } catch (Exception e) { } } } } } } finally { if (zipFile != null) { try { zipFile.close(); } catch (Exception e) { } } } }