Tencent / tinker

Tinker is a hot-fix solution library for Android, it supports dex, library and resources update without reinstall apk.
Other
17.1k stars 3.33k forks source link

关于获取任务列表导致的合规问题 #1577

Open lhjandroid opened 3 years ago

lhjandroid commented 3 years ago

hello 最近在做关于app合规相关问题 下面是我使用的版本 tinker版本:如:1.9.14.6

其中遇到的合规问题是

{'className':'android.app.ActivityManager','methodName':'getRunningAppProcesses','fileName':'ActivityManager.java','level':0,'lineNumber':3460},

{'className':'com.tencent.tinker.loader.shareutil.ShareTinkerInternals','methodName':'getProcessNameInternal','fileName':'ShareTinkerInternals.java','level':0,'lineNumber':496},

{'className':'com.tencent.tinker.loader.shareutil.ShareTinkerInternals','methodName':'getProcessName','fileName':'ShareTinkerInternals.java','level':0,'lineNumber':477},

{'className':'com.tencent.tinker.loader.shareutil.ShareTinkerInternals','methodName':'isInPatchProcess','fileName':'ShareTinkerInternals.java','level':0,'lineNumber':408},

{'className':'com.tencent.tinker.loader.TinkerLoader','methodName':'tryLoadPatchFilesInternal','fileName':'TinkerLoader.java','level':0,'lineNumber':72},

{'className':'com.tencent.tinker.loader.TinkerLoader','methodName':'tryLoad','fileName':'TinkerLoader.java','level':0,'lineNumber':58},{'className':'java.lang.reflect.Method','methodName':'invoke','fileName':'Method.java','level':0,'lineNumber':-2},

关于获取进程列表问题

