/* * Copyright (C) 2015 HouKx <hkx.aidream@gmail.com> * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package androidx.pluginmgr; import java.io.File; import java.io.IOException; import java.io.StringReader; import java.util.Enumeration; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.zip.ZipEntry; import java.util.zip.ZipException; import java.util.zip.ZipFile; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlPullParserFactory; import android.content.Context; import android.content.IntentFilter; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; /** * @author HouKangxi * */ class PluginManifestUtil { static void setManifestInfo(Context context, String apkPath, PlugInfo info) throws XmlPullParserException, IOException { ZipFile zipFile = new ZipFile(new File(apkPath), ZipFile.OPEN_READ); ZipEntry manifestXmlEntry = zipFile .getEntry(XmlManifestReader.DEFAULT_XML); String manifestXML = XmlManifestReader.getManifestXMLFromAPK(zipFile, manifestXmlEntry); PackageInfo pkgInfo = context.getPackageManager() .getPackageArchiveInfo( apkPath, PackageManager.GET_ACTIVITIES | PackageManager.GET_RECEIVERS// | PackageManager.GET_PROVIDERS// | PackageManager.GET_META_DATA// | PackageManager.GET_SHARED_LIBRARY_FILES// // | PackageManager.GET_SERVICES// // | PackageManager.GET_SIGNATURES// ); // Log.d("ManifestReader: setManifestInfo", "GET_SHARED_LIBRARY_FILES=" // + pkgInfo.applicationInfo.nativeLibraryDir); info.setPackageInfo(pkgInfo); File libdir = ActivityOverider.getPluginLibDir(info.getId()); try { if (extractLibFile(zipFile, libdir)) { pkgInfo.applicationInfo.nativeLibraryDir = libdir .getAbsolutePath(); } } finally { zipFile.close(); } setAttrs(info, manifestXML); } private static boolean extractLibFile(ZipFile zip, File tardir) throws ZipException, IOException { String defaultArch = "armeabi"; Map<String, List<ZipEntry>> archLibEntries = new HashMap<String, List<ZipEntry>>(); for (Enumeration<? extends ZipEntry> e = zip.entries(); e .hasMoreElements();) { ZipEntry entry = e.nextElement(); String name = entry.getName(); if (name.startsWith("/")) { name = name.substring(1); } if (name.startsWith("lib/")) { if (entry.isDirectory()) { continue; } int sp = name.indexOf('/', 4); String en2add; if (sp > 0) { String osArch = name.substring(4, sp); en2add = osArch.toLowerCase(); } else { en2add = defaultArch; } List<ZipEntry> ents = archLibEntries.get(en2add); if (ents == null) { ents = new LinkedList<ZipEntry>(); archLibEntries.put(en2add, ents); } ents.add(entry); } } String arch = System.getProperty("os.arch"); List<ZipEntry> libEntries = archLibEntries.get(arch.toLowerCase()); if (libEntries == null) { libEntries = archLibEntries.get(defaultArch); } boolean hasLib = false; if (libEntries != null) { hasLib = true; if (!tardir.exists()) { tardir.mkdirs(); } for (ZipEntry libEntry : libEntries) { String ename = libEntry.getName(); String pureName = ename.substring(ename.lastIndexOf('/') + 1); File target = new File(tardir, pureName); FileUtil.writeToFile(zip.getInputStream(libEntry), target); } } return hasLib; } private static void setAttrs(PlugInfo info, String manifestXML) throws XmlPullParserException, IOException { XmlPullParserFactory factory = XmlPullParserFactory.newInstance(); factory.setNamespaceAware(true); XmlPullParser parser = factory.newPullParser(); parser.setInput(new StringReader(manifestXML)); int eventType = parser.getEventType(); String namespaceAndroid = null; do { switch (eventType) { case XmlPullParser.START_DOCUMENT: { break; } case XmlPullParser.START_TAG: { String tag = parser.getName(); if (tag.equals("manifest")) { namespaceAndroid = parser.getNamespace("android"); } else if ("activity".equals(parser.getName())) { addActivity(info, namespaceAndroid, parser); } else if ("receiver".equals(parser.getName())) { addReceiver(info, namespaceAndroid, parser); } else if ("service".equals(parser.getName())) { addService(info, namespaceAndroid, parser); } else if ("application".equals(parser.getName())) { parseApplicationInfo(info, namespaceAndroid, parser); } break; } case XmlPullParser.END_TAG: { break; } } eventType = parser.next(); } while (eventType != XmlPullParser.END_DOCUMENT); } private static void parseApplicationInfo(PlugInfo info, String namespace, XmlPullParser parser) throws XmlPullParserException, IOException { String applicationName = parser.getAttributeValue(namespace, "name"); String packageName = info.getPackageInfo().packageName; ApplicationInfo applicationInfo = info.getPackageInfo().applicationInfo; applicationInfo.name = getName(applicationName, packageName); } private static void addActivity(PlugInfo info, String namespace, XmlPullParser parser) throws XmlPullParserException, IOException { int eventType = parser.getEventType(); String activityName = parser.getAttributeValue(namespace, "name"); String packageName = info.getPackageInfo().packageName; activityName = getName(activityName, packageName); ResolveInfo act = new ResolveInfo(); act.activityInfo = info.findActivityByClassName(activityName); do { switch (eventType) { case XmlPullParser.START_TAG: { String tag = parser.getName(); if ("intent-filter".equals(tag)) { if (act.filter == null) { act.filter = new IntentFilter(); } } else if ("action".equals(tag)) { String actionName = parser.getAttributeValue(namespace, "name"); act.filter.addAction(actionName); } else if ("category".equals(tag)) { String category = parser.getAttributeValue(namespace, "name"); act.filter.addCategory(category); } else if ("data".equals(tag)) { // TODO parse data } break; } } eventType = parser.next(); } while (!"activity".equals(parser.getName())); // info.addActivity(act); } private static void addService(PlugInfo info, String namespace, XmlPullParser parser) throws XmlPullParserException, IOException { int eventType = parser.getEventType(); String serviceName = parser.getAttributeValue(namespace, "name"); String packageName = info.getPackageInfo().packageName; serviceName = getName(serviceName, packageName); ResolveInfo service = new ResolveInfo(); service.serviceInfo = info.findServiceByClassName(serviceName); do { switch (eventType) { case XmlPullParser.START_TAG: { String tag = parser.getName(); if ("intent-filter".equals(tag)) { if (service.filter == null) { service.filter = new IntentFilter(); } } else if ("action".equals(tag)) { String actionName = parser.getAttributeValue(namespace, "name"); service.filter.addAction(actionName); } else if ("category".equals(tag)) { String category = parser.getAttributeValue(namespace, "name"); service.filter.addCategory(category); } else if ("data".equals(tag)) { // TODO parse data } break; } } eventType = parser.next(); } while (!"service".equals(parser.getName())); // info.addService(service); } private static void addReceiver(PlugInfo info, String namespace, XmlPullParser parser) throws XmlPullParserException, IOException { int eventType = parser.getEventType(); String receiverName = parser.getAttributeValue(namespace, "name"); String packageName = info.getPackageInfo().packageName; receiverName = getName(receiverName, packageName); ResolveInfo receiver = new ResolveInfo(); // 此时的activityInfo 表示 receiverInfo receiver.activityInfo = info.findReceiverByClassName(receiverName); do { switch (eventType) { case XmlPullParser.START_TAG: { String tag = parser.getName(); if ("intent-filter".equals(tag)) { if (receiver.filter == null) { receiver.filter = new IntentFilter(); } } else if ("action".equals(tag)) { String actionName = parser.getAttributeValue(namespace, "name"); receiver.filter.addAction(actionName); } else if ("category".equals(tag)) { String category = parser.getAttributeValue(namespace, "name"); receiver.filter.addCategory(category); } else if ("data".equals(tag)) { // TODO parse data } break; } } eventType = parser.next(); } while (!"receiver".equals(parser.getName())); // info.addReceiver(receiver); } private static String getName(String nameOrig, String pkgName) { if (nameOrig == null) { return null; } StringBuilder sb = null; if (nameOrig.startsWith(".")) { sb = new StringBuilder(); sb.append(pkgName); sb.append(nameOrig); } else if (!nameOrig.contains(".")) { sb = new StringBuilder(); sb.append(pkgName); sb.append('.'); sb.append(nameOrig); } else { return nameOrig; } return sb.toString(); } }