Android LOCAL_JAVA_RESOURCE_FILES 的妙用

简介

在研究Android系统开机流程的时候,看到preloaded-classes被用来做预加载类的载体,但没明白它是怎么编译到系统中的。因此,特意去研究了下,特此记录下来。

将preloaded-classes编译到framework.jar中

frameworks/base/Android.mk

include $(CLEAR_VARS)

LOCAL_MODULE := framework
LOCAL_MODULE_CLASS := JAVA_LIBRARIES
LOCAL_NO_STANDARD_LIBRARIES := true
LOCAL_STATIC_JAVA_LIBRARIES := framework-base
LOCAL_DX_FLAGS := --core-library

# Packages to include, use \* wildcard to include descendants.
LOCAL_JAR_PACKAGES := android\*

# List of classes and interfaces which should be loaded by the Zygote.
LOCAL_JAVA_RESOURCE_FILES += $(LOCAL_PATH)/preloaded-classes

include $(BUILD_JAVA_LIBRARY)

LOCAL_JAVA_RESOURCE_FILES 将文件编译到对应的jar文件中。例如上面的preloaded-classes就会被编译到framework.jar中。如图:

out/target/product/xxx/system/framework/framework.jar

这里写图片描述

读取framework.jar中preloaded-classes的内容

那我们要怎么调用这个jar包中的文件呢?系统framework中给出了调用方法,代码如下:

frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

private static final String PRELOADED_CLASSES = "preloaded-classes";

private static void preloadClasses() {
        InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream(
                PRELOADED_CLASSES);
        if (is == null) {
            Log.e(TAG, "Couldn't find " + PRELOADED_CLASSES + ".");
        } else {
            ...
            try {
                BufferedReader br
                    = new BufferedReader(new InputStreamReader(is), 256);

                int count = 0;
                String line;
                while ((line = br.readLine()) != null) {
                    // Skip comments and blank lines.
                    line = line.trim();
                    if (line.startsWith("#") || line.equals("")) {
                            continue;
                    }
                    ...
                }
            } catch (IOException e) {
                Log.e(TAG, "Error reading " + PRELOADED_CLASSES + ".", e);
            } finally {
                IoUtils.closeQuietly(is);
                ...
            }
        }
    }

通过上面的代码我们知道,主要的读取的代码是这段

ClassLoader.getSystemClassLoader().getResourceAsStream(PRELOADED_CLASSES);

通过这段代码,我们可以获取到preloaded-classes的输入流,这样我们就可以读取其中的内容了。那问题来了,ClassLoader有什么怎么去读取的呢?这个放到下一篇文章来讲解,这里暂不讲解,只讲它的实现和调用。下面我们来看下怎么添加自己的文件到jar包,并去读取其内容呢,其实通过上面的分析,我们要添加自定义文件到framework.jar中也是非常简单的了。

添加自定义资源文件到framework.jar中

第一步 修改Android.mk

我们要添加自定义资源文件到jar中,我们只需要在mk文件,将LOCAL_JAVA_RESOURCE_FILES添加上我们的文件名即可,当然路径要一致。

frameworks/base/Android.mk

include $(CLEAR_VARS)

LOCAL_MODULE := framework

...

# List of classes and interfaces which should be loaded by the Zygote.
LOCAL_JAVA_RESOURCE_FILES += $(LOCAL_PATH)/preloaded-classes
LOCAL_JAVA_RESOURCE_FILES += $(LOCAL_PATH)/test.txt
LOCAL_JAVA_RESOURCE_FILES += $(LOCAL_PATH)/image.jpg

include $(BUILD_JAVA_LIBRARY)

上面我们通过LOCAL_JAVA_RESOURCE_FILES将test.txt和image.jpg添加到了framework.jar中。我们先看test.txt和image.jpg的内容。

frameworks/base/test.txt

“你知道吗,总有一天,你终将会变成你讨厌的人。”
“谢谢吉言,我讨厌有钱人。”

frameworks/base/image.jpg

这里写图片描述

第二步 编译framework.jar

在framework/base目录直接执行mm命令即可。

第三步 检查生成的framework.jar是否编译成功

打开out/target/product/xxx/system/framework/framework.jar,结果如图:

这里写图片描述

第四步 测试结果

先上测试结果,如下:

这里写图片描述

完美!!!

实现代码

TestActivity.java

    @Override
    protected void onCreate(Bundle arg0) {
        super.onCreate(arg0);
        setContentView(R.layout.test_layout);
        TextView mTV = (TextView) findViewById(R.id.id_tv);
        ImageView mIV = (ImageView) findViewById(R.id.id_iv);

        String text = "";
        InputStream isText = ClassLoader.getSystemResourceAsStream("test.txt");
        if (isText != null) {
            BufferedReader br = new BufferedReader(new InputStreamReader(isText));
            String line;
            try {
                while ((line = br.readLine()) != null) {
                    Log.d("TAG", "line:"+line);
                    text += line + "\n";
                }
            } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                isText.close();
                isText = null;
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        mTV.setText(text);
    }

    InputStream isImage = ClassLoader.getSystemResourceAsStream("image.jpg");
        if (isImage != null) {
            Bitmap bitmap = BitmapFactory.decodeStream(isImage);
            if (bitmap != null) {
                mIV.setImageBitmap(bitmap);
            }

            try {
                isImage.close();
                isImage = null;
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

test_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <TextView
        android:id="@+id/id_tv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textAppearance="?android:attr/textAppearanceMedium"/>

    <ImageView
        android:id="@+id/id_iv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/ic_launcher" />

</LinearLayout>

:我这里使用的是ClassLoader.getSystemResourceAsStream,其实跟ClassLoader.getSystemClassLoader().getResourceAsStream是一样的,只不过系统已经将封装好了。看下代码你就明白了。

public static InputStream getSystemResourceAsStream(String resName) {
    return SystemClassLoader.loader.getResourceAsStream(resName);
}

public static ClassLoader getSystemClassLoader() {
    return SystemClassLoader.loader;
}

所以它们调用的是同一个方法。有源码的同学可以实际操作一把,理解就深刻了。争取下一篇文章写一下ClassLoader getSystemResourceAsStream的调用流程。

总结

Read The Fucking Source Code

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值