package com.lody.virtual.server.pm; import android.content.Intent; import android.net.Uri; import android.os.Build; import android.os.RemoteCallbackList; import android.os.RemoteException; import com.lody.virtual.client.core.InstallStrategy; import com.lody.virtual.client.core.VirtualCore; import com.lody.virtual.client.env.VirtualRuntime; import com.lody.virtual.client.hook.secondary.GmsSupport; import com.lody.virtual.client.stub.StubManifest; import com.lody.virtual.helper.collection.IntArray; import com.lody.virtual.helper.compat.NativeLibraryHelperCompat; import com.lody.virtual.helper.utils.ArrayUtils; import com.lody.virtual.helper.utils.FileUtils; import com.lody.virtual.helper.utils.VLog; import com.lody.virtual.os.VEnvironment; import com.lody.virtual.os.VUserHandle; import com.lody.virtual.remote.InstallResult; import com.lody.virtual.remote.InstalledAppInfo; import com.lody.virtual.server.IAppManager; import com.lody.virtual.server.accounts.VAccountManagerService; import com.lody.virtual.server.am.BroadcastSystem; import com.lody.virtual.server.am.UidSystem; import com.lody.virtual.server.am.VActivityManagerService; import com.lody.virtual.server.interfaces.IAppRequestListener; import com.lody.virtual.server.interfaces.IPackageObserver; import com.lody.virtual.server.pm.parser.PackageParserEx; import com.lody.virtual.server.pm.parser.VPackage; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.concurrent.atomic.AtomicReference; /** * @author Lody */ public class VAppManagerService extends IAppManager.Stub { private static final String TAG = VAppManagerService.class.getSimpleName(); private static final AtomicReference<VAppManagerService> sService = new AtomicReference<>(); private final UidSystem mUidSystem = new UidSystem(); private final PackagePersistenceLayer mPersistenceLayer = new PackagePersistenceLayer(this); private final Set<String> mVisibleOutsidePackages = new HashSet<>(); private boolean mBooting; private RemoteCallbackList<IPackageObserver> mRemoteCallbackList = new RemoteCallbackList<>(); private IAppRequestListener mAppRequestListener; public static VAppManagerService get() { return sService.get(); } public static void systemReady() { VEnvironment.systemReady(); VAppManagerService instance = new VAppManagerService(); instance.mUidSystem.initUidList(); sService.set(instance); } public boolean isBooting() { return mBooting; } @Override public void scanApps() { if (mBooting) { return; } synchronized (this) { mBooting = true; mPersistenceLayer.read(); if (StubManifest.ENABLE_GMS && !GmsSupport.isGoogleFrameworkInstalled()) { GmsSupport.installGms(0); } mBooting = false; } } private void cleanUpResidualFiles(PackageSetting ps) { File dataAppDir = VEnvironment.getDataAppPackageDirectory(ps.packageName); FileUtils.deleteDir(dataAppDir); for (int userId : VUserManagerService.get().getUserIds()) { FileUtils.deleteDir(VEnvironment.getDataUserPackageDirectory(userId, ps.packageName)); } } synchronized void loadPackage(PackageSetting setting) { if (!loadPackageInnerLocked(setting)) { cleanUpResidualFiles(setting); } } private boolean loadPackageInnerLocked(PackageSetting ps) { if (ps.dependSystem) { if (!VirtualCore.get().isOutsideInstalled(ps.packageName)) { return false; } } File cacheFile = VEnvironment.getPackageCacheFile(ps.packageName); VPackage pkg = null; try { pkg = PackageParserEx.readPackageCache(ps.packageName); } catch (Throwable e) { e.printStackTrace(); } if (pkg == null || pkg.packageName == null) { return false; } chmodPackageDictionary(cacheFile); PackageCacheManager.put(pkg, ps); BroadcastSystem.get().startApp(pkg); return true; } @Override public boolean isOutsidePackageVisible(String pkg) { return pkg != null && mVisibleOutsidePackages.contains(pkg); } @Override public void addVisibleOutsidePackage(String pkg) { if (pkg != null) { mVisibleOutsidePackages.add(pkg); } } @Override public void removeVisibleOutsidePackage(String pkg) { if (pkg != null) { mVisibleOutsidePackages.remove(pkg); } } @Override public InstallResult installPackage(String path, int flags) { return installPackage(path, flags, true); } public synchronized InstallResult installPackage(String path, int flags, boolean notify) { long installTime = System.currentTimeMillis(); if (path == null) { return InstallResult.makeFailure("path = NULL"); } boolean artFlyMode = VirtualRuntime.isArt() && (flags & InstallStrategy.ART_FLY_MODE) != 0; File packageFile = new File(path); if (!packageFile.exists() || !packageFile.isFile()) { return InstallResult.makeFailure("Package File is not exist."); } VPackage pkg = null; try { pkg = PackageParserEx.parsePackage(packageFile); } catch (Throwable e) { e.printStackTrace(); } if (pkg == null || pkg.packageName == null) { return InstallResult.makeFailure("Unable to parse the package."); } InstallResult res = new InstallResult(); res.packageName = pkg.packageName; // PackageCache holds all packages, try to check if we need to update. VPackage existOne = PackageCacheManager.get(pkg.packageName); PackageSetting existSetting = existOne != null ? (PackageSetting) existOne.mExtras : null; if (existOne != null) { if ((flags & InstallStrategy.IGNORE_NEW_VERSION) != 0) { res.isUpdate = true; return res; } if (!canUpdate(existOne, pkg, flags)) { return InstallResult.makeFailure("Not allowed to update the package."); } res.isUpdate = true; } File appDir = VEnvironment.getDataAppPackageDirectory(pkg.packageName); File libDir = new File(appDir, "lib"); if (res.isUpdate) { FileUtils.deleteDir(libDir); VEnvironment.getOdexFile(pkg.packageName).delete(); VActivityManagerService.get().killAppByPkg(pkg.packageName, VUserHandle.USER_ALL); } if (!libDir.exists() && !libDir.mkdirs()) { return InstallResult.makeFailure("Unable to create lib dir."); } boolean dependSystem = (flags & InstallStrategy.DEPEND_SYSTEM_IF_EXIST) != 0 && VirtualCore.get().isOutsideInstalled(pkg.packageName); if (existSetting != null && existSetting.dependSystem) { dependSystem = false; } NativeLibraryHelperCompat.copyNativeBinaries(new File(path), libDir); if (!dependSystem) { File privatePackageFile = new File(appDir, "base.apk"); File parentFolder = privatePackageFile.getParentFile(); if (!parentFolder.exists() && !parentFolder.mkdirs()) { VLog.w(TAG, "Warning: unable to create folder : " + privatePackageFile.getPath()); } else if (privatePackageFile.exists() && !privatePackageFile.delete()) { VLog.w(TAG, "Warning: unable to delete file : " + privatePackageFile.getPath()); } try { FileUtils.copyFile(packageFile, privatePackageFile); } catch (IOException e) { privatePackageFile.delete(); return InstallResult.makeFailure("Unable to copy the package file."); } packageFile = privatePackageFile; } if (existOne != null) { PackageCacheManager.remove(pkg.packageName); } chmodPackageDictionary(packageFile); PackageSetting ps; if (existSetting != null) { ps = existSetting; } else { ps = new PackageSetting(); } ps.artFlyMode = artFlyMode; ps.dependSystem = dependSystem; ps.apkPath = packageFile.getPath(); ps.libPath = libDir.getPath(); ps.packageName = pkg.packageName; ps.appId = VUserHandle.getAppId(mUidSystem.getOrCreateUid(pkg)); if (res.isUpdate) { ps.lastUpdateTime = installTime; } else { ps.firstInstallTime = installTime; ps.lastUpdateTime = installTime; for (int userId : VUserManagerService.get().getUserIds()) { boolean installed = userId == 0; ps.setUserState(userId, false/*launched*/, false/*hidden*/, installed); } } PackageParserEx.savePackageCache(pkg); PackageCacheManager.put(pkg, ps); mPersistenceLayer.save(); BroadcastSystem.get().startApp(pkg); if (notify) { notifyAppInstalled(ps, -1); } res.isSuccess = true; return res; } @Override public synchronized boolean installPackageAsUser(int userId, String packageName) { if (VUserManagerService.get().exists(userId)) { PackageSetting ps = PackageCacheManager.getSetting(packageName); if (ps != null) { if (!ps.isInstalled(userId)) { ps.setInstalled(userId, true); notifyAppInstalled(ps, userId); mPersistenceLayer.save(); return true; } } } return false; } private void chmodPackageDictionary(File packageFile) { try { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { if (FileUtils.isSymlink(packageFile)) { return; } FileUtils.chmod(packageFile.getParentFile().getAbsolutePath(), FileUtils.FileMode.MODE_755); FileUtils.chmod(packageFile.getAbsolutePath(), FileUtils.FileMode.MODE_755); } } catch (Exception e) { e.printStackTrace(); } } private boolean canUpdate(VPackage existOne, VPackage newOne, int flags) { if ((flags & InstallStrategy.COMPARE_VERSION) != 0) { if (existOne.mVersionCode < newOne.mVersionCode) { return true; } } if ((flags & InstallStrategy.TERMINATE_IF_EXIST) != 0) { return false; } if ((flags & InstallStrategy.UPDATE_IF_EXIST) != 0) { return true; } return false; } @Override public synchronized boolean uninstallPackage(String packageName) { PackageSetting ps = PackageCacheManager.getSetting(packageName); if (ps != null) { uninstallPackageFully(ps); return true; } return false; } @Override public synchronized boolean uninstallPackageAsUser(String packageName, int userId) { if (!VUserManagerService.get().exists(userId)) { return false; } PackageSetting ps = PackageCacheManager.getSetting(packageName); if (ps != null) { int[] userIds = getPackageInstalledUsers(packageName); if (!ArrayUtils.contains(userIds, userId)) { return false; } if (userIds.length == 1) { uninstallPackageFully(ps); } else { // Just hidden it VActivityManagerService.get().killAppByPkg(packageName, userId); ps.setInstalled(userId, false); notifyAppUninstalled(ps, userId); mPersistenceLayer.save(); FileUtils.deleteDir(VEnvironment.getDataUserPackageDirectory(userId, packageName)); } return true; } return false; } private void uninstallPackageFully(PackageSetting ps) { String packageName = ps.packageName; try { BroadcastSystem.get().stopApp(packageName); VActivityManagerService.get().killAppByPkg(packageName, VUserHandle.USER_ALL); VEnvironment.getPackageResourcePath(packageName).delete(); FileUtils.deleteDir(VEnvironment.getDataAppPackageDirectory(packageName)); VEnvironment.getOdexFile(packageName).delete(); for (int id : VUserManagerService.get().getUserIds()) { FileUtils.deleteDir(VEnvironment.getDataUserPackageDirectory(id, packageName)); } PackageCacheManager.remove(packageName); } catch (Exception e) { e.printStackTrace(); } finally { notifyAppUninstalled(ps, -1); } } @Override public int[] getPackageInstalledUsers(String packageName) { PackageSetting ps = PackageCacheManager.getSetting(packageName); if (ps != null) { IntArray installedUsers = new IntArray(5); int[] userIds = VUserManagerService.get().getUserIds(); for (int userId : userIds) { if (ps.readUserState(userId).installed) { installedUsers.add(userId); } } return installedUsers.getAll(); } return new int[0]; } @Override public List<InstalledAppInfo> getInstalledApps(int flags) { List<InstalledAppInfo> infoList = new ArrayList<>(getInstalledAppCount()); for (VPackage p : PackageCacheManager.PACKAGE_CACHE.values()) { PackageSetting setting = (PackageSetting) p.mExtras; infoList.add(setting.getAppInfo()); } return infoList; } @Override public List<InstalledAppInfo> getInstalledAppsAsUser(int userId, int flags) { List<InstalledAppInfo> infoList = new ArrayList<>(getInstalledAppCount()); for (VPackage p : PackageCacheManager.PACKAGE_CACHE.values()) { PackageSetting setting = (PackageSetting) p.mExtras; boolean visible = setting.isInstalled(userId); if ((flags & VirtualCore.GET_HIDDEN_APP) == 0 && setting.isHidden(userId)) { visible = false; } if (visible) { infoList.add(setting.getAppInfo()); } } return infoList; } @Override public int getInstalledAppCount() { return PackageCacheManager.PACKAGE_CACHE.size(); } @Override public boolean isAppInstalled(String packageName) { return packageName != null && PackageCacheManager.PACKAGE_CACHE.containsKey(packageName); } @Override public boolean isAppInstalledAsUser(int userId, String packageName) { if (packageName == null || !VUserManagerService.get().exists(userId)) { return false; } PackageSetting setting = PackageCacheManager.getSetting(packageName); if (setting == null) { return false; } return setting.isInstalled(userId); } private void notifyAppInstalled(PackageSetting setting, int userId) { final String pkg = setting.packageName; int N = mRemoteCallbackList.beginBroadcast(); while (N-- > 0) { try { if (userId == -1) { sendInstalledBroadcast(pkg); mRemoteCallbackList.getBroadcastItem(N).onPackageInstalled(pkg); mRemoteCallbackList.getBroadcastItem(N).onPackageInstalledAsUser(0, pkg); } else { mRemoteCallbackList.getBroadcastItem(N).onPackageInstalledAsUser(userId, pkg); } } catch (RemoteException e) { e.printStackTrace(); } } mRemoteCallbackList.finishBroadcast(); VAccountManagerService.get().refreshAuthenticatorCache(null); } private void notifyAppUninstalled(PackageSetting setting, int userId) { final String pkg = setting.packageName; int N = mRemoteCallbackList.beginBroadcast(); while (N-- > 0) { try { if (userId == -1) { sendUninstalledBroadcast(pkg); mRemoteCallbackList.getBroadcastItem(N).onPackageUninstalled(pkg); mRemoteCallbackList.getBroadcastItem(N).onPackageUninstalledAsUser(0, pkg); } else { mRemoteCallbackList.getBroadcastItem(N).onPackageUninstalledAsUser(userId, pkg); } } catch (RemoteException e) { e.printStackTrace(); } } mRemoteCallbackList.finishBroadcast(); VAccountManagerService.get().refreshAuthenticatorCache(null); } private void sendInstalledBroadcast(String packageName) { Intent intent = new Intent(Intent.ACTION_PACKAGE_ADDED); intent.setData(Uri.parse("package:" + packageName)); VActivityManagerService.get().sendBroadcastAsUser(intent, VUserHandle.ALL); } private void sendUninstalledBroadcast(String packageName) { Intent intent = new Intent(Intent.ACTION_PACKAGE_REMOVED); intent.setData(Uri.parse("package:" + packageName)); VActivityManagerService.get().sendBroadcastAsUser(intent, VUserHandle.ALL); } @Override public void registerObserver(IPackageObserver observer) { try { mRemoteCallbackList.register(observer); } catch (Throwable e) { e.printStackTrace(); } } @Override public void unregisterObserver(IPackageObserver observer) { try { mRemoteCallbackList.unregister(observer); } catch (Throwable e) { e.printStackTrace(); } } @Override public IAppRequestListener getAppRequestListener() { return mAppRequestListener; } @Override public void setAppRequestListener(final IAppRequestListener listener) { this.mAppRequestListener = listener; if (listener != null) { try { listener.asBinder().linkToDeath(new DeathRecipient() { @Override public void binderDied() { listener.asBinder().unlinkToDeath(this, 0); VAppManagerService.this.mAppRequestListener = null; } }, 0); } catch (RemoteException e) { e.printStackTrace(); } } } @Override public void clearAppRequestListener() { this.mAppRequestListener = null; } @Override public InstalledAppInfo getInstalledAppInfo(String packageName, int flags) { synchronized (PackageCacheManager.class) { if (packageName != null) { PackageSetting setting = PackageCacheManager.getSetting(packageName); if (setting != null) { return setting.getAppInfo(); } } return null; } } public boolean isPackageLaunched(int userId, String packageName) { PackageSetting ps = PackageCacheManager.getSetting(packageName); return ps != null && ps.isLaunched(userId); } public void setPackageHidden(int userId, String packageName, boolean hidden) { PackageSetting ps = PackageCacheManager.getSetting(packageName); if (ps != null && VUserManagerService.get().exists(userId)) { ps.setHidden(userId, hidden); mPersistenceLayer.save(); } } public int getAppId(String packageName) { PackageSetting setting = PackageCacheManager.getSetting(packageName); return setting != null ? setting.appId : -1; } void restoreFactoryState() { VLog.w(TAG, "Warning: Restore the factory state..."); VEnvironment.getDalvikCacheDirectory().delete(); VEnvironment.getUserSystemDirectory().delete(); VEnvironment.getDataAppDirectory().delete(); } public void savePersistenceData() { mPersistenceLayer.save(); } }