Android TV 编译自定义jar

  在之前的文章中,介绍了如何在Framework中添加接口。当时添加的接口是编译到ROM原有的jar包中,如果framework中定制需求较多,可以将Framework原有代码与需求实现代码分开,将定制需求实现代码编译到一个jar中。这样Framework层代码就变得较为整洁,容易维护。
  本文以Amlogic905代码为例,通过一个简单的demo,来简单介绍下怎么编出一个定制的jar。该demo需求如下:
    1>编出的jar名称为ysten.jar。
    2>通过判断不同的属性(persist.sys.yst.province)来获取不同的Intent。

一、添加编译项

  这个章节介绍下定制jar的编译配置。既然就要配置编译项,就需要了解下Android系统的编译过程。Android的编译过程是个较大的课题,本章节只是简单介绍。

1.1 Android编译过程

  1>source build/envsetup.sh
   该步骤调用了build/envsetup.sh脚本,其主要作用是初始化编译环境,加载了编译时使用到的函数(help、lunch,m,mm,mmm等)命令。
  2>lunch p201_iptv-eng
   该步骤的作用是调用lunch函数,用来指定此次编译的目标设备选项以及编译类型。目标设备选项可以用芯片原生的,也可以由厂商自己添加,如p201_iptv就是芯片原有的编译项。至于编译类型,可以这样简单理解:

编译类型 意义
eng debug版本
user release版本
userdebug 部分debug版本

  3>make otapackage -j32 2>&1
   该步骤才开始进行真正的编译,make 的参数“-j”指定了同时编译的Job数量,这是个整数,该值通常是编译服务器CPU支持的并发线程总数的1倍或2倍。
   执行make命令的结果就是去执行当前目录下的Makefile文件,编译命令是在系统源码根目录执行的,所以首先执行到的就是根目录的Makefile文件,然后一路追下去就是不断调用其他.mk(也包括Android.mk这个最常用的.mk文件)的过程。
   以Makefile和Android.mk为例,这两个文件可以简单理解为编译过程中最大的和最小的模块。Makefile文件控制整个Android系统源码的编译规则:如指定需要生成哪些目标文件、指定生成这些目标文件依赖哪些源文件、职工生成的目标文件放在哪个文件夹下等等。make就是一个命令工具,可以解析Makefile文件中的指令的一个命令工具。Android.mk也是一样的功能,只不过它是Android编译环境下的一种特殊的Makefile文件,格式非常简单,且与普通的Makefile文件书写格式不一样。

1.2 要添加的编译选项

  由1.1章节可知,要添加编译项其实就是要在一堆的mk文件中添加编译,至于为什么要在如下.mk文件中添加,主要参考的是android.policy.jar的编译项。具体如下:
   1.2.1> build/target/product/base.mk
    该文件中添加的编译型较多,不仅有framework层代码编出来的jar包,还有一些要编译出来的bin文件,如dhcpcd等,可简单理解为该文件中的编译型是Android系统所需要的基本编译项。

--- a/build/target/product/base.mk
+++ b/build/target/product/base.mk
@@ -20,6 +20,7 @@ PRODUCT_PACKAGES += \
    95-configured \
    am \
    android.policy \
+   ysten \
    android.test.runner \

   1.2.2> build/target/product/core_base.mk
    该文件中定义了PRODUCT_BOOT_JARS变量,该变量的值最终被编译到system/framework,并被添加到BOOTCLASSPATH路径。

--- a/build/target/product/core_base.mk
+++ b/build/target/product/core_base.mk
@@ -68,4 +68,4 @@ PRODUCT_PACKAGES += \

$(call inherit-product, $(SRC_TARGET_DIR)/product/core_minimal.mk)
# Override the PRODUCT_BOOT_JARS set in core_minimal.mk
-PRODUCT_BOOT_JARS := core:conscrypt:okhttp:core-junit:bouncycastle:ext:framework:framework2:telephony-common:voip-common:mms-common:android.policy:services:apache-xml:webviewchromium
+PRODUCT_BOOT_JARS := core:conscrypt:okhttp:core-junit:bouncycastle:ext:framework:framework2:telephony-common:voip-common:mms-common:android.policy:ysten:services:apache-xml:webviewchromium

   1.2.3> build/target/product/core_minimal.mk
    该文件中也是定义了PRODUCT_BOOT_JARS变量,作用不再赘述。

  --- a/build/target/product/core_minimal.mk
+++ b/build/target/product/core_minimal.mk
@@ -55,7 +55,7 @@ PRODUCT_PACKAGES += \
     sensorservice \
     uiautomator
 
-PRODUCT_BOOT_JARS := core:conscrypt:okhttp:core-junit:bouncycastle:ext:framework:framework2:android.policy:services:apache-xml:webviewchromium
+PRODUCT_BOOT_JARS := core:conscrypt:okhttp:core-junit:bouncycastle:ext:framework:framework2:android.policy:ysten:services:apache-xml:webviewchromium

   1.2.4> build/tools/releasetools/default_filesystem_config.txt
    该文件的作用是指定system目录及其子目录下文件的权限配置信息, 如system/bin、system/fonts等。