private static String getProcessNameInternal(final Context context) {
        int myPid = android.os.Process.myPid();

        if (context == null || myPid <= 0) {
            return "";
        }

        ActivityManager.RunningAppProcessInfo myProcess = null;
        ActivityManager activityManager =
            (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);

        if (activityManager != null) {
            try {
                List<ActivityManager.RunningAppProcessInfo> appProcessList = activityManager
                    .getRunningAppProcesses();

                if (appProcessList != null) {
                    for (ActivityManager.RunningAppProcessInfo process : appProcessList) {
                        if (process.pid == myPid) {
                            myProcess = process;
                            break;
                        }
                    }

                    if (myProcess != null) {
                        return myProcess.processName;
                    }
                }
            } catch (Exception e) {
                Log.e(TAG, "getProcessNameInternal exception:" + e.getMessage());
            }
        }

因为这块涉及到未授权就获取了,有什么解决方案吗?或者你们有什么好的建议呢

Woaijiangnanyu commented 3 years ago

求解

lhjandroid commented 3 years ago

求解

已经解决,通过自定义tinker loader

mjnhmd commented 2 years ago

求解

已经解决,通过自定义tinker loader

求问怎么改的呀,我们也遇到了同样的问题

lhjandroid commented 2 years ago

求解

已经解决,通过自定义tinker loader

求问怎么改的呀,我们也遇到了同样的问题

Lark20210722-113437

lhjandroid commented 2 years ago

主要是注释的地方,但合规还不止这一处,我记得还有个地方需要修改,还有这个获取进程列表其实是有新的方式获取了

mjnhmd commented 2 years ago

主要是注释的地方,但合规还不止这一处,我记得还有个地方需要修改,还有这个获取进程列表其实是有新的方式获取了

就是说有合规的获取方式吗?

fine1021 commented 2 years ago

可以试试我目前的方法 首先 自定义 TinkerLoader,为了代码的低侵入性,使用继承的方法

image

class MyApplication extend TinkerApplication的时候指定自定义的 TinkerLoader

其中 val processName = context.getProcessName()是一个扩展方法,核心实现如下:

image

image

这么操作的原因 ,从调用堆栈上来看,getRunningAppProcesses方法被调用,都是因为ShareTinkerInternals内部获取了当前的进程名,但是 ShareTinkerInternals. getProcessName的方法也给了外部一个hook的可能,为了不走Tinker本身的getProcessNameInternal方法,自己获取ProcessName的时候,在不违反合规审核的前提下,实在无法获取到ProcessName就返回一个空的字符串来占位,尽可能阻止getProcessNameInternal方法的调用

image

image

@mjnhmd @Woaijiangnanyu

lhjandroid commented 2 years ago

和之前上面说的一样 1.在隐私协议同意前不去加载补丁,其实问题不是出现在初始化上,问题出现在加载补丁时会判断当前是否在pach进程,很早已经给出了解决方案,直接return 在同意隐私协议后再进行补丁的加载,不用修改之前的初始化tinker的流程代码,只需要你替换下tinkerLoad,用上面给的自定义tinkerLoader。2. 高版本的api中有新方式来获取当前进程名。分为新api,反射调用,最后才是getAppRunProcess。在tinker中获取当前进程和是否是补丁进程可以替换成新方案,代码和上面老哥贴的一样,来自于网络收集的获取当前进程方案```public class ProcessUtil {

public static final String  PATCH_PROCESS_NAME    = ":patch";

/**
 * @return 当前进程名
 */
public static String getCurrentProcessName(Context context) {
    String currentProcessName = null;
    if (!MFCommonUtils.isEmpty(currentProcessName)) {
        return currentProcessName;
    }

    //1)通过Application的API获取当前进程名
    currentProcessName = getCurrentProcessNameByApplication();
    if (!MFCommonUtils.isEmpty(currentProcessName)) {
        return currentProcessName;
    }

    //2)通过反射ActivityThread获取当前进程名
    currentProcessName = getCurrentProcessNameByActivityThread();
    if (!MFCommonUtils.isEmpty(currentProcessName)) {
        return currentProcessName;
    }

    //3)通过ActivityManager获取当前进程名
    currentProcessName = getCurrentProcessNameByActivityManager(context);

    return currentProcessName;
}

/**
 * 通过Application新的API获取进程名,无需反射,无需IPC,效率最高。
 */
public static String getCurrentProcessNameByApplication() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
        return Application.getProcessName();
    }
    return null;
}

/**
 * 通过反射ActivityThread获取进程名,避免了ipc
 */
public static String getCurrentProcessNameByActivityThread() {
    String processName = null;
    try {
        final Method declaredMethod = Class.forName("android.app.ActivityThread", false, Application.class.getClassLoader())
                .getDeclaredMethod("currentProcessName", (Class<?>[]) new Class[0]);
        declaredMethod.setAccessible(true);
        final Object invoke = declaredMethod.invoke(null, new Object[0]);
        if (invoke instanceof String) {
            processName = (String) invoke;
        }
    } catch (Throwable e) {
        e.printStackTrace();
    }
    return processName;
}

/**
 * 通过ActivityManager 获取进程名,需要IPC通信
 */
public static String getCurrentProcessNameByActivityManager(Context context) {
    if (context == null) {
        return null;
    }
    int pid = android.os.Process.myPid();
    ActivityManager am = ((ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE));
    if (am != null) {
        List<ActivityManager.RunningAppProcessInfo> runningAppProcesses = am.getRunningAppProcesses();
        for (ActivityManager.RunningAppProcessInfo info : runningAppProcesses) {
            if (info.pid == pid) {
                return info.processName;
            }
        }
    }
    return null;
}

/**
 * 是否是补丁进程
 * @param context
 * @return
 */
public static boolean isInPatchProcess(Context context) {
    // 现通过优化的方式去获取当前进程名
    String processName = getCurrentProcessName(context);
    if (!MFCommonUtils.isEmpty(processName)) {
        return processName.endsWith(PATCH_PROCESS_NAME);
    }
    // 如果没有获取成功用tinker自带的方式去判断
    return ShareTinkerInternals.isInPatchProcess(context);
}

/**
 * 判断tinker是否在主线程中
 * @param context
 * @return
 */
public static boolean isTinkerInMainProcess(Context context) {
    if (context == null) {
        return false;
    }
    String mainProcessName = "";
    ApplicationInfo applicationInfo = context.getApplicationInfo();
    if (applicationInfo != null) {
        mainProcessName = applicationInfo.processName;
    }
    // 先通过优化方式去获取进程名 如果获取失败 通过最后的return方式去获取
    String currentProcessName = getCurrentProcessName(context);
    if (!MFCommonUtils.isEmpty(currentProcessName)) {
        return currentProcessName.equals(mainProcessName);
    }
    return ShareTinkerInternals.isInMainProcess(context);
}

}```