package com.lody.virtual.server.pm.parser; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.ConfigurationInfo; import android.content.pm.FeatureInfo; import android.content.pm.InstrumentationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageParser; import android.content.pm.PermissionGroupInfo; import android.content.pm.PermissionInfo; import android.content.pm.ProviderInfo; import android.content.pm.ServiceInfo; import android.content.pm.Signature; import android.os.Build; import android.os.Parcel; import android.text.TextUtils; import com.lody.virtual.client.core.VirtualCore; import com.lody.virtual.client.fixer.ComponentFixer; import com.lody.virtual.helper.collection.ArrayMap; import com.lody.virtual.helper.compat.PackageParserCompat; import com.lody.virtual.helper.utils.FileUtils; import com.lody.virtual.helper.utils.VLog; import com.lody.virtual.os.VEnvironment; import com.lody.virtual.server.pm.PackageSetting; import com.lody.virtual.server.pm.PackageUserState; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.List; import mirror.android.content.pm.ApplicationInfoL; import mirror.android.content.pm.ApplicationInfoN; /** * @author Lody */ public class PackageParserEx { private static final String TAG = PackageParserEx.class.getSimpleName(); private static final ArrayMap<String, String[]> sSharedLibCache = new ArrayMap<>(); public static VPackage parsePackage(File packageFile) throws Throwable { PackageParser parser = PackageParserCompat.createParser(packageFile); PackageParser.Package p = PackageParserCompat.parsePackage(parser, packageFile, 0); PackageParserCompat.collectCertificates(parser, p, PackageParser.PARSE_IS_SYSTEM); return buildPackageCache(p); } public static VPackage readPackageCache(String packageName) { Parcel p = Parcel.obtain(); try { File cacheFile = VEnvironment.getPackageCacheFile(packageName); FileInputStream is = new FileInputStream(cacheFile); byte[] bytes = FileUtils.toByteArray(is); is.close(); p.unmarshall(bytes, 0, bytes.length); p.setDataPosition(0); if (p.readInt() != 4) { throw new IllegalStateException("Invalid version."); } VPackage pkg = new VPackage(p); addOwner(pkg); return pkg; } catch (Exception e) { e.printStackTrace(); } finally { p.recycle(); } return null; } public static void readSignature(VPackage pkg) { File signatureFile = VEnvironment.getSignatureFile(pkg.packageName); if (!signatureFile.exists()) { return; } Parcel p = Parcel.obtain(); try { FileInputStream fis = new FileInputStream(signatureFile); byte[] bytes = FileUtils.toByteArray(fis); fis.close(); p.unmarshall(bytes, 0, bytes.length); p.setDataPosition(0); pkg.mSignatures = p.createTypedArray(Signature.CREATOR); } catch (IOException e) { e.printStackTrace(); } finally { p.recycle(); } } public static void savePackageCache(VPackage pkg) { final String packageName = pkg.packageName; Parcel p = Parcel.obtain(); try { p.writeInt(4); pkg.writeToParcel(p, 0); FileOutputStream fos = new FileOutputStream(VEnvironment.getPackageCacheFile(packageName)); fos.write(p.marshall()); fos.close(); } catch (Exception e) { e.printStackTrace(); } finally { p.recycle(); } Signature[] signatures = pkg.mSignatures; if (signatures != null) { File signatureFile = VEnvironment.getSignatureFile(packageName); if (signatureFile.exists() && !signatureFile.delete()) { VLog.w(TAG, "Unable to delete the signatures of " + packageName); } p = Parcel.obtain(); try { p.writeTypedArray(signatures, 0); FileUtils.writeParcelToFile(p, signatureFile); } catch (IOException e) { e.printStackTrace(); } finally { p.recycle(); } } } private static VPackage buildPackageCache(PackageParser.Package p) { VPackage cache = new VPackage(); cache.activities = new ArrayList<>(p.activities.size()); cache.services = new ArrayList<>(p.services.size()); cache.receivers = new ArrayList<>(p.receivers.size()); cache.providers = new ArrayList<>(p.providers.size()); cache.instrumentation = new ArrayList<>(p.instrumentation.size()); cache.permissions = new ArrayList<>(p.permissions.size()); cache.permissionGroups = new ArrayList<>(p.permissionGroups.size()); for (PackageParser.Activity activity : p.activities) { cache.activities.add(new VPackage.ActivityComponent(activity)); } for (PackageParser.Service service : p.services) { cache.services.add(new VPackage.ServiceComponent(service)); } for (PackageParser.Activity receiver : p.receivers) { cache.receivers.add(new VPackage.ActivityComponent(receiver)); } for (PackageParser.Provider provider : p.providers) { cache.providers.add(new VPackage.ProviderComponent(provider)); } for (PackageParser.Instrumentation instrumentation : p.instrumentation) { cache.instrumentation.add(new VPackage.InstrumentationComponent(instrumentation)); } cache.requestedPermissions = new ArrayList<>(p.requestedPermissions.size()); cache.requestedPermissions.addAll(p.requestedPermissions); if (mirror.android.content.pm.PackageParser.Package.protectedBroadcasts != null) { List<String> protectedBroadcasts = mirror.android.content.pm.PackageParser.Package.protectedBroadcasts.get(p); if (protectedBroadcasts != null) { cache.protectedBroadcasts = new ArrayList<>(protectedBroadcasts); cache.protectedBroadcasts.addAll(protectedBroadcasts); } } cache.applicationInfo = p.applicationInfo; cache.mSignatures = p.mSignatures; cache.mAppMetaData = p.mAppMetaData; cache.packageName = p.packageName; cache.mPreferredOrder = p.mPreferredOrder; cache.mVersionName = p.mVersionName; cache.mSharedUserId = p.mSharedUserId; cache.mSharedUserLabel = p.mSharedUserLabel; cache.usesLibraries = p.usesLibraries; cache.mVersionCode = p.mVersionCode; cache.mAppMetaData = p.mAppMetaData; cache.configPreferences = p.configPreferences; cache.reqFeatures = p.reqFeatures; addOwner(cache); return cache; } public static void initApplicationInfoBase(PackageSetting ps, VPackage p) { ApplicationInfo ai = p.applicationInfo; ai.flags |= ApplicationInfo.FLAG_HAS_CODE; if (TextUtils.isEmpty(ai.processName)) { ai.processName = ai.packageName; } ai.enabled = true; ai.nativeLibraryDir = ps.libPath; ai.uid = ps.appId; ai.name = ComponentFixer.fixComponentClassName(ps.packageName, ai.name); ai.publicSourceDir = ps.apkPath; ai.sourceDir = ps.apkPath; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { ai.splitSourceDirs = new String[]{ps.apkPath}; ai.splitPublicSourceDirs = ai.splitSourceDirs; ApplicationInfoL.scanSourceDir.set(ai, ai.dataDir); ApplicationInfoL.scanPublicSourceDir.set(ai, ai.dataDir); String hostPrimaryCpuAbi = ApplicationInfoL.primaryCpuAbi.get(VirtualCore.get().getContext().getApplicationInfo()); ApplicationInfoL.primaryCpuAbi.set(ai, hostPrimaryCpuAbi); } if (ps.dependSystem) { String[] sharedLibraryFiles = sSharedLibCache.get(ps.packageName); if (sharedLibraryFiles == null) { PackageManager hostPM = VirtualCore.get().getUnHookPackageManager(); try { ApplicationInfo hostInfo = hostPM.getApplicationInfo(ps.packageName, PackageManager.GET_SHARED_LIBRARY_FILES); sharedLibraryFiles = hostInfo.sharedLibraryFiles; if (sharedLibraryFiles == null) sharedLibraryFiles = new String[0]; sSharedLibCache.put(ps.packageName, sharedLibraryFiles); } catch (PackageManager.NameNotFoundException e) { e.printStackTrace(); } } ai.sharedLibraryFiles = sharedLibraryFiles; } } private static void initApplicationAsUser(ApplicationInfo ai, int userId) { ai.dataDir = VEnvironment.getDataUserPackageDirectory(userId, ai.packageName).getPath(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { ApplicationInfoL.scanSourceDir.set(ai, ai.dataDir); ApplicationInfoL.scanPublicSourceDir.set(ai, ai.dataDir); } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { ApplicationInfoN.deviceEncryptedDataDir.set(ai, ai.dataDir); ApplicationInfoN.deviceProtectedDataDir.set(ai, ai.dataDir); ApplicationInfoN.credentialEncryptedDataDir.set(ai, ai.dataDir); ApplicationInfoN.credentialProtectedDataDir.set(ai, ai.dataDir); } } private static void addOwner(VPackage p) { for (VPackage.ActivityComponent activity : p.activities) { activity.owner = p; for (VPackage.ActivityIntentInfo info : activity.intents) { info.activity = activity; } } for (VPackage.ServiceComponent service : p.services) { service.owner = p; for (VPackage.ServiceIntentInfo info : service.intents) { info.service = service; } } for (VPackage.ActivityComponent receiver : p.receivers) { receiver.owner = p; for (VPackage.ActivityIntentInfo info : receiver.intents) { info.activity = receiver; } } for (VPackage.ProviderComponent provider : p.providers) { provider.owner = p; for (VPackage.ProviderIntentInfo info : provider.intents) { info.provider = provider; } } for (VPackage.InstrumentationComponent instrumentation : p.instrumentation) { instrumentation.owner = p; } for (VPackage.PermissionComponent permission : p.permissions) { permission.owner = p; } for (VPackage.PermissionGroupComponent group : p.permissionGroups) { group.owner = p; } } public static PackageInfo generatePackageInfo(VPackage p, int flags, long firstInstallTime, long lastUpdateTime, PackageUserState state, int userId) { if (!checkUseInstalledOrHidden(state, flags)) { return null; } if (p.mSignatures == null) { readSignature(p); } PackageInfo pi = new PackageInfo(); pi.packageName = p.packageName; pi.versionCode = p.mVersionCode; pi.sharedUserLabel = p.mSharedUserLabel; pi.versionName = p.mVersionName; pi.sharedUserId = p.mSharedUserId; pi.sharedUserLabel = p.mSharedUserLabel; pi.applicationInfo = generateApplicationInfo(p, flags, state, userId); pi.firstInstallTime = firstInstallTime; pi.lastUpdateTime = lastUpdateTime; if ((flags & PackageManager.GET_GIDS) != 0) { pi.gids = PackageParserCompat.GIDS; } if ((flags & PackageManager.GET_CONFIGURATIONS) != 0) { int N = p.configPreferences != null ? p.configPreferences.size() : 0; if (N > 0) { pi.configPreferences = new ConfigurationInfo[N]; p.configPreferences.toArray(pi.configPreferences); } N = p.reqFeatures != null ? p.reqFeatures.size() : 0; if (N > 0) { pi.reqFeatures = new FeatureInfo[N]; p.reqFeatures.toArray(pi.reqFeatures); } } if ((flags & PackageManager.GET_ACTIVITIES) != 0) { final int N = p.activities.size(); if (N > 0) { int num = 0; final ActivityInfo[] res = new ActivityInfo[N]; for (int i = 0; i < N; i++) { final VPackage.ActivityComponent a = p.activities.get(i); res[num++] = generateActivityInfo(a, flags, state, userId); } pi.activities = res; } } if ((flags & PackageManager.GET_RECEIVERS) != 0) { final int N = p.receivers.size(); if (N > 0) { int num = 0; final ActivityInfo[] res = new ActivityInfo[N]; for (int i = 0; i < N; i++) { final VPackage.ActivityComponent a = p.receivers.get(i); res[num++] = generateActivityInfo(a, flags, state, userId); } pi.receivers = res; } } if ((flags & PackageManager.GET_SERVICES) != 0) { final int N = p.services.size(); if (N > 0) { int num = 0; final ServiceInfo[] res = new ServiceInfo[N]; for (int i = 0; i < N; i++) { final VPackage.ServiceComponent s = p.services.get(i); res[num++] = generateServiceInfo(s, flags, state, userId); } pi.services = res; } } if ((flags & PackageManager.GET_PROVIDERS) != 0) { final int N = p.providers.size(); if (N > 0) { int num = 0; final ProviderInfo[] res = new ProviderInfo[N]; for (int i = 0; i < N; i++) { final VPackage.ProviderComponent pr = p.providers.get(i); res[num++] = generateProviderInfo(pr, flags, state, userId); } pi.providers = res; } } if ((flags & PackageManager.GET_INSTRUMENTATION) != 0) { int N = p.instrumentation.size(); if (N > 0) { pi.instrumentation = new InstrumentationInfo[N]; for (int i = 0; i < N; i++) { pi.instrumentation[i] = generateInstrumentationInfo( p.instrumentation.get(i), flags); } } } if ((flags & PackageManager.GET_SIGNATURES) != 0) { int N = (p.mSignatures != null) ? p.mSignatures.length : 0; if (N > 0) { pi.signatures = new Signature[N]; System.arraycopy(p.mSignatures, 0, pi.signatures, 0, N); } } return pi; } public static ApplicationInfo generateApplicationInfo(VPackage p, int flags, PackageUserState state, int userId) { if (p == null) return null; if (!checkUseInstalledOrHidden(state, flags)) { return null; } // Make shallow copy so we can store the metadata/libraries safely ApplicationInfo ai = new ApplicationInfo(p.applicationInfo); if ((flags & PackageManager.GET_META_DATA) != 0) { ai.metaData = p.mAppMetaData; } initApplicationAsUser(ai, userId); return ai; } public static ActivityInfo generateActivityInfo(VPackage.ActivityComponent a, int flags, PackageUserState state, int userId) { if (a == null) return null; if (!checkUseInstalledOrHidden(state, flags)) { return null; } // Make shallow copies so we can store the metadata safely ActivityInfo ai = new ActivityInfo(a.info); if ((flags & PackageManager.GET_META_DATA) != 0 && (a.metaData != null)) { ai.metaData = a.metaData; } ai.applicationInfo = generateApplicationInfo(a.owner, flags, state, userId); return ai; } public static ServiceInfo generateServiceInfo(VPackage.ServiceComponent s, int flags, PackageUserState state, int userId) { if (s == null) return null; if (!checkUseInstalledOrHidden(state, flags)) { return null; } ServiceInfo si = new ServiceInfo(s.info); // Make shallow copies so we can store the metadata safely if ((flags & PackageManager.GET_META_DATA) != 0 && s.metaData != null) { si.metaData = s.metaData; } si.applicationInfo = generateApplicationInfo(s.owner, flags, state, userId); return si; } public static ProviderInfo generateProviderInfo(VPackage.ProviderComponent p, int flags, PackageUserState state, int userId) { if (p == null) return null; if (!checkUseInstalledOrHidden(state, flags)) { return null; } // Make shallow copies so we can store the metadata safely ProviderInfo pi = new ProviderInfo(p.info); if ((flags & PackageManager.GET_META_DATA) != 0 && (p.metaData != null)) { pi.metaData = p.metaData; } if ((flags & PackageManager.GET_URI_PERMISSION_PATTERNS) == 0) { pi.uriPermissionPatterns = null; } pi.applicationInfo = generateApplicationInfo(p.owner, flags, state, userId); return pi; } public static InstrumentationInfo generateInstrumentationInfo( VPackage.InstrumentationComponent i, int flags) { if (i == null) return null; if ((flags & PackageManager.GET_META_DATA) == 0) { return i.info; } InstrumentationInfo ii = new InstrumentationInfo(i.info); ii.metaData = i.metaData; return ii; } public static PermissionInfo generatePermissionInfo( VPackage.PermissionComponent p, int flags) { if (p == null) return null; if ((flags & PackageManager.GET_META_DATA) == 0) { return p.info; } PermissionInfo pi = new PermissionInfo(p.info); pi.metaData = p.metaData; return pi; } public static PermissionGroupInfo generatePermissionGroupInfo( VPackage.PermissionGroupComponent pg, int flags) { if (pg == null) return null; if ((flags & PackageManager.GET_META_DATA) == 0) { return pg.info; } PermissionGroupInfo pgi = new PermissionGroupInfo(pg.info); pgi.metaData = pg.metaData; return pgi; } private static boolean checkUseInstalledOrHidden(PackageUserState state, int flags) { //noinspection deprecation return (state.installed && !state.hidden) || (flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0; } }