1. 程式人生 > >程式碼Overlay機制

程式碼Overlay機制



程式碼Overlay機制

程式碼overlay機制意思是,將我們在Android原生程式碼上修改過的檔案,單獨放在一個目錄下,而在編譯程式碼的時候就會去檢測這個目錄下的檔案,如果這個目錄下的檔案與原生有相同的檔案,那麼就將這個檔案放入編譯的原始檔中,而將原生相同檔名的檔案從編譯的原始檔中去除。

這樣做有什麼好處呢,比如我們和客戶合作,在我們自己的程式碼上加了某一個功能,於是動了原生的程式碼,而我們的客戶有時候不需要這個功能,那麼我們必須在原生上面去除這個程式碼,比如用git revert等。

但是如果我們有這樣一個程式碼overlay的機制,我們只要將我們修改的程式碼檔案去除就可以,這樣系統就會把原生的檔案放入編譯的原始檔中加入編譯。

1.建立overlay的檔案

比如我們需要對原生的PowerManagerService進行修改,首先我們先在伺服器程式碼根目錄建立一個比如:overlay這樣一個目錄,原生PowerManagerService的目錄: frameworks/base/services/core/java/com/android/server/power/PowerManagerService,

那麼如果我們對這個檔案修改,先拷貝一份PowerManagerService程式碼放在目錄:overlay/frameworks/base/services/core/java/com/android/server/power/PowerManagerService,

然後再去對這個目錄下的PowerManagerService進行修改。

2.修改Android.mk檔案

修改好了程式碼之後,就是修改編譯的Android.mk檔案,修改這檔案分為兩步,第一步是將我們修改程式碼加入編譯,第二步是將原生相同檔案從編譯中去除。

2.1將修改的程式碼加入編譯

我們還是舉例上面的PowerManagerService,其對應的Android.mk在目錄:

frameworks/base/services/core

我們先來看下原生的Android.mk檔案:

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := services.core

LOCAL_SRC_FILES += \
    $(call all-java-files-under,java) \
    java/com/android/server/EventLogTags.logtags \
    java/com/android/server/am/EventLogTags.logtags

LOCAL_JAVA_LIBRARIES := telephony-common
LOCAL_STATIC_JAVA_LIBRARIES := tzdata_update

include $(BUILD_STATIC_JAVA_LIBRARY)

我們先在修改這個檔案:

LOCAL_SRC_FILES這個變數程式碼參與編譯的檔案,因此我們第一步就是將我們的檔案放入這個變數中:

services_ext_subdirs := $(addprefix ../../../../overlay/, $(LOCAL_PATH)/)

services_ext_files := $(call all-java-files-under,$(services_ext_subdirs))

LOCAL_SRC_FILES += $(services_ext_files)

上面程式碼中LOCAL_PATH代表當前目錄:frameworks/base/services/core

因此要找到我們的overlay程式碼目錄,先要跳出frameworks這層,因此在LOCAL_PATH前面加了../../../../overlay/這個字首就到了overlay/frameworks/base/services/core目錄了,我們再查詢這個目錄下的java檔案,加入到LOCAL_SRC_FILES這個變數中就把我們修改的檔案加入到編譯中了。

2.2將原生相同檔案從編譯中去除

下面我們需要將原生相同檔案從編譯中去除,也就是把檔案從LOCAL_SRC_FILES這個變數中移除。

我們來看下程式碼實現:

empty :=

services_ext_overlay_files := $(subst $(services_ext_subdirs),$(empty),$(services_ext_files))

LOCAL_SRC_FILES := $(filter-out $(services_ext_overlay_files), $(LOCAL_SRC_FILES))

先把前面上一節中找到的java檔案中字首overlay/frameworks/base/services/core的直接把這個字首替換掉了,可以理解是直接刪除了這個字首。

比如PowerManagerService現在變成:

java/com/android/server/power/PowerManagerService

最後一行利用filter-out將上面這個檔案從LOCAL_SRC_FILES中去除,也就是將原生的檔案從編譯中去除。

這樣就達到了程式碼overlay的目的。

3.例子(修改PowerManager、IPowerManager.aidl、PowerManagerService)

當然這裡只是修改了PowerManagerService,下面我們通過PowerManager、IPowerManager.aidl整個修改來說下這個程式碼overlay機制。

首先我們先修改IPowerManager.aidl:新增一個printPower介面

interface IPowerManager
{
.............

    //set cpu boost
    void boostForPerformance(int cpu_nr, int duration);
    void printPower();//新增printPower介面
}

下面是PowerManager.java中的修改:

.......
    public void printPower() {
        try {
            mService.printPower();
        } catch (RemoteException e) {
        }
    }
......

當然這兩個檔案時overlay,我們需要重新放在overlay/frameworks/base/services/core/java/android/os/IPowerManager.aidl;

overlay/frameworks/base/services/core/java/android/os/PowerManager.java