diff --git a/build/tools/releasetools/default_filesystem_config.txt b/build/tools/releasetools/default_filesystem_config.txt
index 476d457..73c23f1 100755
--- a/build/tools/releasetools/default_filesystem_config.txt
+++ b/build/tools/releasetools/default_filesystem_config.txt
@@ -452,6 +452,7 @@ system/framework/ime.jar 0 0 644
system/framework/com.google.widevine.software.drm.jar 0 0 644
system/framework/input.jar 0 0 644
system/framework/android.policy.jar 0 0 644
+system/framework/ysten.jar 0 0 644
system/framework/javax.obex.jar 0 0 644
system/framework/android.test.runner.jar 0 0 644
system/framework/svc.jar 0 0 644

   1.2.5> dalvik/docs/hello-world.html
    在上面的一些脚本中,在PRODUCT_BOOT_JARS变量里添加了ysten.jar。在该文件中,导入PRODUCT_BOOT_JARS变量。

--- a/dalvik/docs/hello-world.html
+++ b/dalvik/docs/hello-world.html
@@ -168,7 +168,7 @@ export ANDROID_ROOT=$root

# configure bootclasspath
bootpath=$root/framework
-export BOOTCLASSPATH=$bootpath/core.jar:$bootpath/ext.jar:$bootpath/framework.jar:$bootpath/android.policy.jar:$bootpath/services.jar
+export BOOTCLASSPATH=$bootpath/core.jar:$bootpath/ext.jar:$bootpath/framework.jar:$bootpath/android.policy.jar:$bootpath/ysten.jar:$bootpath/services.jar

   1.2.6> device/amlogic/common/base.mk
    该文件中也是定义了一些Android系统所需要的基本编译项。

--- a/device/amlogic/common/base.mk
+++ b/device/amlogic/common/base.mk
@@ -20,6 +20,7 @@ PRODUCT_PACKAGES += \
    95-configured \
    am \
    android.policy \
+   ysten \
    android.test.runner \
    app_process \
    applypatch \
@@ -114,4 +115,4 @@ $(call inherit-product, $(SRC_TARGET_DIR)/product/embedded.mk)

$(call inherit-product, $(SRC_TARGET_DIR)/product/core_minimal.mk)
# Override the PRODUCT_BOOT_JARS set in core_minimal.mk
-PRODUCT_BOOT_JARS := core:conscrypt:okhttp:core-junit:bouncycastle:ext:framework:framework2:telephony-common:voip-common:mms-common:android.policy:services:apache-xml:webviewchromium
+PRODUCT_BOOT_JARS := core:conscrypt:okhttp:core-junit:bouncycastle:ext:framework:framework2:telephony-common:voip-common:mms-common:android.policy:ysten:services:apache-xml:webviewchromium

   1.2.7> device/amlogic/common/tv_amlogic.mk
    该文件中也是定义了PRODUCT_BOOT_JARS变量,作用不再赘述。

--- a/device/amlogic/common/tv_amlogic.mk
+++ b/device/amlogic/common/tv_amlogic.mk
@@ -257,4 +257,4 @@ PRODUCT_MANUFACTURER := TV
PRODUCT_CHARACTERISTICS := TV

# Override the PRODUCT_BOOT_JARS set in core_minimal.mk
-PRODUCT_BOOT_JARS := core:conscrypt:okhttp:core-junit:bouncycastle:ext:framework:framework2:telephony-common:voip-common:mms-common:android.policy:services:apache-xml:webviewchromium:tv
+PRODUCT_BOOT_JARS := core:conscrypt:okhttp:core-junit:bouncycastle:ext:framework:framework2:telephony-common:voip-common:mms-common:android.policy:ysten:services:apache-xml:webviewchromium:tv

   1.2.8> external/smali/baksmali/src/main/java/org/jf/baksmali/main.java
      该文件中添加ysten.jar的作用是将ysten.jar添加到bootclasspath

--- a/external/smali/baksmali/src/main/java/org/jf/baksmali/main.java
+++ b/external/smali/baksmali/src/main/java/org/jf/baksmali/main.java
@@ -295,7 +295,7 @@ public class main {
                 deodex = false;
 
                 if (bootClassPath == null) {
-                    bootClassPath = "core.jar:ext.jar:framework.jar:android.policy.jar:services.jar";
+                    bootClassPath = "core.jar:ext.jar:framework.jar:android.policy.jar:ysten.jar:services.jar";
                 }
             }
 
