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

--- 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

--- 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

  --- 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

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

--- 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

--- 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

--- 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

--- 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名稱。

二、具體實現代碼

  該部分代碼的業務邏輯比較容易理解,就是一個簡單工廠模式的使用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;
      }

}

三、調用代碼

  本章節主要介紹一下怎麼調用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的方式已簡單介紹完畢。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章