[core] Bring back package receiver

This commit is contained in:
LoveSy 2021-02-17 02:27:43 +08:00 committed by tehcneko
parent e7e32351ea
commit e3b2731cd3
5 changed files with 51 additions and 176 deletions

View File

@ -4,4 +4,6 @@ import io.github.lsposed.lspd.service.ILSPApplicationService;
interface ILSPosedService {
ILSPApplicationService requestApplicationService(int uid, int pid) = 1;
oneway void dispatchPackageChanged(in Intent intent) = 2;
}

View File

@ -1,5 +1,8 @@
package io.github.lsposed.lspd.service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.os.Parcel;
@ -146,7 +149,20 @@ public class BridgeService {
}
if (serviceBinder == null) {
PackageReceiver.register();
PackageReceiver.register(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (service == null) {
Log.e(TAG, "Service is dead, missing package changed: " + intent);
return;
}
try {
service.dispatchPackageChanged(intent);
} catch (RemoteException e) {
Log.e(TAG, Log.getStackTraceString(e));
}
}
});
} else {
serviceBinder.unlinkToDeath(LSPSERVICE_DEATH_RECIPIENT, 0);
}

View File

@ -4,7 +4,6 @@ import android.content.ContentValues;
import android.content.pm.PackageInfo;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteQueryBuilder;
import android.database.sqlite.SQLiteStatement;
import android.os.FileObserver;
import android.os.ParcelFileDescriptor;
@ -188,10 +187,6 @@ public class ConfigManager {
// This is called when a new process created, use the cached result
// The signature matches Riru's
public boolean shouldSkipUid(int uid) {
Log.d(TAG, modulesForUid.keySet().size() + "");
for (Integer id : modulesForUid.keySet()) {
Log.d(TAG, id.toString());
}
return !modulesForUid.containsKey(uid) && !isManager(uid);
}
@ -270,7 +265,7 @@ public class ConfigManager {
public String[] enabledModules() {
try (Cursor cursor = db.query("modules", new String[]{"package_name"}, "enabled = ?", new String[]{"1"}, null, null, null)) {
if (cursor == null) {
Log.e(TAG, "db cache failed");
Log.e(TAG, "query enabled modules failed");
return null;
}
int pkg_idx = cursor.getColumnIndex("package_name");

View File

@ -1,6 +1,11 @@
package io.github.lsposed.lspd.service;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Binder;
import android.os.RemoteException;
import android.util.Log;
import static io.github.lsposed.lspd.service.ServiceManager.TAG;
@ -42,4 +47,28 @@ public class LSPosedService extends ILSPosedService.Stub {
return ServiceManager.getApplicationService();
}
@Override
public void dispatchPackageChanged(Intent intent) throws RemoteException {
if (Binder.getCallingUid() != 1000 || intent == null) return;
Uri uri = intent.getData();
String packageName = (uri != null) ? uri.getSchemeSpecificPart() : null;
if (packageName == null) {
Log.e(TAG, "Package name is null");
}
int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
if (intent.getAction().equals(Intent.ACTION_PACKAGE_REMOVED) && uid > 0 && !replacing) {
ConfigManager.getInstance().removeModule(packageName);
ConfigManager.getInstance().removeApp(uid);
}
PackageInfo pkgInfo = PackageService.getPackageInfo(packageName, PackageManager.GET_META_DATA, 0);
boolean isXposedModule = pkgInfo != null && pkgInfo.applicationInfo != null &&
pkgInfo.applicationInfo.enabled && pkgInfo.applicationInfo.metaData != null &&
pkgInfo.applicationInfo.metaData.containsKey("xposedmodule");
if (isXposedModule) {
ConfigManager.getInstance().updateModuleApkPath(packageName, pkgInfo.applicationInfo.sourceDir);
}
}
}

View File

@ -26,184 +26,17 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.RemoteException;
import android.os.UserHandle;
import android.widget.Toast;
import io.github.lsposed.lspd.util.Utils;
import java.io.File;
import java.io.PrintWriter;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Scanner;
import de.robv.android.xposed.XposedHelpers;
public class PackageReceiver {
private static final BroadcastReceiver RECEIVER = new BroadcastReceiver() {
private final String MODULES_LIST_FILENAME = "conf/modules.list";
private final String ENABLED_MODULES_LIST_FILENAME = "conf/enabled_modules.list";
private final String MODULE_UPDATED = "io.github.lsposed.action.MODULE_UPDATED";
private final String MODULE_NOT_ACTIVATAED = "io.github.lsposed.action.MODULE_NOT_ACTIVATAED";
private String getPackageName(Intent intent) {
Uri uri = intent.getData();
return (uri != null) ? uri.getSchemeSpecificPart() : null;
}
private boolean isXposedModule(ApplicationInfo app) {
return app != null && app.enabled && app.metaData != null && app.metaData.containsKey("xposedmodule");
}
private PackageInfo getPackageInfo(String packageName, int uid) {
try {
return PackageService.getPackageInfo(packageName, PackageManager.GET_META_DATA, uid);
} catch (RemoteException e) {
return null;
}
}
private Map<String, String> loadEnabledModules(int uid) {
HashMap<String, String> result = new HashMap<>();
// TODO: FIXME
// try {
// File enabledModules = new File(ConfigManager.getMiscPath(), uid + "/" + ENABLED_MODULES_LIST_FILENAME);
// if (!enabledModules.exists()) return result;
// Scanner scanner = new Scanner(enabledModules);
// while (scanner.hasNextLine()) {
// String packageName = scanner.nextLine();
// PackageInfo info = getPackageInfo(packageName, 0);
// if (info != null && isXposedModule(info.applicationInfo))
// result.put(packageName, info.applicationInfo.sourceDir);
// else if (info == null)
// result.put(packageName, null);
// }
// } catch (Throwable e) {
// Utils.logE("Unable to read enabled modules", e);
// }
return result;
}
private boolean updateModuleList(int uid, String packageName) {
Map<String, String> enabledModules = loadEnabledModules(uid);
// TODO: FIXME
//
// if (!enabledModules.containsKey(packageName)) return false;
//
// try {
// File moduleListFile = new File(ConfigManager.getMiscPath(), uid + "/" + MODULES_LIST_FILENAME);
// File enabledModuleListFile = new File(ConfigManager.getMiscPath(), uid + "/" + ENABLED_MODULES_LIST_FILENAME);
// if (moduleListFile.exists() && !moduleListFile.canWrite()) {
// moduleListFile.delete();
// moduleListFile.createNewFile();
// }
// if (enabledModuleListFile.exists() && !enabledModuleListFile.canWrite()) {
// enabledModuleListFile.delete();
// enabledModuleListFile.createNewFile();
// }
// PrintWriter modulesList = new PrintWriter(moduleListFile);
// PrintWriter enabledModulesList = new PrintWriter(enabledModuleListFile);
// for (Map.Entry<String, String> module : enabledModules.entrySet()) {
// String apkPath = module.getValue();
// if (apkPath != null) {
// modulesList.println(module.getValue());
// enabledModulesList.println(module.getKey());
// } else {
// Utils.logI(String.format("remove obsolete package %s", packageName));
// File prefsDir = new File(ConfigManager.getMiscPath(), uid + "/prefs/" + packageName);
// File[] fileList = prefsDir.listFiles();
// if (fileList != null) {
// for (File childFile : fileList) {
// childFile.delete();
// }
// }
// }
// }
// modulesList.close();
// enabledModulesList.close();
// } catch (Throwable e) {
// Utils.logE("Fail to update module list", e);
// }
return true;
}
@SuppressLint("WrongConstant")
@Override
public void onReceive(Context context, Intent intent) {
if (Objects.requireNonNull(intent.getAction()).equals(Intent.ACTION_PACKAGE_REMOVED) && intent.getBooleanExtra(Intent.EXTRA_REPLACING, false))
// Ignore existing packages being removed in order to be updated
return;
String packageName = getPackageName(intent);
if (packageName == null)
return;
if (intent.getAction().equals(Intent.ACTION_PACKAGE_CHANGED)) {
// make sure that the change is for the complete package, not only a
// component
String[] components = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST);
if (components != null) {
boolean isForPackage = false;
for (String component : components) {
if (packageName.equals(component)) {
isForPackage = true;
break;
}
}
if (!isForPackage)
return;
}
}
PackageInfo pkgInfo = getPackageInfo(packageName, intent.getIntExtra(Intent.EXTRA_USER, 0));
if (pkgInfo != null && !isXposedModule(pkgInfo.applicationInfo)) return;
// TODO: FIXME
//
// try {
// for (int uid : UserService.getUsers()) {
// Utils.logI("updating uid: " + uid);
// boolean activated = updateModuleList(uid, packageName);
// UserHandle userHandle = null;
// try {
// userHandle = (UserHandle) XposedHelpers.callStaticMethod(UserHandle.class, "of", uid);
// } catch (Throwable t) {
// Utils.logW("get user handle failed", t);
// }
// if (userHandle != null) {
// try {
// Intent broadCast = new Intent(activated ? MODULE_UPDATED : MODULE_NOT_ACTIVATAED);
// broadCast.setFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES | 0x01000000);
// broadCast.setData(intent.getData());
// broadCast.setPackage(ConfigManager.getInstallerPackageName());
// XposedHelpers.callMethod(context, "sendBroadcastAsUser", broadCast, userHandle);
// Utils.logI("broadcast to " + ConfigManager.getInstallerPackageName());
// } catch (Throwable t) {
// Utils.logW("send broadcast failed", t);
// Toast.makeText(context, "LSPosed: Updated " + packageName, Toast.LENGTH_SHORT).show();
// }
// } else if (activated) {
// Toast.makeText(context, "LSPosed: Updated " + packageName, Toast.LENGTH_SHORT).show();
// }
// }
// } catch (Throwable e) {
// Utils.logW("update failed", e);
// }
}
};
public static void register() {
public static void register(BroadcastReceiver receiver) {
ActivityThread activityThread = ActivityThread.currentActivityThread();
if (activityThread == null) {
Utils.logW("ActivityThread is null");
@ -238,7 +71,7 @@ public class PackageReceiver {
try {
@SuppressLint("DiscouragedPrivateApi")
Method method = Context.class.getDeclaredMethod("registerReceiverAsUser", BroadcastReceiver.class, UserHandle.class, IntentFilter.class, String.class, Handler.class);
method.invoke(context, RECEIVER, userHandleAll, intentFilter, null, handler);
method.invoke(context, receiver, userHandleAll, intentFilter, null, handler);
Utils.logI("registered package receiver");
} catch (Throwable e) {
Utils.logW("registerReceiver failed", e);