[core] Auto install manager when invalid

This commit is contained in:
LoveSy 2021-03-06 18:58:45 +08:00 committed by tehcneko
parent e857719a96
commit cc6155b496
16 changed files with 259 additions and 11 deletions

View File

@ -39,6 +39,7 @@ val repo = FileRepository(rootProject.file(".git"))
val refId = repo.refDatabase.exactRef("refs/remotes/origin/master").objectId!!
val commitCount = Git(repo).log().add(refId).call().count()
val defaultManagerPackageName by extra("io.github.lsposed.manager")
val verCode by extra(commitCount + 4200)
val verName by extra("v1.2.0")
val androidTargetSdkVersion by extra(30)

View File

@ -47,6 +47,7 @@ val moduleMinRiruApiVersion = 10
val moduleMinRiruVersionName = "v23.0"
val moduleMaxRiruApiVersion = 10
val defaultManagerPackageName: String by rootProject.extra
val apiCode: Int by rootProject.extra
val androidTargetSdkVersion: Int by rootProject.extra
@ -102,6 +103,7 @@ android {
buildConfigField("int", "API_CODE", "$apiCode")
buildConfigField("String", "VERSION_NAME", "\"$verName\"")
buildConfigField("Integer", "VERSION_CODE", verCode.toString())
buildConfigField("String", "DEFAULT_MANAGER_PACKAGE_NAME", "\"$defaultManagerPackageName\"")
}
lint {

View File

@ -6,4 +6,5 @@ interface ILSPosedService {
ILSPApplicationService requestApplicationService(int uid, int pid, String processName, IBinder heartBeat) = 1;
oneway void dispatchPackageChanged(in Intent intent) = 2;
}
oneway void dispatchBootCompleted(in Intent intent) = 3;
}

View File

@ -0,0 +1,45 @@
package io.github.lsposed.lspd.service;
import android.annotation.SuppressLint;
import android.app.ActivityThread;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Handler;
import android.os.HandlerThread;
import java.lang.reflect.Method;
import io.github.lsposed.lspd.util.Utils;
public class BootReceiver {
public static void register(BroadcastReceiver receiver) {
ActivityThread activityThread = ActivityThread.currentActivityThread();
if (activityThread == null) {
Utils.logW("ActivityThread is null");
return;
}
Context context = activityThread.getSystemContext();
if (context == null) {
Utils.logW("context is null");
return;
}
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_LOCKED_BOOT_COMPLETED);
HandlerThread thread = new HandlerThread("lspd-BootReceiver");
thread.start();
Handler handler = new Handler(thread.getLooper());
try {
@SuppressLint("DiscouragedPrivateApi")
Method method = Context.class.getDeclaredMethod("registerReceiver", BroadcastReceiver.class, IntentFilter.class, String.class, Handler.class);
method.invoke(context, receiver, intentFilter, null, handler);
Utils.logI("registered package receiver");
} catch (Throwable e) {
Utils.logW("registerReceiver failed", e);
}
}
}

View File

@ -206,6 +206,16 @@ public class BridgeService {
}
}
});
BootReceiver.register(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
try {
service.dispatchBootCompleted(intent);
} catch (RemoteException e) {
Log.e(TAG, Log.getStackTraceString(e));
}
}
});
} else {
serviceBinder.unlinkToDeath(LSPSERVICE_DEATH_RECIPIENT, 0);
}

View File