3.1 修改frameworks/base/Android.mk

下一步我們就看frameworks/base/Android.mk裡面的修改:

include $(CLEAR_VARS)

# FRAMEWORKS_BASE_SUBDIRS comes from build/core/pathmap.mk
LOCAL_SRC_FILES := $(call find-other-java-files,$(FRAMEWORKS_BASE_SUBDIRS))//base 編譯java檔案目錄

#overlay
ifeq ($(LEADCORE_OVERLAY),true)//自己定義一個巨集開關
base_file_overlay_prefix := $(addprefix ../../overlay/, $(LOCAL_PATH)/)
base_file_overlay_subdir := $(addprefix $(base_file_overlay_prefix), $(FRAMEWORKS_BASE_SUBDIRS))//overlay下java檔案
$(warning $(base_file_overlay_subdir))
overlay_java_file = $(call find-other-java-files,$(base_file_overlay_subdir))
LOCAL_SRC_FILES += $(overlay_java_file)//把overlay下面base對應目錄的java檔案加入編譯

empty :=
base_overlay_files := $(subst $(base_file_overlay_prefix),$(empty),$(overlay_java_file))
$(warning $(base_overlay_files))

LOCAL_SRC_FILES := $(filter-out $(base_overlay_files), $(LOCAL_SRC_FILES))
endif

下面再來看看aidl檔案的overlay:

LOCAL_SRC_FILES += \
	core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl \
	core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl \
	core/java/android/accounts/IAccountManager.aidl \
	core/java/android/accounts/IAccountManagerResponse.aidl \
	core/java/android/accounts/IAccountAuthenticator.aidl \
	core/java/android/accounts/IAccountAuthenticatorResponse.aidl \
	core/java/android/app/IActivityContainer.aidl \
	core/java/android/app/IActivityContainerCallback.aidl \
	core/java/android/app/IActivityController.aidl \
	..........

#aidl files overlay	
ifeq ($(LEADCORE_OVERLAY),true) //巨集開關
//定義了一個變數用來去除原生的aidl檔案的
LOCAL_SRC_FILES := $(filter-out $(FRAMEWORKS_BASE_OVERLAY_AIDL_FILES), $(LOCAL_SRC_FILES))
//加入overlay下對應原生去除的aidl檔案
LOCAL_SRC_FILES += $(base_file_overlay_prefix)$(FRAMEWORKS_BASE_OVERLAY_AIDL_FILES)
//列印除錯
$(warning $(base_file_overlay_prefix)$(FRAMEWORKS_BASE_OVERLAY_AIDL_FILES))
endif

前PowerManager.java可以做到自動化,為什麼aidl做不到呢?因為在base的Android.mk中aidl都是一個一個選出來的,就連同一目錄有的參與編譯,有的不參與編譯,為了簡單起見做了一個變數FRAMEWORKS_BASE_OVERLAY_AIDL_FILES來儲存去除原生aidl檔案。

3.2 系統變數定義

下面我們看下這個變數的定義:其實在build/core/pathmap.mk

FRAMEWORKS_BASE_OVERLAY_AIDL_FILES := \
		core/java/android/os/IPowerManager.aidl

順便看下巨集開關的定義在build/core/envsetup.mk

LEADCORE_OVERLAY := true

最後就是PowerManagerService.java的編譯,前面分析過了,這邊再簡單介紹下:

先在PowerManagerService.java中修改PowerManagerService裡的BinderService增加一個介面如下:

	private final class BinderService extends IPowerManager.Stub {       
	.........
	   @Override // Binder call
        public void printPower() {
	    Slog.e(TAG, "printPower");
        }
	........

3.3修改frameworks/base/services/core/Android.mk

下面就是修改frameworks/base/services/core/Android.mk檔案

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := services.core

LOCAL_SRC_FILES += \
    $(call all-java-files-under,java) \
    java/com/android/server/EventLogTags.logtags \
    java/com/android/server/am/EventLogTags.logtags

$(warning $(LOCAL_PATH))

#overlay
ifeq ($(LEADCORE_OVERLAY),true)
services_ext_subdirs := $(addprefix ../../../../overlay/, $(LOCAL_PATH)/)
$(warning $(services_ext_subdirs))

services_ext_files := $(call all-java-files-under,$(services_ext_subdirs))
LOCAL_SRC_FILES += $(services_ext_files)
$(warning $(services_ext_files))

empty :=
services_ext_overlay_files := $(subst $(services_ext_subdirs),$(empty),$(services_ext_files))
$(warning $(services_ext_overlay_files))

LOCAL_SRC_FILES := $(filter-out $(services_ext_overlay_files), $(LOCAL_SRC_FILES))
endif

LOCAL_JAVA_LIBRARIES := telephony-common
LOCAL_STATIC_JAVA_LIBRARIES := tzdata_update

include $(BUILD_STATIC_JAVA_LIBRARY)
這樣整個修改power就完成了。