Fix uninstall (#588)

* Fix uninstall

* Bump version again

* Add installExistingPackageAsUser

* Drop INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS

* Fix activation

* 反了

* 空格

Co-authored-by: Wang Han <wanghan1995315@gmail.com>
Co-authored-by: LoveSy <shana@zju.edu.cn>
This commit is contained in:
vvb2060 2021-05-15 20:46:14 +08:00 committed by GitHub
parent 3a7b4c9705
commit 5ec10c89bb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 99 additions and 64 deletions

View File

@ -1,7 +1,7 @@
-keep class org.lsposed.manager.Constants { -keep class org.lsposed.manager.Constants {
public static void showErrorToast(int); public static void showErrorToast(int);
} }
-keepclasseswithmembers class org.lsposed.manager.receivers.LSPosedManagerServiceClient { -keepclasseswithmembers class org.lsposed.manager.receivers.LSPManagerServiceClient {
private static android.os.IBinder binder; private static android.os.IBinder binder;
} }

View File

@ -28,7 +28,7 @@ import android.util.Log;
import org.lsposed.lspd.Application; import org.lsposed.lspd.Application;
import org.lsposed.lspd.utils.ParceledListSlice; import org.lsposed.lspd.utils.ParceledListSlice;
import org.lsposed.manager.adapters.ScopeAdapter; import org.lsposed.manager.adapters.ScopeAdapter;
import org.lsposed.manager.receivers.LSPosedManagerServiceClient; import org.lsposed.manager.receivers.LSPManagerServiceClient;
import java.io.File; import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
@ -40,7 +40,7 @@ public class ConfigManager {
public static int getXposedApiVersion() { public static int getXposedApiVersion() {
try { try {
return LSPosedManagerServiceClient.getXposedApiVersion(); return LSPManagerServiceClient.getXposedApiVersion();
} catch (RemoteException | NullPointerException e) { } catch (RemoteException | NullPointerException e) {
Log.e(App.TAG, Log.getStackTraceString(e)); Log.e(App.TAG, Log.getStackTraceString(e));
return -1; return -1;
@ -49,7 +49,7 @@ public class ConfigManager {
public static String getXposedVersionName() { public static String getXposedVersionName() {
try { try {
return LSPosedManagerServiceClient.getXposedVersionName(); return LSPManagerServiceClient.getXposedVersionName();
} catch (RemoteException | NullPointerException e) { } catch (RemoteException | NullPointerException e) {
Log.e(App.TAG, Log.getStackTraceString(e)); Log.e(App.TAG, Log.getStackTraceString(e));
return null; return null;
@ -58,7 +58,7 @@ public class ConfigManager {
public static int getXposedVersionCode() { public static int getXposedVersionCode() {
try { try {
return LSPosedManagerServiceClient.getXposedVersionCode(); return LSPManagerServiceClient.getXposedVersionCode();
} catch (RemoteException | NullPointerException e) { } catch (RemoteException | NullPointerException e) {
Log.e(App.TAG, Log.getStackTraceString(e)); Log.e(App.TAG, Log.getStackTraceString(e));
return -1; return -1;
@ -68,7 +68,7 @@ public class ConfigManager {
public static List<PackageInfo> getInstalledPackagesFromAllUsers(int flags, boolean filterNoProcess) { public static List<PackageInfo> getInstalledPackagesFromAllUsers(int flags, boolean filterNoProcess) {
List<PackageInfo> list = new ArrayList<>(); List<PackageInfo> list = new ArrayList<>();
try { try {
list.addAll(LSPosedManagerServiceClient.getInstalledPackagesFromAllUsers(flags, filterNoProcess)); list.addAll(LSPManagerServiceClient.getInstalledPackagesFromAllUsers(flags, filterNoProcess));
} catch (RemoteException | NullPointerException e) { } catch (RemoteException | NullPointerException e) {
Log.e(App.TAG, Log.getStackTraceString(e)); Log.e(App.TAG, Log.getStackTraceString(e));
} }
@ -77,7 +77,7 @@ public class ConfigManager {
public static String[] getEnabledModules() { public static String[] getEnabledModules() {
try { try {
return LSPosedManagerServiceClient.enabledModules(); return LSPManagerServiceClient.enabledModules();
} catch (RemoteException | NullPointerException e) { } catch (RemoteException | NullPointerException e) {
Log.e(App.TAG, Log.getStackTraceString(e)); Log.e(App.TAG, Log.getStackTraceString(e));
return new String[0]; return new String[0];
@ -86,7 +86,7 @@ public class ConfigManager {
public static boolean setModuleEnabled(String packageName, boolean enable) { public static boolean setModuleEnabled(String packageName, boolean enable) {
try { try {
return enable ? LSPosedManagerServiceClient.enableModule(packageName) : LSPosedManagerServiceClient.disableModule(packageName); return enable ? LSPManagerServiceClient.enableModule(packageName) : LSPManagerServiceClient.disableModule(packageName);
} catch (RemoteException | NullPointerException e) { } catch (RemoteException | NullPointerException e) {
Log.e(App.TAG, Log.getStackTraceString(e)); Log.e(App.TAG, Log.getStackTraceString(e));
return false; return false;
@ -102,7 +102,7 @@ public class ConfigManager {
app.packageName = application.packageName; app.packageName = application.packageName;
list.add(app); list.add(app);
}); });
return LSPosedManagerServiceClient.setModuleScope(packageName, new ParceledListSlice<>(list)); return LSPManagerServiceClient.setModuleScope(packageName, new ParceledListSlice<>(list));
} catch (RemoteException | NullPointerException e) { } catch (RemoteException | NullPointerException e) {
Log.e(App.TAG, Log.getStackTraceString(e)); Log.e(App.TAG, Log.getStackTraceString(e));
return false; return false;
@ -112,7 +112,7 @@ public class ConfigManager {
public static List<ScopeAdapter.ApplicationWithEquals> getModuleScope(String packageName) { public static List<ScopeAdapter.ApplicationWithEquals> getModuleScope(String packageName) {
List<ScopeAdapter.ApplicationWithEquals> list = new ArrayList<>(); List<ScopeAdapter.ApplicationWithEquals> list = new ArrayList<>();
try { try {
List<Application> applications = LSPosedManagerServiceClient.getModuleScope(packageName).getList(); List<Application> applications = LSPManagerServiceClient.getModuleScope(packageName).getList();
if (applications == null) { if (applications == null) {
return list; return list;
} }
@ -129,7 +129,7 @@ public class ConfigManager {
public static boolean isResourceHookEnabled() { public static boolean isResourceHookEnabled() {
try { try {
return LSPosedManagerServiceClient.isResourceHook(); return LSPManagerServiceClient.isResourceHook();
} catch (RemoteException | NullPointerException e) { } catch (RemoteException | NullPointerException e) {
Log.e(App.TAG, Log.getStackTraceString(e)); Log.e(App.TAG, Log.getStackTraceString(e));
return false; return false;
@ -138,7 +138,7 @@ public class ConfigManager {
public static boolean setResourceHookEnabled(boolean enabled) { public static boolean setResourceHookEnabled(boolean enabled) {
try { try {
LSPosedManagerServiceClient.setResourceHook(enabled); LSPManagerServiceClient.setResourceHook(enabled);
return true; return true;
} catch (RemoteException | NullPointerException e) { } catch (RemoteException | NullPointerException e) {
Log.e(App.TAG, Log.getStackTraceString(e)); Log.e(App.TAG, Log.getStackTraceString(e));
@ -148,7 +148,7 @@ public class ConfigManager {
public static boolean isVerboseLogEnabled() { public static boolean isVerboseLogEnabled() {
try { try {
return LSPosedManagerServiceClient.isVerboseLog(); return LSPManagerServiceClient.isVerboseLog();
} catch (RemoteException | NullPointerException e) { } catch (RemoteException | NullPointerException e) {
Log.e(App.TAG, Log.getStackTraceString(e)); Log.e(App.TAG, Log.getStackTraceString(e));
return false; return false;
@ -157,7 +157,7 @@ public class ConfigManager {
public static boolean setVerboseLogEnabled(boolean enabled) { public static boolean setVerboseLogEnabled(boolean enabled) {
try { try {
LSPosedManagerServiceClient.setVerboseLog(enabled); LSPManagerServiceClient.setVerboseLog(enabled);
return true; return true;
} catch (RemoteException | NullPointerException e) { } catch (RemoteException | NullPointerException e) {
Log.e(App.TAG, Log.getStackTraceString(e)); Log.e(App.TAG, Log.getStackTraceString(e));
@ -167,7 +167,7 @@ public class ConfigManager {
public static ParcelFileDescriptor getLogs(boolean verbose) { public static ParcelFileDescriptor getLogs(boolean verbose) {
try { try {
return verbose ? LSPosedManagerServiceClient.getVerboseLog() : LSPosedManagerServiceClient.getModulesLog(); return verbose ? LSPManagerServiceClient.getVerboseLog() : LSPManagerServiceClient.getModulesLog();
} catch (RemoteException | NullPointerException e) { } catch (RemoteException | NullPointerException e) {
Log.e(App.TAG, Log.getStackTraceString(e)); Log.e(App.TAG, Log.getStackTraceString(e));
return null; return null;
@ -176,7 +176,7 @@ public class ConfigManager {
public static boolean clearLogs(boolean verbose) { public static boolean clearLogs(boolean verbose) {
try { try {
return LSPosedManagerServiceClient.clearLogs(verbose); return LSPManagerServiceClient.clearLogs(verbose);
} catch (RemoteException | NullPointerException e) { } catch (RemoteException | NullPointerException e) {
Log.e(App.TAG, Log.getStackTraceString(e)); Log.e(App.TAG, Log.getStackTraceString(e));
return false; return false;
@ -185,7 +185,7 @@ public class ConfigManager {
public static PackageInfo getPackageInfo(String packageName, int flags, int userId) throws PackageManager.NameNotFoundException { public static PackageInfo getPackageInfo(String packageName, int flags, int userId) throws PackageManager.NameNotFoundException {
try { try {
return LSPosedManagerServiceClient.getPackageInfo(packageName, flags, userId); return LSPManagerServiceClient.getPackageInfo(packageName, flags, userId);
} catch (RemoteException | NullPointerException e) { } catch (RemoteException | NullPointerException e) {
Log.e(App.TAG, Log.getStackTraceString(e)); Log.e(App.TAG, Log.getStackTraceString(e));
throw new PackageManager.NameNotFoundException(); throw new PackageManager.NameNotFoundException();
@ -194,7 +194,7 @@ public class ConfigManager {
public static boolean forceStopPackage(String packageName, int userId) { public static boolean forceStopPackage(String packageName, int userId) {
try { try {
LSPosedManagerServiceClient.forceStopPackage(packageName, userId); LSPManagerServiceClient.forceStopPackage(packageName, userId);
return true; return true;
} catch (RemoteException | NullPointerException e) { } catch (RemoteException | NullPointerException e) {
Log.e(App.TAG, Log.getStackTraceString(e)); Log.e(App.TAG, Log.getStackTraceString(e));
@ -204,7 +204,7 @@ public class ConfigManager {
public static boolean reboot(boolean confirm, String reason, boolean wait) { public static boolean reboot(boolean confirm, String reason, boolean wait) {
try { try {
LSPosedManagerServiceClient.reboot(confirm, reason, wait); LSPManagerServiceClient.reboot(confirm, reason, wait);
return true; return true;
} catch (RemoteException | NullPointerException e) { } catch (RemoteException | NullPointerException e) {
Log.e(App.TAG, Log.getStackTraceString(e)); Log.e(App.TAG, Log.getStackTraceString(e));
@ -212,9 +212,9 @@ public class ConfigManager {
} }
} }
public static boolean uninstallPackage(String packageName) { public static boolean uninstallPackage(String packageName, int userId) {
try { try {
return LSPosedManagerServiceClient.uninstallPackage(packageName); return LSPManagerServiceClient.uninstallPackage(packageName, userId);
} catch (RemoteException | NullPointerException e) { } catch (RemoteException | NullPointerException e) {
Log.e(App.TAG, Log.getStackTraceString(e)); Log.e(App.TAG, Log.getStackTraceString(e));
return false; return false;
@ -223,7 +223,7 @@ public class ConfigManager {
public static boolean isSepolicyLoaded() { public static boolean isSepolicyLoaded() {
try { try {
return LSPosedManagerServiceClient.isSepolicyLoaded(); return LSPManagerServiceClient.isSepolicyLoaded();
} catch (RemoteException | NullPointerException e) { } catch (RemoteException | NullPointerException e) {
Log.e(App.TAG, Log.getStackTraceString(e)); Log.e(App.TAG, Log.getStackTraceString(e));
return false; return false;
@ -232,7 +232,7 @@ public class ConfigManager {
public static int[] getUsers() { public static int[] getUsers() {
try { try {
return LSPosedManagerServiceClient.getUsers(); return LSPManagerServiceClient.getUsers();
} catch (RemoteException | NullPointerException e) { } catch (RemoteException | NullPointerException e) {
Log.e(App.TAG, Log.getStackTraceString(e)); Log.e(App.TAG, Log.getStackTraceString(e));
return null; return null;

View File

@ -30,7 +30,7 @@ import org.lsposed.lspd.utils.ParceledListSlice;
import java.util.List; import java.util.List;
public class LSPosedManagerServiceClient { public class LSPManagerServiceClient {
@SuppressWarnings("FieldMayBeFinal") @SuppressWarnings("FieldMayBeFinal")
private static IBinder binder = null; private static IBinder binder = null;
@ -144,9 +144,9 @@ public class LSPosedManagerServiceClient {
service.reboot(confirm, reason, wait); service.reboot(confirm, reason, wait);
} }
public static boolean uninstallPackage(String packageName) throws RemoteException, NullPointerException { public static boolean uninstallPackage(String packageName, int userId) throws RemoteException, NullPointerException {
ensureService(); ensureService();
return service.uninstallPackage(packageName); return service.uninstallPackage(packageName, userId);
} }
public static boolean isSepolicyLoaded() throws RemoteException, NullPointerException { public static boolean isSepolicyLoaded() throws RemoteException, NullPointerException {
@ -158,4 +158,8 @@ public class LSPosedManagerServiceClient {
ensureService(); ensureService();
return service.getUsers(); return service.getUsers();
} }
public static int installExistingPackageAsUser(String packageName, int userId) throws RemoteException, NullPointerException {
ensureService();
return service.installExistingPackageAsUser(packageName, userId);
}
} }

View File

@ -224,9 +224,7 @@ public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleLi
@Override @Override
public void onSingleInstalledModuleReloaded() { public void onSingleInstalledModuleReloaded() {
adapters.forEach(adapter -> { adapters.forEach(adapter -> adapter.refresh(true));
adapter.refresh(true);
});
} }
@Override @Override
@ -278,7 +276,7 @@ public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleLi
.setMessage(R.string.module_uninstall_message) .setMessage(R.string.module_uninstall_message)
.setPositiveButton(android.R.string.ok, (dialog, which) -> .setPositiveButton(android.R.string.ok, (dialog, which) ->
uninstallHandler.post(() -> { uninstallHandler.post(() -> {
boolean success = ConfigManager.uninstallPackage(module.packageName); boolean success = ConfigManager.uninstallPackage(module.packageName, module.userId);
runOnUiThread(() -> { runOnUiThread(() -> {
String text = success ? getString(R.string.module_uninstalled, module.getAppName()) : getString(R.string.module_uninstall_failed); String text = success ? getString(R.string.module_uninstalled, module.getAppName()) : getString(R.string.module_uninstall_failed);
if (getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.RESUMED)) { if (getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.RESUMED)) {
@ -425,6 +423,9 @@ public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleLi
if (RepoLoader.getInstance().getOnlineModule(item.packageName) == null) { if (RepoLoader.getInstance().getOnlineModule(item.packageName) == null) {
menu.removeItem(R.id.menu_repo); menu.removeItem(R.id.menu_repo);
} }
if (userHandle == null) {
menu.removeItem(R.id.menu_app_info);
}
}); });
holder.itemView.setOnClickListener(v -> { holder.itemView.setOnClickListener(v -> {

View File

@ -86,11 +86,9 @@ public final class ModuleUtil {
Map<Pair<String, Integer>, InstalledModule> modules = new HashMap<>(); Map<Pair<String, Integer>, InstalledModule> modules = new HashMap<>();
for (PackageInfo pkg : ConfigManager.getInstalledPackagesFromAllUsers(PackageManager.GET_META_DATA, false)) { for (PackageInfo pkg : ConfigManager.getInstalledPackagesFromAllUsers(PackageManager.GET_META_DATA, false)) {
ApplicationInfo app = pkg.applicationInfo; ApplicationInfo app = pkg.applicationInfo;
if (!app.enabled)
continue;
if (app.metaData != null && app.metaData.containsKey("xposedminversion")) { if (app.metaData != null && app.metaData.containsKey("xposedminversion")) {
InstalledModule installed = new InstalledModule(pkg, false); InstalledModule installed = new InstalledModule(pkg);
modules.put(Pair.create(pkg.packageName, app.uid / 100000), installed); modules.put(Pair.create(pkg.packageName, app.uid / 100000), installed);
} }
} }
@ -120,8 +118,8 @@ public final class ModuleUtil {
} }
ApplicationInfo app = pkg.applicationInfo; ApplicationInfo app = pkg.applicationInfo;
if (app.enabled && app.metaData != null && app.metaData.containsKey("xposedminversion")) { if (app.metaData != null && app.metaData.containsKey("xposedminversion")) {
InstalledModule module = new InstalledModule(pkg, false); InstalledModule module = new InstalledModule(pkg);
installedModules.put(Pair.create(packageName, userId), module); installedModules.put(Pair.create(packageName, userId), module);
for (ModuleListener listener : listeners) { for (ModuleListener listener : listeners) {
listener.onSingleInstalledModuleReloaded(); listener.onSingleInstalledModuleReloaded();
@ -196,19 +194,17 @@ public final class ModuleUtil {
public final int minVersion; public final int minVersion;
public final long installTime; public final long installTime;
public final long updateTime; public final long updateTime;
final boolean isFramework;
public ApplicationInfo app; public ApplicationInfo app;
public PackageInfo pkg; public PackageInfo pkg;
private String appName; // loaded lazyily private String appName; // loaded lazyily
private String description; // loaded lazyily private String description; // loaded lazyily
private List<String> scopeList; // loaded lazyily private List<String> scopeList; // loaded lazyily
private InstalledModule(PackageInfo pkg, boolean isFramework) { private InstalledModule(PackageInfo pkg) {
this.app = pkg.applicationInfo; this.app = pkg.applicationInfo;
this.pkg = pkg; this.pkg = pkg;
this.userId = pkg.applicationInfo.uid / 100000; this.userId = pkg.applicationInfo.uid / 100000;
this.packageName = pkg.packageName; this.packageName = pkg.packageName;
this.isFramework = isFramework;
this.versionName = pkg.versionName; this.versionName = pkg.versionName;
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) {
this.versionCode = pkg.versionCode; this.versionCode = pkg.versionCode;
@ -218,18 +214,13 @@ public final class ModuleUtil {
this.installTime = pkg.firstInstallTime; this.installTime = pkg.firstInstallTime;
this.updateTime = pkg.lastUpdateTime; this.updateTime = pkg.lastUpdateTime;
if (isFramework) { Object minVersionRaw = app.metaData.get("xposedminversion");
this.minVersion = 0; if (minVersionRaw instanceof Integer) {
this.description = ""; this.minVersion = (Integer) minVersionRaw;
} else if (minVersionRaw instanceof String) {
this.minVersion = extractIntPart((String) minVersionRaw);
} else { } else {
Object minVersionRaw = app.metaData.get("xposedminversion"); this.minVersion = 0;
if (minVersionRaw instanceof Integer) {
this.minVersion = (Integer) minVersionRaw;
} else if (minVersionRaw instanceof String) {
this.minVersion = extractIntPart((String) minVersionRaw);
} else {
this.minVersion = 0;
}
} }
} }

View File

@ -37,7 +37,7 @@ val commitCount = Git(repo).log().add(refId).call().count()
val defaultManagerPackageName by extra("org.lsposed.manager") val defaultManagerPackageName by extra("org.lsposed.manager")
val verCode by extra(commitCount + 4200) val verCode by extra(commitCount + 4200)
val verName by extra("v1.3.6") val verName by extra("v1.3.7")
val androidTargetSdkVersion by extra(30) val androidTargetSdkVersion by extra(30)
val androidMinSdkVersion by extra(27) val androidMinSdkVersion by extra(27)
val androidBuildToolsVersion by extra("30.0.3") val androidBuildToolsVersion by extra("30.0.3")

View File

@ -32,7 +32,7 @@ public class XposedInstallerHooker {
public static void hookXposedInstaller(final ClassLoader classLoader, IBinder binder) { public static void hookXposedInstaller(final ClassLoader classLoader, IBinder binder) {
Utils.logI("Found LSPosed Manager, hooking it"); Utils.logI("Found LSPosed Manager, hooking it");
try { try {
Class<?> serviceClass = XposedHelpers.findClass("org.lsposed.manager.receivers.LSPosedManagerServiceClient", classLoader); Class<?> serviceClass = XposedHelpers.findClass("org.lsposed.manager.receivers.LSPManagerServiceClient", classLoader);
XposedHelpers.setStaticObjectField(serviceClass, "binder", binder); XposedHelpers.setStaticObjectField(serviceClass, "binder", binder);
Utils.logI("Hooked LSPosed Manager"); Utils.logI("Hooked LSPosed Manager");

View File

@ -616,10 +616,6 @@ public class ConfigManager {
return uid == managerUid; return uid == managerUid;
} }
public String getCachePath(String fileName) {
return miscPath + File.separator + "cache" + File.separator + fileName;
}
public String getPrefsPath(String fileName, int uid) { public String getPrefsPath(String fileName, int uid) {
int userId = uid / PER_USER_RANGE; int userId = uid / PER_USER_RANGE;
return miscPath + File.separator + "prefs" + (userId == 0 ? "" : String.valueOf(userId)) + File.separator + fileName; return miscPath + File.separator + "prefs" + (userId == 0 ? "" : String.valueOf(userId)) + File.separator + fileName;
@ -640,6 +636,10 @@ public class ConfigManager {
return cachedModule.containsKey(uid % PER_USER_RANGE); return cachedModule.containsKey(uid % PER_USER_RANGE);
} }
public boolean isModule(String packageName) {
return cachedModule.containsValue(packageName);
}
private void recursivelyChown(File file, int uid, int gid) throws ErrnoException { private void recursivelyChown(File file, int uid, int gid) throws ErrnoException {
Os.chown(file.toString(), uid, gid); Os.chown(file.toString(), uid, gid);
if (file.isDirectory()) { if (file.isDirectory()) {

View File

@ -22,6 +22,7 @@ package org.lsposed.lspd.service;
import android.content.pm.PackageInfo; import android.content.pm.PackageInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.pm.VersionedPackage; import android.content.pm.VersionedPackage;
import android.graphics.Bitmap;
import android.os.IBinder; import android.os.IBinder;
import android.os.ParcelFileDescriptor; import android.os.ParcelFileDescriptor;
import android.os.RemoteException; import android.os.RemoteException;
@ -36,6 +37,7 @@ import org.lsposed.lspd.BuildConfig;
import org.lsposed.lspd.ILSPManagerService; import org.lsposed.lspd.ILSPManagerService;
import org.lsposed.lspd.utils.ParceledListSlice; import org.lsposed.lspd.utils.ParceledListSlice;
import static org.lsposed.lspd.service.PackageService.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME;
import static org.lsposed.lspd.service.ServiceManager.TAG; import static org.lsposed.lspd.service.ServiceManager.TAG;
public class LSPManagerService extends ILSPManagerService.Stub { public class LSPManagerService extends ILSPManagerService.Stub {
@ -148,9 +150,9 @@ public class LSPManagerService extends ILSPManagerService.Stub {
} }
@Override @Override
public boolean uninstallPackage(String packageName) throws RemoteException { public boolean uninstallPackage(String packageName, int userId) throws RemoteException {
try { try {
return PackageService.uninstallPackage(new VersionedPackage(packageName, PackageManager.VERSION_CODE_HIGHEST)); return PackageService.uninstallPackage(new VersionedPackage(packageName, PackageManager.VERSION_CODE_HIGHEST), userId);
} catch (InterruptedException | InvocationTargetException | NoSuchMethodException | InstantiationException | IllegalAccessException e) { } catch (InterruptedException | InvocationTargetException | NoSuchMethodException | InstantiationException | IllegalAccessException e) {
Log.e(TAG, e.getMessage(), e); Log.e(TAG, e.getMessage(), e);
return false; return false;
@ -166,4 +168,12 @@ public class LSPManagerService extends ILSPManagerService.Stub {
public int[] getUsers() throws RemoteException { public int[] getUsers() throws RemoteException {
return UserService.getUsers(); return UserService.getUsers();
} }
@Override
public int installExistingPackageAsUser(String packageName, int userid) {
if (ConfigManager.getInstance().isModule(packageName)) {
return PackageService.installExistingPackageAsUser(packageName, userid);
}
return INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME;
}
} }

View File

@ -96,7 +96,6 @@ public class LSPosedService extends ILSPosedService.Stub {
ApplicationInfo applicationInfo = PackageService.getApplicationInfo(packageName, PackageManager.GET_META_DATA, 0); ApplicationInfo applicationInfo = PackageService.getApplicationInfo(packageName, PackageManager.GET_META_DATA, 0);
boolean isXposedModule = applicationInfo != null && boolean isXposedModule = applicationInfo != null &&
applicationInfo.enabled &&
applicationInfo.metaData != null && applicationInfo.metaData != null &&
applicationInfo.metaData.containsKey("xposedminversion"); applicationInfo.metaData.containsKey("xposedminversion");

View File

@ -65,6 +65,12 @@ import java.util.stream.Collectors;
import hidden.HiddenApiBridge; import hidden.HiddenApiBridge;
public class PackageService { public class PackageService {
static final int INSTALL_FAILED_INTERNAL_ERROR = -110;
static final int INSTALL_REASON_UNKNOWN = 0;
static final int INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME = -106;
private static IPackageManager pm = null; private static IPackageManager pm = null;
private static IBinder binder = null; private static IBinder binder = null;
private static final IBinder.DeathRecipient recipient = new IBinder.DeathRecipient() { private static final IBinder.DeathRecipient recipient = new IBinder.DeathRecipient() {
@ -231,10 +237,11 @@ public class PackageService {
} }
} }
public static boolean uninstallPackage(VersionedPackage versionedPackage) throws RemoteException, InterruptedException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException { public static boolean uninstallPackage(VersionedPackage versionedPackage, int userId) throws RemoteException, InterruptedException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
CountDownLatch latch = new CountDownLatch(1); CountDownLatch latch = new CountDownLatch(1);
final boolean[] result = {false}; final boolean[] result = {false};
pm.getPackageInstaller().uninstall(versionedPackage, null, 0x00000002, new IntentSenderAdaptor() { var flag = userId == -1 ? 0x00000002 : 0; //PackageManager.DELETE_ALL_USERS = 0x00000002; UserHandle ALL = new UserHandle(-1);
pm.getPackageInstaller().uninstall(versionedPackage, null, flag, new IntentSenderAdaptor() {
@Override @Override
public void send(Intent intent) { public void send(Intent intent) {
int status = intent.getIntExtra(PackageInstaller.EXTRA_STATUS, PackageInstaller.STATUS_FAILURE); int status = intent.getIntExtra(PackageInstaller.EXTRA_STATUS, PackageInstaller.STATUS_FAILURE);
@ -242,11 +249,21 @@ public class PackageService {
Log.d(TAG, intent.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE)); Log.d(TAG, intent.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE));
latch.countDown(); latch.countDown();
} }
}.getIntentSender(), 0); }.getIntentSender(), userId == -1 ? 0 : userId);
latch.await(); latch.await();
return result[0]; return result[0];
} }
public static int installExistingPackageAsUser(String packageName, int userId) {
IPackageManager pm = getPackageManager();
if (pm == null) return INSTALL_FAILED_INTERNAL_ERROR;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
return pm.installExistingPackageAsUser(packageName, userId, 0, INSTALL_REASON_UNKNOWN, null);
} else {
return pm.installExistingPackageAsUser(packageName, userId, 0, INSTALL_REASON_UNKNOWN);
}
}
@SuppressWarnings("JavaReflectionMemberAccess") @SuppressWarnings("JavaReflectionMemberAccess")
public static synchronized boolean installManagerIfAbsent(String packageName, File apkFile) { public static synchronized boolean installManagerIfAbsent(String packageName, File apkFile) {
IPackageManager pm = getPackageManager(); IPackageManager pm = getPackageManager();
@ -264,7 +281,7 @@ public class PackageService {
if (versionMatch && signatureMatch && pkgInfo.versionCode >= BuildConfig.VERSION_CODE) if (versionMatch && signatureMatch && pkgInfo.versionCode >= BuildConfig.VERSION_CODE)
return false; return false;
if (!signatureMatch || !versionMatch && pkgInfo.versionCode > BuildConfig.VERSION_CODE) if (!signatureMatch || !versionMatch && pkgInfo.versionCode > BuildConfig.VERSION_CODE)
uninstallPackage(new VersionedPackage(pkgInfo.packageName, pkgInfo.versionCode)); uninstallPackage(new VersionedPackage(pkgInfo.packageName, pkgInfo.versionCode), -1);
} }
// Install manager // Install manager
@ -282,7 +299,7 @@ public class PackageService {
} }
PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL); PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL);
int installFlags = HiddenApiBridge.PackageInstaller_SessionParams_installFlags(params); int installFlags = HiddenApiBridge.PackageInstaller_SessionParams_installFlags(params);
installFlags |= 0x00000004/*PackageManager.INSTALL_ALLOW_TEST*/ | 0x00000002/*PackageManager.INSTALL_REPLACE_EXISTING*/; installFlags |= 0x00000002/*PackageManager.INSTALL_REPLACE_EXISTING*/;
HiddenApiBridge.PackageInstaller_SessionParams_installFlags(params, installFlags); HiddenApiBridge.PackageInstaller_SessionParams_installFlags(params, installFlags);
int sessionId = installer.createSession(params); int sessionId = installer.createSession(params);

View File

@ -5,6 +5,10 @@ import android.os.IBinder;
import android.os.IInterface; import android.os.IInterface;
import android.os.RemoteException; import android.os.RemoteException;
import androidx.annotation.RequiresApi;
import java.util.List;
public interface IPackageManager extends IInterface { public interface IPackageManager extends IInterface {
ApplicationInfo getApplicationInfo(String packageName, int flags, int userId) ApplicationInfo getApplicationInfo(String packageName, int flags, int userId)
@ -48,6 +52,13 @@ public interface IPackageManager extends IInterface {
IPackageInstaller getPackageInstaller() throws RemoteException; IPackageInstaller getPackageInstaller() throws RemoteException;
int installExistingPackageAsUser(String packageName, int userId, int installFlags,
int installReason);
@RequiresApi(29)
int installExistingPackageAsUser(String packageName, int userId, int installFlags,
int installReason, List<String> whiteListedPermissions);
abstract class Stub extends Binder implements IPackageManager { abstract class Stub extends Binder implements IPackageManager {
public static IPackageManager asInterface(IBinder obj) { public static IPackageManager asInterface(IBinder obj) {

View File

@ -43,9 +43,11 @@ interface ILSPManagerService {
void reboot(boolean confirm, String reason, boolean wait) = 24; void reboot(boolean confirm, String reason, boolean wait) = 24;
boolean uninstallPackage(String packageName) = 25; boolean uninstallPackage(String packageName, int userId) = 25;
boolean isSepolicyLoaded() = 26; boolean isSepolicyLoaded() = 26;
int[] getUsers() = 27; int[] getUsers() = 27;
int installExistingPackageAsUser(String packageName, int userId) = 28;
} }