@ -58,6 +58,7 @@ import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import io.github.lsposed.lspd.Application;
import io.github.lsposed.lspd.BuildConfig;
import static io.github.lsposed.lspd.service.ServiceManager.TAG;
@ -81,8 +82,6 @@ public class ConfigManager {
private static final File verboseLogSwitch = new File(configPath, "verbose_log");
private boolean verboseLog = false;
private static final String DEFAULT_MANAGER_PACKAGE_NAME = "io.github.lsposed.manager";
private static final File managerPath = new File(configPath, "manager");
private String manager = null;
private int managerUid = -1;
@ -226,7 +225,7 @@ public class ConfigManager {
public synchronized void updateManager() {
if (!packageStarted) return;
try {
PackageInfo info = PackageService.getPackageInfo(readText(managerPath, DEFAULT_MANAGER_PACKAGE_NAME), 0, 0);
PackageInfo info = PackageService.getPackageInfo(readText(managerPath, BuildConfig.DEFAULT_MANAGER_PACKAGE_NAME), 0, 0);
if (info != null) {
managerUid = info.applicationInfo.uid;
manager = info.packageName;
@ -237,6 +236,15 @@ public class ConfigManager {
}
}
public void ensureManager() {
if (!packageStarted) return;
new Thread(() -> {
if (PackageService.installManagerIfAbsent(manager, new File("/data/adb/lspd/base.apk"))) {
updateManager(BuildConfig.DEFAULT_MANAGER_PACKAGE_NAME);
}
}).start();
}
public synchronized void updateManager(@NonNull String packageName) {
writeText(managerPath, packageName);
manager = packageName;
@ -610,7 +618,7 @@ public class ConfigManager {
}
public boolean isManager(String packageName) {
return packageName.equals(manager) || packageName.equals(DEFAULT_MANAGER_PACKAGE_NAME);
return packageName.equals(manager) || packageName.equals(BuildConfig.DEFAULT_MANAGER_PACKAGE_NAME);
}
public boolean isManager(int uid) {
@ -627,7 +635,7 @@ public class ConfigManager {
public static void grantManagerPermission() {
try {
PackageService.grantRuntimePermission(readText(managerPath, DEFAULT_MANAGER_PACKAGE_NAME), "android.permission.INTERACT_ACROSS_USERS", 0);
PackageService.grantRuntimePermission(readText(managerPath, BuildConfig.DEFAULT_MANAGER_PACKAGE_NAME), "android.permission.INTERACT_ACROSS_USERS", 0);
} catch (RemoteException e) {
Log.e(TAG, Log.getStackTraceString(e));
}

View File

@ -31,6 +31,7 @@ import android.util.Log;
import java.util.Arrays;
import io.github.lsposed.lspd.Application;
import pxb.android.arsc.Config;
import static io.github.lsposed.lspd.service.ServiceManager.TAG;
@ -122,4 +123,9 @@ public class LSPosedService extends ILSPosedService.Stub {
}
}
@Override
public void dispatchBootCompleted(Intent intent) throws RemoteException {
ConfigManager.getInstance().ensureManager();
}
}

View File

@ -19,12 +19,20 @@
package io.github.lsposed.lspd.service;
import android.content.IIntentReceiver;
import android.content.IIntentSender;
import android.content.Intent;
import android.content.IntentSender;
import android.content.pm.ApplicationInfo;
import android.content.pm.ComponentInfo;
import android.content.pm.IPackageInstaller;
import android.content.pm.IPackageManager;
import android.content.pm.PackageInfo;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
import android.content.pm.ServiceInfo;
import android.content.pm.VersionedPackage;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
@ -32,14 +40,23 @@ import android.util.Log;
import android.util.Pair;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.stream.Collectors;
import hidden.HiddenApiBridge;
import io.github.lsposed.lspd.Application;
import io.github.lsposed.lspd.BuildConfig;
import io.github.lsposed.lspd.util.InstallerVerifier;
import io.github.lsposed.lspd.utils.ParceledListSlice;
import static android.content.pm.ServiceInfo.FLAG_ISOLATED_PROCESS;
@ -145,6 +162,8 @@ public class PackageService {
}
private static PackageInfo getPackageInfoWithComponents(String packageName, int flags, int userId) throws RemoteException {
IPackageManager pm = getPackageManager();
if (pm == null) return null;
PackageInfo pkgInfo;
try {
pkgInfo = pm.getPackageInfo(packageName, flags | PackageManager.GET_ACTIVITIES | PackageManager.GET_SERVICES | PackageManager.GET_RECEIVERS | PackageManager.GET_PROVIDERS, userId);
@ -176,4 +195,87 @@ public class PackageService {
return null;
return pkgInfo;
}
static abstract class IntentSenderAdaptor extends IIntentSender.Stub {
public abstract void send(Intent intent);
@Override
public int send(int code, Intent intent, String resolvedType, IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) {
send(intent);
return 0;
}
@Override
public void send(int code, Intent intent, String resolvedType, IBinder whitelistToken, IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) {
send(intent);
}
public IntentSender getIntentSender() throws IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchMethodException {
@SuppressWarnings("JavaReflectionMemberAccess")
Constructor<IntentSender> intentSenderConstructor = IntentSender.class.getConstructor(IIntentSender.class);
intentSenderConstructor.setAccessible(true);
return intentSenderConstructor.newInstance(this);
}
}
private static void uninstallPackage(VersionedPackage versionedPackage) throws RemoteException, InterruptedException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
CountDownLatch latch = new CountDownLatch(1);
pm.getPackageInstaller().uninstallExistingPackage(versionedPackage, "com.android.shell", new IntentSenderAdaptor() {
@Override
public void send(Intent intent) {
latch.countDown();
}
}.getIntentSender(), 0);
latch.await();
}
public static synchronized boolean installManagerIfAbsent(String packageName, File apkFile) {
IPackageManager pm = getPackageManager();
if (pm == null) return false;
try {
PackageInfo pkgInfo = pm.getPackageInfo(packageName, 0, 0);
if (pkgInfo != null && pkgInfo.versionName != null && pkgInfo.versionName.equals(BuildConfig.VERSION_NAME) && pkgInfo.applicationInfo != null && InstallerVerifier.verifyInstallerSignature(pkgInfo.applicationInfo))
return false;
// manager is not installed or version not matched, install stub
if (pkgInfo != null) {
uninstallPackage(new VersionedPackage(pkgInfo.packageName, pkgInfo.versionCode));
}
IPackageInstaller installerService = pm.getPackageInstaller();
String installerPackageName = "com.android.shell";
@SuppressWarnings("JavaReflectionMemberAccess")
Constructor<PackageInstaller> installerConstructor = PackageInstaller.class.getConstructor(IPackageInstaller.class, String.class, int.class);
installerConstructor.setAccessible(true);
PackageInstaller installer = installerConstructor.newInstance(installerService, installerPackageName, 0);
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*/;
HiddenApiBridge.PackageInstaller_SessionParams_installFlags(params, installFlags);
int sessionId = installer.createSession(params);
try (PackageInstaller.Session session = installer.openSession(sessionId)) {
try (InputStream is = new FileInputStream(apkFile); OutputStream os = session.openWrite(apkFile.getName(), 0, -1)) {
byte[] buf = new byte[8192];
int len;
while ((len = is.read(buf)) > 0) {
os.write(buf, 0, len);
os.flush();
session.fsync(os);
}
}
session.commit(new IntentSenderAdaptor() {
@Override
public void send(Intent result) {
int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS, PackageInstaller.STATUS_FAILURE);
String message = result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE);
Log.d(TAG, status + " " + message);
}
}.getIntentSender());
}
return true;
} catch (Throwable e) {
Log.e(TAG, e.getMessage(), e);
return false;
}
}
}

View File

@ -192,11 +192,6 @@ else
ui_print " - ${LANG_CUST_INST_CONF_NEW} ${MISC_RAND}"
mkdir -p /data/adb/lspd || abortC "! ${LANG_CUST_ERR_CONF_CREATE}"
echo "$MISC_PATH" > /data/adb/lspd/misc_path || abortC "! ${LANG_CUST_ERR_CONF_STORE}"
if [[ -d /data/user_de/0/io.github.lsposed.manager/conf/ ]]; then
mkdir -p /data/misc/$MISC_PATH/0/conf
cp -r /data/user_de/0/io.github.lsposed.manager/conf/* /data/misc/$MISC_PATH/0/conf/
set_perm_recursive /data/misc/$MISC_PATH 0 0 0771 0660 "u:object_r:magisk_file:s0" || abortC "! ${LANG_CUST_ERR_PERM}"
fi
fi
touch /data/adb/lspd/new_install || abortC "! ${LANG_CUST_ERR_CONF_FIRST}"
ui_print "- ${LANG_CUST_INST_COPY_LIB}"

View File

@ -19,6 +19,7 @@
package hidden;
import android.content.pm.PackageInstaller;
import android.content.res.AssetManager;
import android.content.res.Resources;
import android.content.res.ResourcesImpl;
@ -37,4 +38,12 @@ public class HiddenApiBridge {
public static void Resources_setImpl(Resources resources, ResourcesImpl impl) {
resources.setImpl(impl);
}
public static int PackageInstaller_SessionParams_installFlags(PackageInstaller.SessionParams params) {
return params.installFlags;
}
public static void PackageInstaller_SessionParams_installFlags(PackageInstaller.SessionParams params, int flags) {
params.installFlags = flags;
}
}

View File

@ -0,0 +1,34 @@
package android.content;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.os.IInterface;
import androidx.annotation.RequiresApi;
public interface IIntentSender extends IInterface {
int send(int code, Intent intent, String resolvedType,
IIntentReceiver finishedReceiver, String requiredPermission, Bundle options);
@RequiresApi(26)
void send(int code, Intent intent, String resolvedType, IBinder whitelistToken,
IIntentReceiver finishedReceiver, String requiredPermission, Bundle options);
abstract class Stub extends Binder implements IIntentSender {
public Stub() {
throw new UnsupportedOperationException();
}
@Override
public android.os.IBinder asBinder() {
throw new UnsupportedOperationException();
}
public static IIntentSender asInterface(IBinder binder) {
throw new UnsupportedOperationException();
}
}
}

View File

@ -0,0 +1,4 @@
package android.content;
public class IntentSender {
}

View File

@ -0,0 +1,18 @@
package android.content.pm;
import android.content.IntentSender;
import android.os.Binder;
import android.os.IBinder;
import android.os.IInterface;
public interface IPackageInstaller extends IInterface {
void uninstallExistingPackage(VersionedPackage versionedPackage, String callerPackageName,
IntentSender statusReceiver, int userId);
abstract class Stub extends Binder implements IPackageInstaller {
public static IPackageInstaller asInterface(IBinder obj) {
throw new UnsupportedOperationException();
}
}
}

View File

@ -46,6 +46,8 @@ public interface IPackageManager extends IInterface {
int checkUidPermission(String permName, int uid)
throws RemoteException;
IPackageInstaller getPackageInstaller() throws RemoteException;
abstract class Stub extends Binder implements IPackageManager {
public static IPackageManager asInterface(IBinder obj) {

View File

@ -0,0 +1,7 @@
package android.content.pm;
public class PackageInstaller {
public static class SessionParams {
public int installFlags = 0;
}
}

View File

@ -0,0 +1,4 @@
package android.content.pm;
public class VersionedPackage {
}