@@ -416,7 +416,7 @@ public class main {
 
         Option classPathOption = OptionBuilder.withLongOpt("bootclasspath")
                 .withDescription("the bootclasspath jars to use, for analysis. Defaults to " +
-                        "core.jar:ext.jar:framework.jar:android.policy.jar:services.jar. If the value begins with a " +
+                        "core.jar:ext.jar:framework.jar:android.policy.jar:ysten.jar:services.jar. If the value begins with a " +
                         ":, it will be appended to the default bootclasspath instead of replacing it")
                 .hasOptionalArg()
                 .withArgName("BOOTCLASSPATH")

   1.2.9> frameworks/base/CleanSpec.mk

--- a/frameworks/base/CleanSpec.mk
+++ b/frameworks/base/CleanSpec.mk
@@ -53,6 +53,8 @@ $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framew
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/FrameworkTest_intermediates/)
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/android.policy*)
$(call add-clean-step, rm -rf $(TARGET_OUT_JAVA_LIBRARIES)/android.policy.jar)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/ysten*)
+$(call add-clean-step, rm -rf $(TARGET_OUT_JAVA_LIBRARIES)/ysten.jar)
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates)
$(call add-clean-step, rm -f $(PRODUCT_OUT)/obj/lib/libequalizer.so)
$(call add-clean-step, rm -f $(PRODUCT_OUT)/obj/lib/libequalizertest.so)

   1.2.10> frameworks/base/ysten/Android.mk
      这个文件是新加的文件,内容如下:

LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)

LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_MODULE := ysten
include $(BUILD_JAVA_LIBRARY)

include $(call all-makefiles-under,$(LOCAL_PATH))

      该文件中主要的内容有两块:
        1)LOCAL_SRC_FILES,该变量定义的是所需要的源码目录。
        2)LOCAL_MODULE,该变量定义的是jar名称。

二、jar功能实现

  该部分代码的业务逻辑比较容易理解,就是一个简单工厂模式的使用demo。至于目录结构的设计,参考的是android.policy.jar对应的源码结构。
  ysten.jar对应的源码总路径是frameworks/base/ysten/src/com/ysten/am。这样编译出来的jar,import的路径就是src文件夹下的具体目录,即com.ysten.am。该目录下有三个文件,具体如下:

2.1 抽象基类

  本demo中对应的是frameworks/base/ysten/src/com/ysten/am/BaseActivity.java,该文件是一个抽象基类,定义一个抽象接口,内容如下:

package com.ysten.am;

import android.content.Intent;

public abstract  class BaseActivity {

    public abstract Intent getYstenHomeIntent();

}

2.2 具体实现类

  本demo中对应的是frameworks/base/ysten/src/com/ysten/am/DemoActivityManager.java,该文件是具体实现类,实现BaseActivity.java中定义的抽象接口,内容如下:

package com.ysten.am;

import android.content.Intent;
import android.content.ComponentName;

public class DemoActivityManager extends BaseActivity {

  private Intent intent = null;

  public DemoActivityManager(){
          intent = new Intent();
  }

  public Intent getYstenHomeIntent(){
       ComponentName componentName = new ComponentName("com.yst.whitebox","com.yst.whitebox.MainActivity");
       intent.setComponent(componentName);
       return intent;
  }

}

2.3 工厂类

  本demo中对应的是frameworks/base/ysten/src/com/ysten/am/ActivityFactory.java,该文件是一个子类生产的工厂,生产出什么类型的子类取决于调用的类中传下来的persist.sys.yst.province参数(本demo重点不在该模式的使用,所以只会产生一个子类),内如如下:

package com.ysten.am;

import android.util.Log;

public class ActivityFactory {

      private static final int PROVINCE_DEMO = 571;
      private BaseActivity baseActivity = null;
      private String TAG = "ActivityFactory";

      public BaseActivity getActivity(String tmpProvince){
           int province = Integer.parseInt(tmpProvince);
           Log.d(TAG,"the province is: "+province);

           switch(province){
                case PROVINCE_DEMO:
                        baseActivity = new DemoActivityManager();
           }
           return baseActivity;
      }

}

三、调用jar中接口

  本章节主要介绍一下怎么调用ysten.jar中的接口。主要分为两部分,具体如下:

3.1 声明jar

  本demo中声明使用该jar的地方是frameworks/base/services/java/Android.mk,内容如下:

--- a/frameworks/base/services/java/Android.mk
+++ b/frameworks/base/services/java/Android.mk
@@ -11,7 +11,7 @@ LOCAL_SRC_FILES := \

LOCAL_MODULE:= services

-LOCAL_JAVA_LIBRARIES := android.policy conscrypt telephony-common
+LOCAL_JAVA_LIBRARIES := android.policy conscrypt telephony-common ysten

3.2 使用jar

  本demo中使用的地方是frameworks/base/services/java/com/android/server/am/ActivityManagerService.java,即在该文件中调用ysten.jar中的接口,具体方式同调用其他系统原生jar中的方式一下,内容如下:

import com.ysten.am.*;

   private ActivityFactory activityFactory = new ActivityFactory();
    
   String tmpProvince = (SystemProperties.get("persist.sys.yst.province")).substring(1);
   BaseActivity baseActivity = activityFactory.getActivity(tmpProvince);
   if(baseActivity.getYstenHomeIntent() != null){
       intent = baseActivity.getYstenHomeIntent();
   }

  至此,添加定制jar的方式已简单介绍完毕。

猜你喜欢

转载自blog.csdn.net/m0_37741420/article/details/105936019