程式碼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就完成了。