Android Studio中如何全局搜索字节码中的内容?

1 我们的使用痛点是什么?

当我们使用Android Studio 搜索 MainActivity 的时候可以查到内容,好像看起来很方便?
在这里插入图片描述
但是如果关键字在class文件中,那么就搜索不到了。
在这里插入图片描述

2 我们为什么需要查看class文件中的内容呢?

我们App上线之后发现用户使用流量猛增,使用各种统计手段发现程序大量创建一个名为 “xxx” (因为避免涉密不具体贴出来字符,可以看上面图片中的字符串)的线程,这个线程是谁创建的? 我们上来先搜索这个"xxx"发现我们的代码中并没有创建过这个线程,那么是谁创建的呢?

怀疑是什么aar导致的,于是我们要排查到底是哪个aar导致的呢?
在这里插入图片描述

3 写代码把aar拷贝到目标文件夹中

注意是使用Android Studio 运行 Java项目,不知道怎么运行java项目可以看Android Studio运行JAVA程序

public class Grep {
    public static final String GRADLE_CACHE_PATH = "/Users/liangchaojie/.gradle/caches/transforms-1/files-1.1";
    public static final String TARGET_PATH = "/Users/liangchaojie/Desktop/result";

    private static int mCopyCount = 0;
    private static int mUnZipCount = 0;
    private static int mDeleteCount = 0;


    public static void main(String[] args) {
        File file = new File(GRADLE_CACHE_PATH);
        // 1 先把缓存中的文件拷贝到指定的文件夹中
        traverseCopy(file);
        System.out.println("traverseCopy file number ="+mCopyCount);
        // 2 把所有的jar文件解压出来到指定的文件夹中
        tarJarFile(TARGET_PATH);
        //  3 删除掉之前存在的jar文件
        deleteJarFile(TARGET_PATH);
    }

    /**
     * 遍历复制gradle cache 中的classes.jar到 指定目录中去
     *
     * @param file
     */
    private static void traverseCopy(File file) {
        File[] fs = file.listFiles();
        for (File f : fs) {
            if (f.isDirectory())    //若是目录,则递归打印该目录下的文件
            {
                traverseCopy(f);
            } else if (f.isFile() && "classes.jar".equals(f.getName()))        //若是文件,直接打印
            {
                mCopyCount++;
                String sourcePath = f.getAbsolutePath();
                String aarName = getSimpleAarPathName(f.getAbsolutePath());
                String targetPath = getTargetPathName(aarName);


                File fileTargetFile = new File(targetPath);
                // 如果文件已经存在就不用去拷贝了
                if(fileTargetFile.exists()){
                    continue;
                }
                copyFile(sourcePath, targetPath);
            }
        }
    }

    /**
     * 返回类似 homepage-api-2.5.30
     * @param path
     * @return
     */
    private static String getSimpleAarPathName(String path) {
        String aarNameFirst = path.substring(path.indexOf("files-1.1/") + 10, path.indexOf(".aar/"));
        String aarNameLast = path.substring(path.indexOf(".aar/") + 5, path.indexOf(".aar/") + 10);
        return aarNameFirst+"-"+aarNameLast;
    }

    private static String getTargetPathName(String aarName) {
        return TARGET_PATH + "/" + aarName  +".jar";
    }


    public static void copyFile(String source, String target) {

        try (FileInputStream fis = new FileInputStream(new File(source));
             FileOutputStream fos = new FileOutputStream(new File(target))) {
            FileChannel sourceChannel = fis.getChannel();
            FileChannel targetChannel = fos.getChannel();
            MappedByteBuffer mappedByteBuffer = sourceChannel.map(FileChannel.MapMode.READ_ONLY, 0, sourceChannel.size());
            targetChannel.write(mappedByteBuffer);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    private static void deleteJarFile(String targetPath) {
        File[] fs = new File(targetPath).listFiles();
        for (File f : fs) {
            if (f.isFile() && f.getName().contains(".jar")) {
                mDeleteCount++;
                f.delete();
            }
        }
        System.out.println(" deleteJarFile file number = " + mDeleteCount);
    }


    /**
     * 把指定目录中的  classes.jar 解压到文件中
     */
    private static void tarJarFile(String targetPath) {
        File[] fs = new File(targetPath).listFiles();

        for (File f : fs) {
            if (f.isFile() && f.getName().contains(".jar")) {

                mUnZipCount++;
                String directory = f.getName().substring(0, f.getName().lastIndexOf(".jar"));
                String targetPathDirectory = TARGET_PATH + "/" + directory + "/";

                File targetPathDirectoryFile = new File(targetPathDirectory);
                // 如果已经创建过文件夹就不要去重复创建了
                if (targetPathDirectoryFile.exists()) {
                    continue;
                }
                 targetPathDirectoryFile.mkdirs();
                 UnZipUtils.unZip(f, targetPathDirectory);
            }
        }
        System.out.println(" tarJarFile file number = " + mUnZipCount);
    }
}

/**
 * 对文件进行解压操作
 */
public class UnZipUtils {
    private static final int  BUFFER_SIZE = 2 * 1024;


    /**
     * zip解压
     * @param srcFile        zip源文件
     * @param destDirPath     解压后的目标文件夹
     * @throws RuntimeException 解压失败会抛出运行时异常
     */
    public static void unZip(File srcFile, String destDirPath) throws RuntimeException {
        long start = System.currentTimeMillis();
        // 判断源文件是否存在
        if (!srcFile.exists()) {
            throw new RuntimeException(srcFile.getPath() + "所指文件不存在");
        }
        // 开始解压
        ZipFile zipFile = null;
        try {
            zipFile = new ZipFile(srcFile);
            Enumeration<?> entries = zipFile.entries();
            while (entries.hasMoreElements()) {
                ZipEntry entry = (ZipEntry) entries.nextElement();
                // 如果是文件夹,就创建个文件夹
                if (entry.isDirectory()) {
                    String dirPath = destDirPath + "/" + entry.getName();
                    File dir = new File(dirPath);
                    dir.mkdirs();
                } else {
                    // 如果是文件,就先创建一个文件,然后用io流把内容copy过去
                    File targetFile = new File(destDirPath + "/" + entry.getName());
                    // 保证这个文件的父文件夹必须要存在
                    if(!targetFile.getParentFile().exists()){
                        targetFile.getParentFile().mkdirs();
                    }
                    targetFile.createNewFile();
                    // 将压缩文件内容写入到这个文件中
                    InputStream is = zipFile.getInputStream(entry);
                    FileOutputStream fos = new FileOutputStream(targetFile);
                    int len;
                    byte[] buf = new byte[BUFFER_SIZE];
                    while ((len = is.read(buf)) != -1) {
                        fos.write(buf, 0, len);
                    }
                    // 关流顺序,先打开的后关闭
                    fos.close();
                    is.close();
                }
            }
            long end = System.currentTimeMillis();
        } catch (Exception e) {
            throw new RuntimeException("unzip error from ZipUtils", e);
        } finally {
            if(zipFile != null){
                try {
                    zipFile.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

}

4 命令行查看具体的内容

grep  "xxx" -r /Users/liangchaojie/Desktop/result

在这里插入图片描述
用Android Studio打开这个a.class,确实发现创建了线程

在这里插入图片描述
完结撒花~

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值