[core] Bring back package receiver
This commit is contained in:
parent
e7e32351ea
commit
e3b2731cd3
|
|
@ -4,4 +4,6 @@ import io.github.lsposed.lspd.service.ILSPApplicationService;
|
||||||
|
|
||||||
interface ILSPosedService {
|
interface ILSPosedService {
|
||||||
ILSPApplicationService requestApplicationService(int uid, int pid) = 1;
|
ILSPApplicationService requestApplicationService(int uid, int pid) = 1;
|
||||||
|
|
||||||
|
oneway void dispatchPackageChanged(in Intent intent) = 2;
|
||||||
}
|
}
|
||||||
|
|
@ -1,5 +1,8 @@
|
||||||
package io.github.lsposed.lspd.service;
|
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.Binder;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
|
|
@ -146,7 +149,20 @@ public class BridgeService {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (serviceBinder == null) {
|
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 {
|
} else {
|
||||||
serviceBinder.unlinkToDeath(LSPSERVICE_DEATH_RECIPIENT, 0);
|
serviceBinder.unlinkToDeath(LSPSERVICE_DEATH_RECIPIENT, 0);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@ import android.content.ContentValues;
|
||||||
import android.content.pm.PackageInfo;
|
import android.content.pm.PackageInfo;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.database.sqlite.SQLiteDatabase;
|
import android.database.sqlite.SQLiteDatabase;
|
||||||
import android.database.sqlite.SQLiteQueryBuilder;
|
|
||||||
import android.database.sqlite.SQLiteStatement;
|
import android.database.sqlite.SQLiteStatement;
|
||||||
import android.os.FileObserver;
|
import android.os.FileObserver;
|
||||||
import android.os.ParcelFileDescriptor;
|
import android.os.ParcelFileDescriptor;
|
||||||
|
|
@ -188,10 +187,6 @@ public class ConfigManager {
|
||||||
// This is called when a new process created, use the cached result
|
// This is called when a new process created, use the cached result
|
||||||
// The signature matches Riru's
|
// The signature matches Riru's
|
||||||
public boolean shouldSkipUid(int uid) {
|
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);
|
return !modulesForUid.containsKey(uid) && !isManager(uid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -270,7 +265,7 @@ public class ConfigManager {
|
||||||
public String[] enabledModules() {
|
public String[] enabledModules() {
|
||||||
try (Cursor cursor = db.query("modules", new String[]{"package_name"}, "enabled = ?", new String[]{"1"}, null, null, null)) {
|
try (Cursor cursor = db.query("modules", new String[]{"package_name"}, "enabled = ?", new String[]{"1"}, null, null, null)) {
|
||||||
if (cursor == null) {
|
if (cursor == null) {
|
||||||
Log.e(TAG, "db cache failed");
|
Log.e(TAG, "query enabled modules failed");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
int pkg_idx = cursor.getColumnIndex("package_name");
|
int pkg_idx = cursor.getColumnIndex("package_name");
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,11 @@
|
||||||
package io.github.lsposed.lspd.service;
|
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.Binder;
|
||||||
|
import android.os.RemoteException;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import static io.github.lsposed.lspd.service.ServiceManager.TAG;
|
import static io.github.lsposed.lspd.service.ServiceManager.TAG;
|
||||||
|
|
@ -42,4 +47,28 @@ public class LSPosedService extends ILSPosedService.Stub {
|
||||||
return ServiceManager.getApplicationService();
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,184 +26,17 @@ import android.content.BroadcastReceiver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.IntentFilter;
|
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.Handler;
|
||||||
import android.os.HandlerThread;
|
import android.os.HandlerThread;
|
||||||
import android.os.RemoteException;
|
|
||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
import io.github.lsposed.lspd.util.Utils;
|
import io.github.lsposed.lspd.util.Utils;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.PrintWriter;
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.lang.reflect.Method;
|
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 {
|
public class PackageReceiver {
|
||||||
private static final BroadcastReceiver RECEIVER = new BroadcastReceiver() {
|
public static void register(BroadcastReceiver receiver) {
|
||||||
|
|
||||||
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() {
|
|
||||||
ActivityThread activityThread = ActivityThread.currentActivityThread();
|
ActivityThread activityThread = ActivityThread.currentActivityThread();
|
||||||
if (activityThread == null) {
|
if (activityThread == null) {
|
||||||
Utils.logW("ActivityThread is null");
|
Utils.logW("ActivityThread is null");
|
||||||
|
|
@ -238,7 +71,7 @@ public class PackageReceiver {
|
||||||
try {
|
try {
|
||||||
@SuppressLint("DiscouragedPrivateApi")
|
@SuppressLint("DiscouragedPrivateApi")
|
||||||
Method method = Context.class.getDeclaredMethod("registerReceiverAsUser", BroadcastReceiver.class, UserHandle.class, IntentFilter.class, String.class, Handler.class);
|
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");
|
Utils.logI("registered package receiver");
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
Utils.logW("registerReceiver failed", e);
|
Utils.logW("registerReceiver failed", e);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue