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 {
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;
}

View File

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

View File

@ -30,7 +30,7 @@ import org.lsposed.lspd.utils.ParceledListSlice;
import java.util.List;
public class LSPosedManagerServiceClient {
public class LSPManagerServiceClient {
@SuppressWarnings("FieldMayBeFinal")
private static IBinder binder = null;
@ -144,9 +144,9 @@ public class LSPosedManagerServiceClient {
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();
return service.uninstallPackage(packageName);
return service.uninstallPackage(packageName, userId);
}
public static boolean isSepolicyLoaded() throws RemoteException, NullPointerException {
@ -158,4 +158,8 @@ public class LSPosedManagerServiceClient {
ensureService();
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
public void onSingleInstalledModuleReloaded() {
adapters.forEach(adapter -> {
adapter.refresh(true);
});
adapters.forEach(adapter -> adapter.refresh(true));
}
@Override
@ -278,7 +276,7 @@ public class ModulesActivity extends BaseActivity implements ModuleUtil.ModuleLi
.setMessage(R.string.module_uninstall_message)
.setPositiveButton(android.R.string.ok, (dialog, which) ->
uninstallHandler.post(() -> {
boolean success = ConfigManager.uninstallPackage(module.packageName);
boolean success = ConfigManager.uninstallPackage(module.packageName, module.userId);
runOnUiThread(() -> {
String text = success ? getString(R.string.module_uninstalled, module.getAppName()) : getString(R.string.module_uninstall_failed);
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) {
menu.removeItem(R.id.menu_repo);
}
if (userHandle == null) {
menu.removeItem(R.id.menu_app_info);
}
});
holder.itemView.setOnClickListener(v -> {

View File

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

View File

@ -37,7 +37,7 @@ val commitCount = Git(repo).log().add(refId).call().count()
val defaultManagerPackageName by extra("org.lsposed.manager")
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 androidMinSdkVersion by extra(27)
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) {
Utils.logI("Found LSPosed Manager, hooking it");
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);
Utils.logI("Hooked LSPosed Manager");

View File

@ -616,10 +616,6 @@ public class ConfigManager {
return uid == managerUid;
}
public String getCachePath(String fileName) {
return miscPath + File.separator + "cache" + File.separator + fileName;
}
public String getPrefsPath(String fileName, int uid) {
int userId = uid / PER_USER_RANGE;
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);
}
public boolean isModule(String packageName) {
return cachedModule.containsValue(packageName);
}
private void recursivelyChown(File file, int uid, int gid) throws ErrnoException {
Os.chown(file.toString(), uid, gid);
if (file.isDirectory()) {

View File

@ -22,6 +22,7 @@ package org.lsposed.lspd.service;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.VersionedPackage;
import android.graphics.Bitmap;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
@ -36,6 +37,7 @@ import org.lsposed.lspd.BuildConfig;
import org.lsposed.lspd.ILSPManagerService;
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;
public class LSPManagerService extends ILSPManagerService.Stub {
@ -148,9 +150,9 @@ public class LSPManagerService extends ILSPManagerService.Stub {
}
@Override
public boolean uninstallPackage(String packageName) throws RemoteException {
public boolean uninstallPackage(String packageName, int userId) throws RemoteException {
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) {
Log.e(TAG, e.getMessage(), e);
return false;
@ -166,4 +168,12 @@ public class LSPManagerService extends ILSPManagerService.Stub {
public int[] getUsers() throws RemoteException {
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);
boolean isXposedModule = applicationInfo != null &&
applicationInfo.enabled &&
applicationInfo.metaData != null &&
applicationInfo.metaData.containsKey("xposedminversion");

View File

@ -65,6 +65,12 @@ import java.util.stream.Collectors;
import hidden.HiddenApiBridge;
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 IBinder binder = null;
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);
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
public void send(Intent intent) {
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));
latch.countDown();
}
}.getIntentSender(), 0);
}.getIntentSender(), userId == -1 ? 0 : userId);
latch.await();
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")
public static synchronized boolean installManagerIfAbsent(String packageName, File apkFile) {
IPackageManager pm = getPackageManager();
@ -264,7 +281,7 @@ public class PackageService {
if (versionMatch && signatureMatch && pkgInfo.versionCode >= BuildConfig.VERSION_CODE)
return false;
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
@ -282,7 +299,7 @@ public class PackageService {
}
PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL);
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);
int sessionId = installer.createSession(params);

View File

@ -5,6 +5,10 @@ import android.os.IBinder;
import android.os.IInterface;
import android.os.RemoteException;
import androidx.annotation.RequiresApi;
import java.util.List;
public interface IPackageManager extends IInterface {
ApplicationInfo getApplicationInfo(String packageName, int flags, int userId)
@ -48,6 +52,13 @@ public interface IPackageManager extends IInterface {
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 {
public static IPackageManager asInterface(IBinder obj) {

View File

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