Lỗi lệnh mkl cong ban1.lin cant find file năm 2024

Cây Thuốc Việt Nam tôn trọng quyền riêng tư của mỗi cá nhân, vì thế chúng tôi luôn cố gắng bảo vệ toàn bộ thông tin của mọi người. Chính sách về quyền riêng tư sẽ thể hiện quá trình chúng tôi thu thập, chuyển đổi, xử lý và sử dụng

Bằng việc cung cấp thông tin cá nhân, bạn đã đồng ý và chấp nhận việc trao đổi, xử lý, sử dụng và công bố thông tin được đề cập tại Chính sách này.

Bạn có thể thấy thông tin về chính sách quyền riêng tư tại mục footer trên website Cây Thuốc Việt Nam.

Chúng tôi thu thập gì?

Chúng tôi sẽ thu thập thông tin cá nhân mà bạn cung cấp, các thông tin này sẽ thể hiện rằng bạn là một người dùng cá nhân. Việc thu thập trên chỉ được thực hiện nếu bạn đồng ý yêu cầu của chúng tôi. Thông tin này có thể bao gồm:

  • Họ tên
  • Địa chỉ
  • Số điện thoại
  • Địa chỉ email

Chúng tôi sử dụng thông tin cá nhân ra sao?

Bằng việc cung cấp thông tin cá nhân, bạn đồng ý với việc nếu pháp luật tại địa phương hoặc tại nơi bạn nhận thông tin cho phép, chúng tôi sẽ dùng thông tin đó để thực hiện các công việc sau:

  • Trả lời các yêu cầu của bạn
  • Cải thiện dịch vụ của chúng tôi
  • Nâng cấp thông tin trên các phương tiện truyền thông
  • Cung cấp cho bạn các thủ thuật, thông tin hữu ích, tin tức cập nhật mới về sản phẩm
  • Thông báo về sản phẩm và dịch vụ mới
  • Giúp khách hàng có cái nhìn về sản phẩm và dịch vụ
  • Đánh giá các hồ sơ ứng tuyển công việc
  • Cho các mục đích quản trị và đảm bảo chất lượng sản phẩm của chúng tôi
  • Cho các mục đích khác được liệt kê chi tiết trên web hoặc các ứng dụng đi động

Chúng tôi Bảo mật thông tin như thế nào?

Cây Thuốc Việt Nam sẽ luôn bảo mật thông tin cá nhân của bạn nhưng chúng tôi không đảm bảo sự an toàn các thông tin bạn tải lên web hoặc qua ứng dụng di động: Bạn sẽ chịu rủi ro về các thông tin được tải lên. Vì chúng tôi không thể đảm bảo tuyệt đối không có việc rò rỉ thông tin, sử dụng sai mục đích hoặc thay đổi dữ liệu, nên ngay khi nhận được thông tin của bạn, chúng tôi sẽ sử dụng các biện pháp bảo mật chuyên môn để phòng tránh các sự cố nêu trên xảy ra.

CHIA SẺ THÔNG TIN VỚI BÊN THỨ BA

Chúng tôi cam kết sẽ không chia sẻ thông tin của bạn sang đơn vị thứ 3 hay bất kể đơn vị nào khác.

Thay đổi chính sách

Chính sách quyền Riêng tư này đôi khi được cập nhật. Nếu sự thay đổi có tính chất quan trọng, chúng tôi sẽ đăng thông báo trên trang web hoặc các ứng dụng và các thỏa thuận cấp phép liên quan. Chúng tôi khuyến khích bạn nên thường xuyên tham khảo Chính sách Quyền Riêng Tư để cập nhật thông tin mới nhất về việc chúng tôi bảo mật thông tin cá nhân thu thập được. Việc bạn tiếp tục sử dụng website đồng nghĩa với việc chấp thuận điều khoản quyền Riêng tư và các cập nhật của Chính sách này. Những thay đổi trong chính sách không áp dụng với các dữ liệu được thu thập trước đó.

Chính sách quyền Riêng tư mới nhất của Cây Thuốc Việt Nam cập nhập mới nhất vào ngày 31 tháng 08 năm 2021

Sơ đồ mạch:

  1. biến trở 3296 (vặn nấc 6~14 Ohm)
  2. LM317
  3. Công tắc & nguồn 5V
  4. đồng hồ vạn năng ANENG 8002 > vặn thang đo ôm

hướng dẫn:

Trả lời 3 vấn đề:

  1. Làm sao liệt kê tất cả các file được biên dịch của android.
  2. Làm sao so sánh các file đã biên dịch và các file đã có mặc định trong source code của android
  3. Cấu trúc biên dịch của android dạng cây cụ thể thế nào.

1.Thêm vào android một script để liệt kê tất cả các file được biên dịch.

  • Dựa vào cấu trúc biên dịch của android, ở phần 3. ta có thể thêm một script vào gốc của cấu trúc build để mọi template đều gọi đến script này. và script này chỉ một nhiệm vụ hiển thị các source files được định nghĩa.
  • Tuy nhiên không phải tất cả các template đều tuân theo cấu trúc mặc định của android, nhiều thư mục build không theo qui luật này sẽ không export được, và qua đó ta cũng biết được mục nào người lập trình đã định nghĩa không chuẩn trong build file.

MakeFile workflow 1 Export all build commands and arguments[sửa] At the top of the file android-4.2.2_r1_tiny4412/build/core/base_rules.mk add the export commands $(info $(shell (/work/tree_make.sh “base_rules.mk”) )) $(info $(shell (/work/tree_make.sh “LOCAL_MODULE_CLASS–” $(LOCAL_MODULE_CLASS)) )) $(info $(shell (/work/tree_make.sh “LOCAL_PATH–” $(LOCAL_PATH)) )) $(info $(shell (/work/tree_make.sh “LOCAL_MODULE–” $(LOCAL_MODULE)) )) $(info $(shell (/work/tree_make.sh “LOCAL_SRC_FILES–” $(LOCAL_SRC_FILES)) )) $(info $(shell (/work/tree_make.sh “sources–” $(sources)) )) $(info $(shell (/work/tree_make.sh “LOCAL_MODULE_PATH–” $(LOCAL_MODULE_PATH)) )) $(info $(shell (/work/tree_make.sh “LOCAL_CFLAGS–” $(LOCAL_CFLAGS)) )) In the file tree_make.sh #!/bin/bash echo “TREE_MAKE–$@” >>/work/tree_make.txt the command above will print all the arguments into the text file the content is all build files, folders, include file, destination type is used in android build. The output file: TREE_MAKE–base_rules.mk TREE_MAKE–LOCAL_MODULE_CLASS– EXECUTABLES TREE_MAKE–LOCAL_PATH– bootable/recovery TREE_MAKE–LOCAL_SRC_FILES– recovery.cpp bootloader.cpp install.cpp roots.cpp ui.cpp screen_ui.cpp verifier.cpp adb_install.cpp default_device.cpp TREE_MAKE–sources– TREE_MAKE–LOCAL_MODULE– recovery TREE_MAKE–LOCAL_MODULE_PATH– TREE_MAKE–LOCAL_CFLAGS– -DRECOVERY_API_VERSION=3 -DUSE_EXT4 The var source code is user variable, so to clean it-> add one command to clear_vars.mk

\================================================================================================================================

2. Cấu trúc Make file của android có gì đặc biệt.

  • thứ nhất:
    • cơ bản cấu trúc Makefile của kernel theo tính đệ qui, nghĩa là một Makefile đầu sẽ gọi đệ qui đến các Makefile ở các thư mục con, và cứ như thế toàn bộ kernel và những folder được định nghĩa sẽ được gọi đến để build.
    • còn cấu trúc build của android không theo tính đệ qui, android chỉ có duy nhất một file Makefile, file này sẽ gọi tất cả các file định nghĩa biên dịch cụ thể là các file Android.mk, các file Android.mk này có thể lại được gọi đến một số file .mk khác… để tạo nên một file make file duy nhất và lưu tạm vào đâu đó trong android. sau đó mới thực hiện biên dịch.
  • thứ 2 ta có được cấu trúc build file của android.

Lỗi lệnh mkl cong ban1.lin cant find file năm 2024

Cấu trúc cây make file android-gốc là base_rules.mk

4 đường link sau giải thích cụ thể 1. “Recursive Make Considered Harmful” – Điểm yếu của biên dịch đệ qui make file

the main idea is show that: use the recursive makefile will not have good performance for build, suggestion is use non-recursive makefile = 1 makefile for whole project, to build subdir => use include config file such as android.mk 2. “Writing a large build system with GNU make” to understand make command and some common make arguments

http://david.rothlis.net/large-gnu-make/ 3. “Chapter 4. The Build System” Android makefile structure – cấu trúc cây Makefile của android.

https://www.safaribooksonline.com/library/view/embedded-android/9781449327958/ch04.html

Lỗi lệnh mkl cong ban1.lin cant find file năm 2024

Các main build file của android build

the main content show the structure of non-recursive makefile: in the item “Architecture” the second main content is “Module Build Templates”: the output build file not put at same folder with source code, it will be moved to template folder the module template also shows the template of android.mk to build Java or C code 4. “Understanding of Android Build system” deep show android makefile architecture

http://www.programering.com/a/MDN5EDNwATM.html

Lỗi lệnh mkl cong ban1.lin cant find file năm 2024

Cấu trúc cây của Android build với gốc là base_rules.mk

The main point is show the rule of Build Template of android makefile. The second is list of android make target

\===================================================================================================================================

3. So sánh các file được gọi đến khi build android, với toàn bộ android source code. Mục đích là có thể loại bỏ các thư mục không cần thiết, và giúp thống kê phân tích cấu trúc output file ở bài trước. Tree-View-And-Compare 1 Android Tree view To export all the folders & Files with full path => we use tree command in linux In the Android folder, using the command: tree -f -i >android_tree.txt -f : to display full file/folder path -i : to not display the indent symbol result export to file to use for text compare with beyoncompare software or other compare tool Output will be abi abi/cpp abi/cpp/Android.mk abi/cpp/include abi/cpp/include/cxxabi.h 2 ReOrder the Tree view output data 1. the output data is sorted without seperate folder or file, and without care the Upper case or Lower case. bionic bionic/Android.mk bionic/CleanSpec.mk bionic/libc bionic/libc/Android.mk bionic/libc/arch-arm bionic/libc/arch-arm/bionic 2. the output data is sorted without include the prefix “__” of file name bionic/libc/arch-arm/bionic/exidx_static.c bionic/libc/arch-arm/bionic/_exit_with_stack_teardown.S bionic/libc/arch-arm/bionic/ffs.S So to compare with output tree_make.sh we should reorder them with same algorithm. 3 Modify output of Tree_Make[sửa] From output of Tree_Make.sh => modify to same format with Tree view output of Linux command 1. The source file in LOCAL_SRC_FILES or sources tag, the include file is folder or can specify the header file The source file can be file at same level or can be from child folder. TREE_MAKE–base_rules.mk TREE_MAKE–LOCAL_MODULE_CLASS– STATIC_LIBRARIES TREE_MAKE–LOCAL_PATH– bionic/libc TREE_MAKE–LOCAL_SRC_FILES– upstream-netbsd/libc/compat-43/creat.c upstream-netbsd/libc/gen/ftw.c TREE_MAKE–sources– TREE_MAKE–LOCAL_MODULE– libc_netbsd TREE_MAKE–LOCAL_MODULE_PATH– TREE_MAKE–LOCAL_CFLAGS– -Ibionic/libc/private -DPOSIX_MISTAKE -Ibionic/libc/upstream-netbsd -include upstream-netbsd/netbsd-compat.h 2. The source code can be duplicate, because same source file can build for multi purpose TREE_MAKE–LOCAL_MODULE_CLASS– EXECUTABLES TREE_MAKE–LOCAL_PATH– bootable/recovery/edify TREE_MAKE–LOCAL_SRC_FILES– lexer.l parser.y expr.c main.c TREE_MAKE–sources– TREE_MAKE–LOCAL_MODULE– edify TREE_MAKE–LOCAL_MODULE_PATH– TREE_MAKE–LOCAL_CFLAGS– -x c -g -O0 TREE_MAKE–base_rules.mk TREE_MAKE–LOCAL_MODULE_CLASS– STATIC_LIBRARIES TREE_MAKE–LOCAL_PATH– bootable/recovery/edify TREE_MAKE–LOCAL_SRC_FILES– lexer.l parser.y expr.c TREE_MAKE–sources– TREE_MAKE–LOCAL_MODULE– libedify TREE_MAKE–LOCAL_MODULE_PATH– TREE_MAKE–LOCAL_CFLAGS– -x c 3. var sources not have in clear_vars.mk modify build>core>clear_vars.mk to clear sources var. 4. write the software to generate list file 5. download Kdiff software to compare.

1. có các folder nào được biên dịch với android 4.2.2 cho tiny4412? (xem phần tìm hiểu android make file, để thấy được cấu trúc biên dịch android) 2. các folder nào trên android chỉ nên build một lần rồi lần sau sử dụng không build lại? làm sao để giữ lại folder đấy khi make clean? các folder sau khi build được out put ra đâu:

  1. Các folder sau khi build output ra đâu: a1. abi/cpp/src/ – Android make file: LOCAL_MODULE:= libgabi++ – include $(BUILD_SHARED_LIBRARY) : out/target/product/PRODUCT_DEVICE/system/lib – include $(BUILD_STATIC_LIBRARY) : ./target/product/tiny4412/obj/lib/libgabi++.so ./target/product/tiny4412/symbols/system/lib/libgabi++.so – Trong lúc build các file c, output là các file object .o được lưu trong folder tương ứng

./target/product/tiny4412/obj/SHARED_LIBRARIES/libgabi++_intermediates ./target/product/tiny4412/obj/SHARED_LIBRARIES/libgabi++_intermediates/LINKED ./target/product/tiny4412/obj/SHARED_LIBRARIES/libgabi++_intermediates/LINKED/libgabi++.so ./target/product/tiny4412/obj/SHARED_LIBRARIES/libgabi++_intermediates/export_includes ./target/product/tiny4412/obj/SHARED_LIBRARIES/libgabi++_intermediates/import_includes ./target/product/tiny4412/obj/SHARED_LIBRARIES/libgabi++_intermediates/src ./target/product/tiny4412/obj/SHARED_LIBRARIES/libgabi++_intermediates/src/array_type_info.P ./target/product/tiny4412/obj/SHARED_LIBRARIES/libgabi++_intermediates/src/array_type_info.o ./target/product/tiny4412/obj/SHARED_LIBRARIES/libgabi++_intermediates/src/class_type_info.P ./target/product/tiny4412/obj/SHARED_LIBRARIES/libgabi++_intermediates/src/class_type_info.o ./target/product/tiny4412/obj/SHARED_LIBRARIES/libgabi++_intermediates/src/delete.P ./target/product/tiny4412/obj/SHARED_LIBRARIES/libgabi++_intermediates/src/delete.o ./target/product/tiny4412/obj/SHARED_LIBRARIES/libgabi++_intermediates/src/dynamic_cast.P ./target/product/tiny4412/obj/SHARED_LIBRARIES/libgabi++_intermediates/src/dynamic_cast.o ./target/product/tiny4412/obj/SHARED_LIBRARIES/libgabi++_intermediates/src/enum_type_info.P ./target/product/tiny4412/obj/SHARED_LIBRARIES/libgabi++_intermediates/src/enum_type_info.o ./target/product/tiny4412/obj/SHARED_LIBRARIES/libgabi++_intermediates/src/function_type_info.P ./target/product/tiny4412/obj/SHARED_LIBRARIES/libgabi++_intermediates/src/function_type_info.o ./target/product/tiny4412/obj/SHARED_LIBRARIES/libgabi++_intermediates/src/new.P ./target/product/tiny4412/obj/SHARED_LIBRARIES/libgabi++_intermediates/src/new.o ./target/product/tiny4412/obj/SHARED_LIBRARIES/libgabi++_intermediates/src/pbase_type_info.P ./target/product/tiny4412/obj/SHARED_LIBRARIES/libgabi++_intermediates/src/pbase_type_info.o ./target/product/tiny4412/obj/SHARED_LIBRARIES/libgabi++_intermediates/src/pointer_to_member_type_info.P ./target/product/tiny4412/obj/SHARED_LIBRARIES/libgabi++_intermediates/src/pointer_to_member_type_info.o ./target/product/tiny4412/obj/SHARED_LIBRARIES/libgabi++_intermediates/src/pointer_type_info.P ./target/product/tiny4412/obj/SHARED_LIBRARIES/libgabi++_intermediates/src/pointer_type_info.o ./target/product/tiny4412/obj/SHARED_LIBRARIES/libgabi++_intermediates/src/si_class_type_info.P ./target/product/tiny4412/obj/SHARED_LIBRARIES/libgabi++_intermediates/src/si_class_type_info.o ./target/product/tiny4412/obj/SHARED_LIBRARIES/libgabi++_intermediates/src/type_info.P ./target/product/tiny4412/obj/SHARED_LIBRARIES/libgabi++_intermediates/src/type_info.o ./target/product/tiny4412/obj/SHARED_LIBRARIES/libgabi++_intermediates/src/vmi_class_type_info.P ./target/product/tiny4412/obj/SHARED_LIBRARIES/libgabi++_intermediates/src/vmi_class_type_info.o

a2. tương tự như vậy các module trong bionic/libc – LOCAL_MODULE:= libc_malloc_debug_qemu include $(BUILD_SHARED_LIBRARY) – LOCAL_MODULE:= libc_malloc_debug_leak include $(BUILD_SHARED_LIBRARY) – LOCAL_MODULE:= libc include $(BUILD_SHARED_LIBRARY) – LOCAL_MODULE := libc include $(BUILD_STATIC_LIBRARY) – LOCAL_MODULE := libc_nomalloc include $(BUILD_STATIC_LIBRARY)

3. vậy tại sao lại có output file ở các thư mục như: host/linux-x86, hay target/common? – những folder nào thì output build file ra những folder này?

./host/common/obj/JAVA_LIBRARIES ./host/linux-x86 ./host/linux-x86/bin ./host/linux-x86/framework ./host/linux-x86/lib ./host/linux-x86/obj/ETC ./host/linux-x86/obj/EXECUTABLES ./host/linux-x86/obj/NOTICE_FILES ./host/linux-x86/obj/SHARED_LIBRARIES ** ./host/linux-x86/obj/STATIC_LIBRARIES ** ./host/linux-x86/obj/include ./host/linux-x86/obj/lib ./target/common/R ./target/common/docs ./target/common/obj/APPS //* ./target/common/obj/JAVA_LIBRARIES //* ./target/product/tiny4412 ./target/product/tiny4412/cache ./target/product/tiny4412/data ./target/product/tiny4412/obj ./target/product/tiny4412/obj/APPS ./target/product/tiny4412/obj/ETC ./target/product/tiny4412/obj/EXECUTABLES ./target/product/tiny4412/obj/NOTICE_FILES ./target/product/tiny4412/obj/SHARED_LIBRARIES ** ./target/product/tiny4412/obj/STATIC_LIBRARIES ** ./target/product/tiny4412/obj/include ./target/product/tiny4412/root ./target/product/tiny4412/symbols ./target/product/tiny4412/system ./target/product/tiny4412/test

– Dựa vào include trong android make file ta thấy:

Row Labels Count of output TREE_MAKE–LOCAL_MODULE_CLASS– APPS 442 TREE_MAKE–LOCAL_MODULE_CLASS– DATA 1 TREE_MAKE–LOCAL_MODULE_CLASS– ETC 349 TREE_MAKE–LOCAL_MODULE_CLASS– EXECUTABLES 491 TREE_MAKE–LOCAL_MODULE_CLASS– FAKE 3 TREE_MAKE–LOCAL_MODULE_CLASS– JAVA_LIBRARIES 276 TREE_MAKE–LOCAL_MODULE_CLASS– NONE 2 TREE_MAKE–LOCAL_MODULE_CLASS– SHARED_LIBRARIES 324 TREE_MAKE–LOCAL_MODULE_CLASS– STATIC_LIBRARIES 423 (blank) Grand Total 2311

\=>chỉ có khoảng 2.311 module được tạo ra tuy nhiên output file lại có tới 234.820 files – các include template được tạo ra chỉ để output file vào ./target/product/tiny4412/obj ./target/product/tiny4412/symbols ./target/product/tiny4412/system/lib .. – vậy những thư mục sau được tạo ra bằng cách nào? ./host/common hay ./host/linux-x86 hay ./target/common ./target/product

– ngoài template : BUILD_JAVA_LIBRARY, BUILD_STATIC_LIBRARY, BUILD_SHARED_LIBRARY,,… output to ./target/product/ thì còn có: BUILD_HOST_STATIC_LIBRARY, BUILD_HOST_SHARED_LIBRARY,,… output to ./host/linux-x86/ \=> host library là các library cho development tools

– vậy khi nào thì output ra : ./host/common hay ./target/common ? ví dụ: – temp folder: ./host/common/obj/JAVA_LIBRARIES/CtsAppSecurityTests_intermediates ./host/common/obj/JAVA_LIBRARIES/CtsAppSecurityTests_intermediates/classes ./host/common/obj/JAVA_LIBRARIES/CtsAppSecurityTests_intermediates/classes/com ./host/common/obj/JAVA_LIBRARIES/CtsAppSecurityTests_intermediates/classes/com/android ./host/common/obj/JAVA_LIBRARIES/CtsAppSecurityTests_intermediates/classes/com/android/cts ./host/common/obj/JAVA_LIBRARIES/CtsAppSecurityTests_intermediates/classes/com/android/cts/appsecurity ./host/common/obj/JAVA_LIBRARIES/CtsAppSecurityTests_intermediates/classes/com/android/cts/appsecurity/AppSecurityTests.class ./host/common/obj/JAVA_LIBRARIES/CtsAppSecurityTests_intermediates/javalib.jar

– output folder ./host/linux-x86/framework/CtsAppSecurityTests.jar

– make file: cts/hostsidetests/appsecurity/Android.mk:LOCAL_MODULE := CtsAppSecurityTests include $(BUILD_CTS_HOST_JAVA_LIBRARY)

– trong /build/core/config.mk chỉ có BUILD_HOST_JAVA_LIBRARY nên template này thuộc: cts/build/config.mk

BUILD_CTS_EXECUTABLE := cts/build/test_executable.mk BUILD_CTS_PACKAGE := cts/build/test_package.mk BUILD_CTS_HOST_JAVA_LIBRARY := cts/build/test_host_java_library.mk BUILD_CTS_UI_JAVA_LIBRARY := cts/build/test_uiautomator.mk

– trong cts/build/test_host_java_library.mk sử dụng biến $(HOST_OUT_JAVA_LIBRARIES)/$(LOCAL_MODULE).jar để output các file jar vào thư mục cần thiết.

build/core/envsetup.mk: HOST_OUT_JAVA_LIBRARIES:= $(HOST_OUT)/framework = ./host/linux-x86/framework với HOST_OUT := $(HOST_OUT_$(HOST_BUILD_TYPE)) = ./host/linux-x86/

-theo đó ta tìm được qui định out folder cho common TARGET_COMMON_OUT_ROOT := $(TARGET_OUT_ROOT)/common = ./target/common HOST_COMMON_OUT_ROOT := $(HOST_OUT_ROOT)/common ./host/common với HOST_OUT_ROOT := $(HOST_OUT_ROOT_$(HOST_BUILD_TYPE)) = ./host TARGET_OUT_ROOT := $(TARGET_OUT_ROOT_$(TARGET_BUILD_TYPE)) = ./target ta có TARGET_OUT_COMMON_INTERMEDIATES := $(TARGET_COMMON_OUT_ROOT)/obj = ./target/common/obj HOST_OUT_COMMON_INTERMEDIATES := $(HOST_COMMON_OUT_ROOT)/obj = ./host/common/obj – Như vậy trong /build/core/envsetup.mk đã qui định toàn bộ đường dẫn output cho các loại build. – Quay trở lại với câu hỏi: câu lệnh build nào đã output build temp ra intermediate folder: ./host/common/obj/JAVA_LIBRARIES? hẳn câu lệnh đó phải sử dụng biến: HOST_OUT_COMMON_INTERMEDIATES tuy nhiên lại không có make file nào sử dụng biến này, vậy nó được dùng ở đâu?

-trong file: cts/build/test_host_java_library.mk include $(BUILD_HOST_JAVA_LIBRARY) build/core/config.mk:BUILD_HOST_JAVA_LIBRARY:= $(BUILD_SYSTEM)/host_java_library.mk

-kiểm tra file /build/core/host_java_library.mk LOCAL_BUILT_MODULE_STEM := javalib.jar = ./host/common/obj/JAVA_LIBRARIES/CtsAppSecurityTests_intermediates/javalib.jar intermediates := $(call local-intermediates-dir) intermediates.COMMON := $(call local-intermediates-dir,COMMON) = ./host/common/obj/JAVA_LIBRARIES PRIVATE_CLASS_INTERMEDIATES_DIR := $(intermediates.COMMON)/classes = ./host/common/obj/JAVA_LIBRARIES/CtsAppSecurityTests_intermediates/classes – đầu tiên script clean the intermediate folder: $(cleantarget): PRIVATE_CLEAN_FILES += $(intermediates.COMMON) – tiếp theo build tất cả các file java, và move tới package $(full_classes_compiled_jar): PRIVATE_JAVACFLAGS := $(LOCAL_JAVACFLAGS) $(full_classes_compiled_jar): PRIVATE_JAR_EXCLUDE_FILES := $(full_classes_compiled_jar): $(java_sources) $(java_resource_sources) $(full_java_lib_deps) $(jar_manifest_file) $(transform-host-java-to-package) – chạy jarjar hay đơn thuần copy file bằng acp $(full_classes_jarjar_jar): $(full_classes_compiled_jar) | $(ACP) – chuyển đổi file jar thành file dex (cho dalvik machine) $(built_dex): PRIVATE_INTERMEDIATES_DIR := $(intermediates.COMMON) $(built_dex): PRIVATE_DX_FLAGS := $(LOCAL_DX_FLAGS) $(built_dex): $(full_classes_jar) $(DX) $(transform-classes.jar-to-dex) – Cuối cùng là build module $(LOCAL_BUILT_MODULE): PRIVATE_DEX_FILE := $(built_dex) $(LOCAL_BUILT_MODULE): $(built_dex) $(java_resource_sources) | $(AAPT) @echo “Host Jar: $(PRIVATE_MODULE) ($@)” $(create-empty-package) $(add-dex-to-package) $(add-carried-java-resources) ifneq ($(extra_jar_args),) $(add-java-resources-to-package) endif else $(LOCAL_BUILT_MODULE): PRIVATE_JAVACFLAGS := $(LOCAL_JAVACFLAGS) $(LOCAL_BUILT_MODULE): PRIVATE_JAR_EXCLUDE_FILES := $(LOCAL_BUILT_MODULE): $(java_sources) $(java_resource_sources) $(full_java_lib_deps) $(jar_manifest_file) $(transform-host-java-to-package) endif # LOCAL_BUILD_HOST_DEX

– một số script được gọi cần quan tâm: local-intermediates-dir transform-host-java-to-package … – những script này được định nghĩa ở đâu? trong file /build/core/definitions.mk # $(1): if non-empty, force the intermediates to be COMMON define local-intermediates-dir $(strip \ $(if $(strip $(LOCAL_MODULE_CLASS)),, \ $(error $(LOCAL_PATH): LOCAL_MODULE_CLASS not defined before call to local-intermediates-dir)) \ $(if $(strip $(LOCAL_MODULE)),, \ $(error $(LOCAL_PATH): LOCAL_MODULE not defined before call to local-intermediates-dir)) \ $(call intermediates-dir-for,$(LOCAL_MODULE_CLASS),$(LOCAL_MODULE),$(LOCAL_IS_HOST_MODULE),$(1)) \ ) endef – hàm local-intermediates-dir gọi intermediates-dir-for # $(1): target class, like “APPS” # $(2): target name, like “NotePad” # $(3): if non-empty, this is a HOST target. # $(4): if non-empty, force the intermediates to be COMMON define intermediates-dir-for $(strip \ $(eval _idfClass := $(strip $(1))) \ $(if $(_idfClass),, \ $(error $(LOCAL_PATH): Class not defined in call to intermediates-dir-for)) \ $(eval _idfName := $(strip $(2))) \ $(if $(_idfName),, \ $(error $(LOCAL_PATH): Name not defined in call to intermediates-dir-for)) \ $(eval _idfPrefix := $(if $(strip $(3)),HOST,TARGET)) \ $(if $(filter $(_idfPrefix)-$(_idfClass),$(COMMON_MODULE_CLASSES))$(4), \ $(eval _idfIntBase := $($(_idfPrefix)_OUT_COMMON_INTERMEDIATES)) \ , \ $(eval _idfIntBase := $($(_idfPrefix)_OUT_INTERMEDIATES)) \ ) \ $(_idfIntBase)/$(_idfClass)/$(_idfName)_intermediates \ ) endef

– Tóm lại CtsAppSecurityTests bằng việc khai báo include template build, template build này sẽ tập hợp các file make file khác qui định và thực hiện build source code, vào các folder đã định sẵn như intermediate hay output folder. – thư mục host với các output file là các tool của linux dùng cho việc build android. – thư mục target… với các output file là các thư viện, các app, driver… của android. – Như vậy, khi clean android, thư mực host có thể không cần thiết phải xóa – các thư mục intermediate có thể xóa bỏ để dành chỗ trống cho linux. – một module khi được build luôn có 2 loại output folder: intermediate folder, và output target. – các module dạng share_lib có thể được sử dụng cho các modul khác khi build.

1. Điều gì cần chú ý khi build một platform android cho tiny4412, Dựa trên những issue khi sử dụng uboot+kernel+android source code mà friendly arm cung cấp khi biên dịch và chạy android (system.img) có một vài issue, cần lưu ý + surface flinger không lên do thiếu một vài thư viện khi config build. log khi khởi động surface link sẽ nói nên điều này + khi khởi động android, init.rc khởi động một số service không sử dụng hay không có trên board, có thể loại bỏ. + đặt debug log khi khởi động.

ngoài ra còn lưu ý một số điểm như: android make file workflow, dalvik khởi động như thế nào, một vài issue khi khởi động: + lỗi card remove + lỗi mount ext4 + lỗi dalvik khởi động fail khi load các file jar hệ thống

chú ý qui định phân vùng partition được qui định trong 1 file trên kernel và trên android, kiểm tra file này để phân vùng bộ nhớ cho phù hợp.

1.1 lỗi mount ext4 Android bắt đầu khởi động từ system/core/init/init.c, enable debug mode và đặt command debug ta sẽ thấy chu trình khởi động của Android – Đầu tiên Android đưa một loạt các action và trigger trong android config init.rc vào hàng đợi thực hiện, sau đó gọi vòng lặp để thực hiện chúng: \================= [ 10.895000] init: property init [ 10.895000] init: reading config file [ 10.900000] init: found import ‘/init.usb.rc’, adding to import listinit: found import ‘/init.tiny4412.rc’, adding to import listinit: found import ‘/init.trace.rc’, adding to import listinit: importing ‘/init.usb.rc’init: importing ‘/init.tiny4412.rc’init: found import ‘init.tiny4412.usb.rc’, adding to import listinit: importing ‘init.tiny4412.usb.rc’init: importing ‘/init.trace.rc’init: + wait_for_coldboot_done [ 10.935000] init: + keychord_init [ 10.940000] init: + console_init [ 10.945000] init: + init [ 10.945000] init: + early-fs [ 10.950000] init: + fs [ 10.950000] init: + post-fs [ 10.955000] init: + post-fs-data [ 10.955000] init: + property_service_init [ 10.960000] init: + signal_init [ 10.965000] init: + check_startup [ 10.970000] init: + early-boot [ 10.970000] init: + boot [ 10.975000] init: + queue_property_trigger …

[ 10.980000] init: processing action 0x2d200 (early-init) …. \================

Đáng chú ý ở action init (fs) lỗi mount file fail; với kết quả câu lệnh mount return fail: ‘mount’ r=-1 chú ý lại thấy câu lệnh mount thứ 2 bị fail: ‘mount_all’ r=255 vậy 2 câu lệnh mount này được lấy từ đâu? có cần thiết phải gọi đến 2 lần mount? phải chăng lỗi cũng chính từ việc double time gọi mount này? \================ [ 11.945000] init: processing action 0x34010 (init) [ 11.950000] init: command ‘mkdir’ r=0 … [ 12.000000] init: processing action 0x2dd80 (fs) [ 12.005000] EXT4-fs (mmcblk0p2): ext4_fill_super: journal inode [ 12.010000] EXT4-fs (mmcblk0p2): ext4_fill_super: ext4_load_journal() [ 12.020000] EXT4-fs (mmcblk0p2): ext4_load_journal() [ 12.025000] EXT4-fs (mmcblk0p2): new_decode_dev() [ 12.025000] EXT4-fs (mmcblk0p2): bdev_read_only() [ 12.030000] EXT4-fs (mmcblk0p2): INFO: recovery required on readonly filesystem [ 12.040000] EXT4-fs (mmcblk0p2): write access will be enabled during recovery [ 12.045000] EXT4-fs (mmcblk0p2): ext4_get_journal() [ 12.055000] EXT4-fs (mmcblk0p2): jdb2_journal_load() [ 12.055000] JBD2: jdb2_journal_load: load_superblock() [ 12.070000] JBD2: jdb2_journal_load: j_formate_version>=2 [ 12.070000] JBD2: jdb2_journal_load: jdb2_journal_create_slab() JBD2: jdb2_journal_load: jdb2_journal_recover() [ 12.115000] JBD2: jdb2_journal_load: journal_reset() init: ueventd: poll() [ 12.120000] EXT4-fs (mmcblk0p2): recovery complete [ 12.120000] EXT4-fs (mmcblk0p2): mounted filesystem with ordered data mode. Opts: (null) [ 12.120000] init: command ‘mount’ r=0 [ 12.135000] EXT4-fs (mmcblk0p4): ext4_fill_super: journal inode [ 12.135000] EXT4-fs (mmcblk0p4): ext4_fill_super: ext4_load_journal() [ 12.135000] EXT4-fs (mmcblk0p4): ext4_load_journal() [ 12.135000] EXT4-fs (mmcblk0p4): new_decode_dev() [ 12.140000] EXT4-fs (mmcblk0p4): bdev_read_only() [ 12.145000] EXT4-fs (mmcblk0p4): ext4_get_journal() [ 12.150000] EXT4-fs (mmcblk0p4): jdb2_journal_wipe() [ 12.160000] EXT4-fs (mmcblk0p4): jdb2_journal_load() [ 12.160000] JBD2: jdb2_journal_load: load_superblock() [ 12.165000] JBD2: jdb2_journal_load: j_formate_version>=2 [ 12.170000] JBD2: jdb2_journal_load: jdb2_journal_create_slab() JBD2: jdb2_journal_load: jdb2_journal_recover() [ 12.180000] JBD2: jdb2_journal_load: journal_reset() [ 12.185000] EXT4-fs (mmcblk0p4): mounted filesystem with ordered data mode. Opts: (null) [ 12.190000] init: command ‘mount’ r=0 [ 12.205000] EXT4-fs (mmcblk0p3): ext4_fill_super: journal inode [ 12.205000] EXT4-fs (mmcblk0p3): ext4_fill_super: ext4_load_journal() [ 12.210000] EXT4-fs (mmcblk0p3): ext4_load_journal() [ 12.215000] EXT4-fs (mmcblk0p3): new_decode_dev() [ 12.220000] EXT4-fs (mmcblk0p3): bdev_read_only() [ 12.225000] EXT4-fs (mmcblk0p3): ext4_get_journal() [ 12.235000] EXT4-fs (mmcblk0p3): no journal found [ 12.260000] init: command ‘mount’ r=-1 [ 12.260000] init: processing action 0x34570 (fs) [ 12.260000] fs_mgr: Cannot mount filesystem on /dev/block/mmcblk0p2 at /system [ 12.260000] init: fs_mgr_mount_all returned an error [ 12.260000] init: command ‘mount_all’ r=255 [ 12.260000] init: command ‘setprop’ r=0

\=========================

Kiểm tra trong init.rc mục fs thấy câu lệnh mount đã được khai báo: mount ext4 /dev/block/mmcblk0p2 /system Tiếp tục kiểm tra trong init.tiny4412.rc lệnh mount lại bị lặp lại: \========== on fs mount_all /fstab.tiny4412 \==========

Vậy để đảm bảo một lần mount duy nhất cho hệ thống thì câu lệnh mount trong init.rc nên bị disable đi, và chỉ sử dụng một lệnh mount trong init.tiny4412.rc Tìm hiểu thêm về lệnh mount_all, lệnh được khai báo trong file: android/source/system/core/init/keywords.h \========== 0015 int do_mount_all(int nargs, char **args); 0016 int do_mount(int nargs, char **args); 0064 KEYWORD(mount_all, COMMAND, 1, do_mount_all) 0065 KEYWORD(mount, COMMAND, 3, do_mount) \===========

lệnh mount_all thực thi bằng function do_mount_all() trong file: android-4.2.2_r1_tiny4412/system/core/init/builtins.c function do_mount_all() gọi fs_mgr_mount_all() – android-4.2.2_r1_tiny4412/system/core/fs_mgr/fs_mgr.c fs_mgr_mount_all() lúc này mới gọi đến lệnh mount được cài đặt trong kernel Trong kernel, lệnh mount được cài đặt cho chức năng mount ext4 trong file: linux3.5/fs/ext4/super.c \=========== module_init(ext4_init_fs) module_exit(ext4_exit_fs) …. static int __init ext4_init_fs(void) { … register_as_ext3(); register_as_ext2(); err = register_filesystem(&ext4_fs_type); if (err) goto out; … } ……. static struct dentry *ext4_mount(struct file_system_type *fs_type, int flags, const char *dev_name, void *data) { return mount_bdev(fs_type, flags, dev_name, data, ext4_fill_super); } … static int ext4_fill_super(struct super_block *sb, void *data, int silent) { … cantfind_ext4: if (!silent) ext4_msg(sb, KERN_ERR, “VFS: Can’t find ext4 filesystem”); goto failed_mount; …} \========

Kết quả nếu mount ext4 không thành công, hàm ext4_fill_super() sẽ đưa thông báo mount fail như sau: “…VFS: Can’t find ext4 filesystem”

1.1.2 Giải quyết lỗi mount fail này thế nào? nguyên nhân do: – phân vùng được mount chưa được định dạng ext4 – file system.img khi ghi vào phân vùng này chưa được ghi với định dạng ext4 cách sửa đã được trình bày trong bài trước.

\====================================================================================================================================== 1.2. Lỗi Surface flinger không khởi động. theo thứ tự trong init.rc các action và trigger được thực hiện, theo đó service manager được khởi động, kèm theo là zygote, media, surfaceflinger cũng được khởi động. (frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp == 4.2.2)

\========= service servicemanager /system/bin/servicemanager class core user system group system critical onrestart restart zygote onrestart restart media onrestart restart surfaceflinger onrestart restart drm …. service surfaceflinger /system/bin/surfaceflinger class main user system group graphics drmrpc onrestart restart zygote

\=========== [ 13.310000] init: starting ‘servicemanager’ [ 13.390000] init: starting ‘ril-daemon’ [ 13.390000] init: starting ‘surfaceflinger’ [ 13.415000] init: starting ‘zygote’ [ 13.415000] init: starting ‘drm’ … shell@android:/ $ [ 13.990000] init: waitpid returned pid 106, status = 0000000b [ 13.990000] init: process ‘ril-daemon’, pid 106 exited [ 13.990000] init: process ‘ril-daemon’ killing any children in process group …. [ 14.540000] init: waitpid returned pid 107, status = 0000000b [ 14.540000] init: process ‘surfaceflinger’, pid 107 exited [ 14.540000] init: process ‘surfaceflinger’ killing any children in process group [ 14.540000] init: service ‘zygote’ is being killed [ 14.540000] init: starting ‘zygote’

Thứ nhất: ril-daemon được khởi động, nhưng bảng mạch tiny4412 không có phần cứng support cho gọi điện thoại, nên service này có thể disable khi khởi động. Thứ 2: ‘surfaceflinger’ khởi động fail, màn hình android không hiển thị được. Vậy kiểm tra fail bằng cách nào? \=> Ngay khi adbd service được khởi động, là lúc ta có thể enable logcat debug để hiển thị log android, với logcat, có thể quan sát được debug log của các service.

\=============== [ 13.470000] init: ueventd: poll() [ 13.470000] initcall init_module+0x0/0x38 [snd_soc_wm8960] returned 0 after 264 usecs [ 13.500000] init: processing action 0x2fd30 (property:ro.debuggable=1) [ 13.510000] init: starting ‘console’ [ 13.510000] init: command ‘start’ r=0 [ 13.515000] init: processing action 0x30028 (property:persist.service.adb.enable=1) [ 13.515000] calling init_module+0x0/0xc [snd_soc_tiny4412_wm8960] @ 115 [ 13.515000] init: ueventd: poll() [ 13.515000] FriendlyARM http://www.arm9.net [ 13.535000] init: starting ‘adbd’ [ 13.540000] init: command ‘start’ r=0 [ 13.540000] init: Created socket ‘/dev/socket/adbd’ with mode ‘660’, user ‘1000’, group ‘1000’ [ 13.540000] warning: `adbd’ uses 32-bit capabilities (legacy support in use) [ 13.560000] init: processing action 0x32e20 (property:persist.sys.usb.config=*) [ 13.565000] init: command ‘setprop’ r=0 [ 13.570000] init: command ‘setprop’ r=0 [ 13.575000] init: processing action 0x324f8 (property:sys.usb.config=none) [ 13.580000] init: service ‘adbd’ is being killed [ 13.585000] init: command ‘stop’ r=0 [ 13.590000] init: waitpid returned pid 117, status = 00000009 [ 13.595000] init: process ‘adbd’, pid 117 exited [ 13.600000] init: process ‘adbd’ killing any children in process group [ 13.605000] init: command ‘write’ r=-19 [ 13.610000] init: command ‘write’ r=0 [ 13.615000] init: command ‘setprop’ r=0 [ 13.620000] init: processing action 0x35c38 (property:sys.usb.config=mtp,adb) [ 13.625000] init: command ‘write’ r=-19 [ 13.630000] init: command ‘write’ r=0 [ 13.630000] init: command ‘write’ r=0 [ 13.635000] init: command ‘write’ r=0 [ 13.640000] init: command ‘write’ r=-19 [ 13.645000] init: starting ‘adbd’ [ 13.645000] init: ueventd: poll() \==========

Như vậy ngay khi có trigger: property:persist.service.adb.enable=1 Ta đặt lệnh khởi động logcat service trong init.rc \=========== ….

Quan sát logcat: – khi SurfaceFlinger khởi động, thư viện libEGL được gọi đến (/system/lib/libEGL.so) – Thông báo hàm load_library() không load được thư viện “libexynosv4l2.so” từ hàm soinfo_link_image(linker.cpp:1635) trong thư viện “hwcomposer.tiny4412.so” – Vậy những thư viện này ở đâu, khai báo chỗ nào? \============== I/SurfaceFlinger( 103): SurfaceFlinger is starting I/SurfaceFlinger( 103): SurfaceFlinger’s main thread ready to run. Initializing graphics H/W… E/libEGL ( 103): eglGetDisplay:121 error 300c (EGL_BAD_PARAMETER) /system/lib/libEGL.so E/libEGL ( 103): eglInitialize:137 error 3008 (EGL_BAD_DISPLAY) I/[Gralloc]( 103): using (fd=18) I/[Gralloc]( 103): id = I/[Gralloc]( 103): xres = 800 px I/[Gralloc]( 103): yres = 1280 px I/[Gralloc]( 103): xres_virtual = 800 px I/[Gralloc]( 103): yres_virtual = 3840 px I/[Gralloc]( 103): bpp = 32 I/[Gralloc]( 103): r = 0:8 I/[Gralloc]( 103): g = 8:8 I/[Gralloc]( 103): b = 16:8 I/[Gralloc]( 103): width = 94 mm (216.170212 dpi) I/[Gralloc]( 103): height = 151 mm (215.311264 dpi) I/[Gralloc]( 103): refresh rate = 58.86 Hz oE/HAL ( 103): load: module=/system/lib/hw/hwcomposer.tiny4412.so E/HAL ( 103): Cannot load library: soinfo_link_image(linker.cpp:1635): could not load library “libexynosv4l2.so” needed by “hwcomposer.tiny4412.so”; caused by load_library(linker.cpp:745): library “libexynosv4l2.so” not found E/SurfaceFlinger( 103): hwcomposer module not found W/SurfaceFlinger( 103): getting VSYNC period from fb HAL: 16989177 E/libEGL ( 103): validate_display:251 error 3008 (EGL_BAD_DISPLAY) F/libc ( 103): Fatal signal 11 (SIGSEGV) at 0xdeadbaad (code=1), thread 128 (SurfaceFlinger) I/DEBUG ( 102): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** I/DEBUG ( 102): Build fingerprint: ‘Android/full_tiny4412/tiny4412:4.2.2/JDQ39/eng.root.20141127.141958:userdebug/test-keys’ I/DEBUG ( 102): Revision: ‘0’ I/DEBUG ( 102): pid: 103, tid: 128, name: SurfaceFlinger >>> /system/bin/surfaceflinger <<< I/DEBUG ( 102): signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr deadbaad I/DEBUG ( 102): r0 00000027 r1 deadbaad r2 4019c258 r3 00000000 I/DEBUG ( 102): r4 00000000 r5 4055ad04 r6 00000000 r7 41ea1aa8 I/DEBUG ( 102): r8 00000005 r9 00003038 sl 00003142 fp 00003038 I/DEBUG ( 102): ip 401a7ff4 sp 4055ad00 lr 4016f2f9 pc 4016b992 cpsr 60000030 I/DEBUG ( 102): d0 0000000200000000 d1 0000000000000000 I/DEBUG ( 102): d2 0000000600000000 d3 4765ed0000000000 I/DEBUG ( 102): d4 3cf2c5aee6666666 d5 0000000046fe0000 I/DEBUG ( 102): d6 4448000000000320 d7 426b71aa00000500 I/DEBUG ( 102): d8 0000000000000000 d9 0000000000000000 I/DEBUG ( 102): d10 0000000000000000 d11 0000000000000000 I/DEBUG ( 102): d12 0000000000000000 d13 0000000000000000 I/DEBUG ( 102): d14 0000000000000000 d15 0000000000000000 I/DEBUG ( 102): d16 417033bf9e045cc0 d17 41cdcd6500000000 I/DEBUG ( 102): d18 3fdffffffffedaaf d19 3fe0000000000000 I/DEBUG ( 102): d20 3fe00000000092a8 d21 0000000000000000 I/DEBUG ( 102): d22 0000000000000000 d23 0000000000000000 I/DEBUG ( 102): d24 0000000000000000 d25 0000000000000000 I/DEBUG ( 102): d26 0000000000000000 d27 0000000000000000 I/DEBUG ( 102): d28 0000000000000000 d29 0000000000000000 I/DEBUG ( 102): d30 0000000000000000 d31 0000000000000000 I/DEBUG ( 102): scr 20000010 I/DEBUG ( 102): I/DEBUG ( 102): backtrace: I/DEBUG ( 102):

00 pc 0001a992 /system/lib/libc.so

I/DEBUG ( 102):

01 pc 00018070 /system/lib/libc.so (abort+4)

I/DEBUG ( 102):

02 pc 000008f1 /system/lib/libstdc++.so (operator new(unsigned int)+8)

I/DEBUG ( 102):

03 pc 0002474d /system/lib/libsurfaceflinger.so (android::SurfaceFlinger::selectConfigForAttribute(void*, int const*, int, int, void**)+38)

I/DEBUG ( 102):

04 pc 000248a7 /system/lib/libsurfaceflinger.so (android::SurfaceFlinger::selectEGLConfig(void*, int)+162)

I/DEBUG ( 102):

05 pc 00028819 /system/lib/libsurfaceflinger.so (android::SurfaceFlinger::readyToRun()+92)

I/DEBUG ( 102):

06 pc 0001123d /system/lib/libutils.so (android::Thread::_threadLoop(void*)+72)

I/DEBUG ( 102):

07 pc 00010dcd /system/lib/libutils.so

I/DEBUG ( 102):

08 pc 0000e3d8 /system/lib/libc.so (__thread_entry+72)

I/DEBUG ( 102):

09 pc 0000dac4 /system/lib/libc.so (pthread_create+160)

I/DEBUG ( 102): I/DEBUG ( 102): stack: I/DEBUG ( 102): 4055acc0 c0000000 I/DEBUG ( 102): 4055acc4 00000050

Các thư viện bị thiếu ở đâu? Trước tiên tìm hiểu về biên dịch device/friendly-arm: /work/android-4.2.2_r1_tiny4412/device/friendly-arm/tiny4412/full_tiny4412.mk \======= device/friendly-arm/tiny4412/full_tiny4412.mk … $(call inherit-product, device/friendly-arm/tiny4412/device.mk) … \====== android-4.2.2_r1_tiny4412/device/friendly-arm/tiny4412/device.mk $(call inherit-product, device/friendly-arm/tiny4412/device_base.mk) $(call inherit-product-if-exists, hardware/samsung_slsi/exynos4/exynos4.mk) $(call inherit-product-if-exists, vendor/friendly-arm/exynos4412/device-tiny4412.mk) … \======= /vendor/friendly-arm/exynos4412/device-tiny4412.mk … ifeq ($(BOARD_USES_HGL),true) # Misc other modules PRODUCT_PACKAGES += \ gralloc.tiny4412 \ ************ libnetcmdiface endif … \======= /android-4.2.2_r1_tiny4412/hardware/samsung_slsi/exynos4/exynos4.mk # hw composer HAL PRODUCT_PACKAGES += \ hwcomposer.tiny4412 \ ************ libstagefrighthw \ camera.tiny4412 \ libexynosv4l2 \ ************ Thư viện sử dụng khai báo thiếu libexynosutils \ ************ Thư viện sử dụng khai báo thiếu libexynosfimc ************ Thư viện sử dụng khai báo thiếu … \====== hardware/libhardware/modules/hwcomposer/Android.mk LOCAL_SHARED_LIBRARIES := liblog libEGL ************ LOCAL_SRC_FILES := hwcomposer.cpp LOCAL_MODULE := hwcomposer.default

LOCAL_MODULE_TAGS := eng install default for eng mode LOCAL_MODULE := libexynosfimc

LOCAL_MODULE_TAGS := optional module specify in PRODUCT_PACKAGES for install \======

/system/lib/libEGL.so khai báo biên dịch trong file: frameworks/native/opengl/libs/Android.mk: LOCAL_MODULE:= libEGL LOCAL_MODULE:= libGLESv2 LOCAL_MODULE:= libGLESv2 .. LOCAL_SHARED_LIBRARIES += libcutils libutils libGLES_trace // Các thư viện cần đến khi biên dịch LOCAL_LDLIBS := -lpthread -ldl LOCAL_MODULE:= libEGL LOCAL_LDFLAGS += -Wl,–exclude-libs=ALL LOCAL_SHARED_LIBRARIES += libdl

Thư viện sử dụng khai báo thiếu \====== /hardware/samsung_slsi/exynos4/libv4l2/Android.mk LOCAL_SHARED_LIBRARIES := \ liblog \ libutils \ libexynosutils

LOCAL_MODULE := libexynosv4l2 \====== hardware/samsung_slsi/exynos4/libexynosutils/Android.mk LOCAL_SHARED_LIBRARIES := liblog libutils libcutils LOCAL_MODULE := libexynosutils

1.3 AudioPolicyManagerBase Can’t load libsecril-client.so (/ ril/libsecril-client/secril-client.h) AudioPolicy là service quản lý rule của audio, tự động điều hướng audio khi có các thay đổi như, cuộc gọi, bluetooth kết nối… Thuộc android framework \=================================== [ 14.445000] init: waitpid returned pid 100, status = 00000000 [ 14.445000] init: process ‘tiny4412-setup’, pid 100 exited I/mediaserver( 109): ServiceManager: 0x41a86e30 I/AudioFlinger( 109): Using default 3000 mSec as standby time. I/CameraService( 109): CameraService started (pid=109) E/AudioPolicyManagerBase( 109): could not load audio policy configuration file, setting defaults E/AudioHardware( 109): Can’t load libsecril-client.so I/AudioFlinger( 109): loadHwModule() Loaded primary audio interface from LEGACY Audio HW HAL (audio) handle 1 I/AudioFlinger( 109): HAL output buffer size 2048 frames, normal mix buffer size 2048 frames I/AudioMixer( 109): found effect “Multichannel Downmix To Stereo” from The Android Open Source Project

1.3 enable android debug mode: init.rc : loglevel 6

1.4 enable adb and logcat in init.rc # adbd is controlled via property triggers in init..usb.rc service adbd /sbin/adbd class core socket adbd stream 660 system system disabled seclabel u:r:adbd:s0

# adbd on at boot in emulator on property:ro.kernel.qemu=1 start adbd

# added by FriendlyARM on property:persist.service.adb.enable=1 start adbd

# added by FriendlyARM on property:persist.service.adb.enable=0 stop adbd

# added for debug surfaceflinger service logcat /system/bin/logcat user root console disabled

# added for debug surfaceflinger on property:sys.usb.config=mtp,adb start logcat 2. Setup môi trường build android source code: – sử dụng compiler: arm-2009q3.tar.gz + giải nén : tar xzf arm-2009q3.tar.gz -C /usr/local/arm/ + cấu hình cho bashrc: vim ~/.bashrc -create new environment variables- export JAVA_HOME=/usr/lib/jvm/java-6-sun export ANDROID_JAVA_HOME=$JAVA_HOME export PATH=/usr/local/arm/arm-2009q3/bin:$PATH export ARCH=arm export CROSS_COMPILE=/usr/local/arm/arm-2009q3/bin/arm-none-linux-gnueabi- ——- source ~/.bashrc – biên dịch: source setenv.sh //donot run by ./setenv.sh make -j4 – tạo file ramdisk-u.img + copy file: mkimage vào thư mục Android + sửa dòng .. trong gen-img.sh: + chạy script: source gen-img.sh

  1. flash uboot vào thẻ nhớ bằng cách nào?
  2. dựa vào nguyên tắc cơ bản: – khi bảng mạch khởi động ở chế độ thẻ nhớ, nó sẽ đọc section đầu tiên của thẻ nhớ để khởi động. \=> do vậy uboot sẽ được ghi vào đây – ban đầu thẻ nhớ được format 32, chưa có phân vùng. Sau khi flash uboot vào thẻ nhớ, và khởi động bảng mạch vào được uboot, lúc này mới dùng các câu lệnh phân vùng thẻ nhớ của uboot, để phân vùng cho linux, và android hoạt động.
  1. vậy flash uboot lên sector đầu tiên của thẻ nhớ bằng cách nào? với tiny4412, đã support sẵn thư mục “sd_fuse” biên dịch và flash uboot lên thẻ nhớ.

1. build uboot a.toolchain (arm-linux-gcc-4.5.1-v6-vfp-20120301.tgz) giải nén và set path

vim ~/.bashrc

export PATH=~/working/opt/FriendlyARM/toolschain/4.5.1/bin:$PATH => thêm vào cuối file

source ~/.bashrc

  1. giải nén uboot: tar xzf uboot_tiny4412-20130729.tgz
  2. build uboot cd uboot_tiny4412

make distclean ==> xóa output make tiny4412_config make

  1. build sd_fuse (dùng để flash uboot lên thẻ nhớ) make -C sd_fuse hoặc: cd sd_fuse; make
  2. flash uboot lên thẻ nhớ. -cắm thẻ nhớ vào máy tính, bật usb trên ubuntu, để nhận dạng thẻ nhớ. -khi đó thẻ nhớ được mount mặc định là /dev/sdb cd sd_fuse/tiny4412 ./sd_fusing.sh /dev/sdb
  1. Tìm hiểu về script sd_fusing.sh Script sd_fusing.sh sẽ flash uboot lên thẻ nhớ. 1.vậy script này làm việc như thế nào.

– sau khi biên dịch uboot, có output file uboot.bin – sau khi biên dịch sd_fuse, có output file mkbl2 (make bootloader 2) vậy file bootloader 1 ở đâu? samsung cung cấp bootloader dưới dạng file đã biên dịch: E4412_N.bl1.bin và file trustzone bootloader dạng đã biên dịch: E4412_tzsw.bin – script tạo file bootloader số 2, output file: bl2.bin E4412_UBOOT=../../u-boot.bin MKBL2=../mkbl2 ${MKBL2} ${E4412_UBOOT} bl2.bin 14336 \=> câu lệnh có dạng: mkbl2 u-boot.bin bl2.bin 14336 – sau đó script lần lượt ghi 4 file vào 4 phân vùng boot sector: 1. bootloader 1: E4412_N.bl1.bin => ghi vào sector số 1 (phân vùng khởi động số 1) signed_bl1_position=1 dd iflag=dsync oflag=dsync if=./E4412_N.bl1.bin of=$1 seek=$signed_bl1_position nhiệm vụ khởi động ban đầu và load bootloader số 2 2. bootloader 2: bl2.bin => ghi vào sector số 17 (phân vùng khởi động số 2) bl2_position=17 dd iflag=dsync oflag=dsync if=./bl2.bin of=$1 seek=$bl2_position nhiệm vụ kiểm tra và load đúng file u-boot.bin mà bl2.bin được tạo ra. 3. uboot cho hệ thống: u-boot.bin => ghi vào sector số 49 (phân vùng khởi động số 3) uboot_position=49 dd iflag=dsync oflag=dsync if=${E4412_UBOOT} of=$1 seek=$uboot_position nhiệm vụ khởi động các phần cứng cần thiết cho quá trình boot, như cổng serial, miniusb, network port, thẻ nhớ, và một số câu lệnh hệ thống 4. trustZone : E4412_tzsw.bin => ghi vào sector số 705 (phân vùng khởi động số 4) tzsw_position=705 dd iflag=dsync oflag=dsync if=./E4412_tzsw.bin of=$1 seek=$tzsw_position nhiệm vụ xác định kích thước phân vùng khởi động số 3. – sau đó thẻ nhớ đã sẵn sàng để khởi động trên bảng mạch tiny4412

2. Ý nghĩa về kích thước của 4 phân vùng khởi động? – Uboot qui định kích thước mỗi block là 512 bytes. phân vùng khởi động 1 từ block số 1 -> 16, kích thước: 16 * 512 bytes = 8 Kbytes phân vùng khởi động 2 từ block số 17 -> 48, kích thước: 32 * 512 bytes = 16 Kbytes phân vùng khởi động 3 từ block số 49 -> 704, kích thước: 656 * 512 bytes = 328 Kbytes phân vùng khởi động 4 từ block số 705 => không xác định kích thước. – Như vậy file u-boot.bin phải có kích thước nhỏ hơn 328 Kb, trong một số trường hợp porting cho uboot, file này lớn hơn 328 Kb, phải khai báo lại kích thước phân vùng 3. ví dụ: thay vì phân vùng trustZone vị trí 705 đổi thành 1073 phân vùng khởi động 3 từ block số 49 -> 1072, kích thước: 1024 * 512 bytes = 512 Kbytes \=> make lại file bootload số 2, và flash lại thẻ nhớ.

  1. Tìm hiểu thêm về các phân vùng thẻ nhớ. 1. phân vùng bằng fdisk của uboot – sau khi flash uboot vào thẻ nhớ, và khởi động bảng mạch bằng thẻ nhớ. – việc đầu tiên phải phân vùng lại thẻ nhớ bằng lệnh của uboot fdisk -c 0 320 806 518 – định dạng phân vùng tự do số 1 thành phân vùng fat32 để lưu file, bằng câu lệnh uboot fatformat mmc 0:1 – với tiny4412 các phân vùng 2,3,4 phải được format dạng ext4, trong khi câu lệnh uboot chưa support lệnh ext4format mmc 0:2; và chưa support write file system.img lên phân vùng số 2 theo định dạng ext4, nên phải dụng lệnh của ubuntu (có thể port ext4 vào uboot ở bài khác) 2. kiểm tra phân vùng thẻ nhớ đã định dạng bằng câu lệnh ubuntu fdisk -l Device Boot Start End Blocks Id System /dev/sdb1 3517260 7601819 2042280 c W95 FAT32 (LBA) /dev/sdb2 136152 794219 329034 83 Linux ==>system /dev/sdb3 794220 2450735 828258 83 Linux ==>user /dev/sdb4 2450736 3517259 533262 83 Linux ==>cache

– định dạng phân vùng số 2 & 3 thành ext4 bằng câu lệnh linux ubuntu mkfs.ext4 /dev/sdb2 mkfs.ext4 /dev/sdb3

(theo hướng dẫn bài trước, để ghi file system.img và userdata.img vào các phân vùng này dinh-dang-ext4-cho-sdmmc-ghi-file-len-phan-vung-ext4)

3. Sử dụng định dạng ext2format cho các phân vùng thẻ nhớ ở một số board khác. – với tiny4412 các phân vùng 2,3,4 phải được format dạng ext4, tuy nhiên một số board khác support load file system.img và userdata.img dạng ext2, thì có thể định dạng phân vùng theo ext2 theo câu lệnh sau của uboot: fatformat mmc 0:1; //fat32 ext2format mmc 0:2; //system ext2format mmc 0:3; //user ext2format mmc 0:4; //cache \=> log: Partition1: Start Address(0x35ab4c), Size(0x3e5350) Partition2: Start Address(0x213d8), Size(0xa0a94) Partition3: Start Address(0xc1e6c), Size(0x1946c4) Partition4: Start Address(0x256530), Size(0x10461c)

– sau đó có thể ghi file system.img hoặc userdata.img xuống các phân vùng bằng lệnh: fastboot: với cổng microUsb tftp hoặc nfs: với cổng ethernet DM9000

— movi write kernel/rootfs: ví dụ fatload mmc 0:1 40008000 zImage movi write kernel 0 40008000 fatload mmc 0:1 41000000 ramdisk-u.img movi write rootfs 0 41000000 100000

\==> load 2 files zImage & ramdisk-u.img từ thẻ nhớ ghi lên mmc vào 2 phân vùng kernel & rootfs định sẵn trong cmd_movi

— mmc write: ví dụ fatload mmc 0:1 40008000 system.img mmc write 0 40008000 0x213d8 0xa0a94 fatload mmc 0:1 40008000 userdata.img mmc write 0 40008000 0xc1e6c 0x1946c4

\==> sau đó load 2 files system.img & userdata.img từ thẻ nhớ vào địa chỉ 40008000, sau đó dùng câu lệnh uboot cmd_mmc để khi vào các phân vùng tương ứng 0x213d8 0xa0a94 & 0xc1e6c 0x1946c4 (phân vùng số 2 &3 có được bằng ext2format mmc 0:2 & ext2format mmc 0:3 đã nêu trên)

– với các board loại này có thể đặt lệnh khởi động từ mmc số 0 bằng lệnh uboot: setenv bootcmd “movi read kernel 0 40008000; movi read rootfs 0 41000000 100000; bootm 40008000 41000000”

\=> sau khi đã lưu các file vào vị trí trên mmc, chỉ cần gọi lệnh đọc thông tin kernel và roofs rồi khởi động bootm từ đó.

4. khởi động board tiny4412:

– 3 phân vùng 2,3,4 được định dạng ext4 và copy các file tương ứng (chi tiết ở link tiny4412-khoi-dong-voi-uboot-kernel-android-tren-sdmmc )

– Tiny4412 khởi động với câu lệnh: setenv bootcmd ‘mmc init; fatload mmc 0:1 0x41000000 ramdisk-u.img; fatload mmc 0:1 0x40008000 zImage; bootm 0x40008000 41000000’

5. bản chất các phân vùng: – khi so sánh cách ghi file system.img bằng ubuntu và bằng câu lệnh fatload & (mmc or movi) + ta thấy với ubuntu khi được mount định dạng ext4 vào một folder trên ubuntu, thì file ảnh system.img thực chất là tập hợp các file & folder, có thể copy, thay đổi và thêm bớt. + với uboot các file .img được ghi trực tiếp vào các phân vùng sau đó khi khởi động được load lên theo địa chỉ star & size của phân vùng đó. \=> vậy: các phân vùng sau khi ghi file ảnh vào, nếu được đọc với định dạng tương ứng (ext4, ext2,…) thì có thể thêm bớt sửa xóa. thông tin luôn được ghi lại cho lần sử dụng tiếp theo \=> suy ra: nếu driver, chỉ là các file, có thể cài đặt sau khi hệ điều hành khởi động, sẽ được lưu lại để sử dụng cho lần restart (boot) tiếp theo.

6. Định dạng các phân vùng thành ext4 bằng uboot

– Ngoài cách định dạng phân vùng mmc thành ext4 bằng ubuntu, thì có thể dùng uboot.

– Uboot khi được porting thêm câu lệnh ext4format sẽ có thể dùng như sau

ext4format mmc 0:2

ext4format mmc 0:3

ext4format mmc 0:4

– Uboot cũng có thể được porting thêm một số câu lệnh thao tác trên phân vùng này như: ext4ls , ext4load and ext4write

ext4load- load binary file from a Ext4 file system ext4ls – list files in a directory (default /) ext4write- create a file in ext4 formatted partition

ví dụ:

ext4ls mmc 0:5 /usr/lib

ext4load mmc 2:2 0x30007fc0 uImage =>load file from mmc to address 0x30007fc0

ext4write mmc 2:2 /boot/uImage 0x30007fc0 6183120 => write file from address 0x30007fc0 with size 6183120 bytes to mmc

– Cấu trúc dạng cây của sysfs được tạo ra như thế nào? – Khi viết các driver, trong các module driver thường sử dụng như platform_bus_registry,…vậy nó có tác dụng gì? . Cấu trúc dạng cây của sysfs được tạo ra như thế nào? – vấn đề này liên quan đến Kobject, Ktypes, Ksets,..hay khái niệm device, driver, bus, class và subsystem nhưng đó chỉ là các khái niệm với các cấu trúc struct của kernel. Ta hãy xem từng bước cấu trúc dạng cây được hình thành như thế nào. – Theo kernel workflow: kernel_init> do_basic_setup > driver_init [ 0.180000] kernel_init: do_basic_setup [ 0.180000] do_basic_setup: driver_init [ 0.180000] driver_init: devtmpfs_init [ 0.180000] driver_init: devices_init [ 0.180000] driver_init: buses_init [ 0.180000] driver_init: classes_init [ 0.180000] driver_init: firmware_init [ 0.180000] driver_init: hypervisor_init [ 0.180000] driver_init: platform_bus_init [ 0.180000] driver_init: cpu_dev_init [ 0.180000] driver_init: memory_dev_init 1. Tại function devices_init() của driver/base/core.c, function sẽ thực hiện các bước sau: + Tạo cấu trúc Kset “Devices_kset” và thêm vào thư mục /sys/devices bằng function kset_create_and_add() + Tạo cấu trúc Kobject “Dev_kobj” và thêm vào thư mục /sys/dev bằng function kobject_create_and_add() + Tạo cấu trúc Kobject “sysfs_dev_block_kobj, sysfs_dev_char_kobj” và thêm vào dev_obj và thư mục /sys/dev/block, /sys/dev/char bằng function kobject_create_and_add() 2. Tại buse_init của driver/base/bus.c, function sẽ thực hiện các bước sau: + Tạo cấu trúc Kset “bus_kset” và thêm vào thư mục /sys/bus bằng function kset_create_and_add() + Tạo cấu trúc Kset “system_kset” và thêm vào parent devices_kset->kobj vào thư mục /sys/devices/system bằng function kset_create_and_add() 3. Tại classes_init của driver/base/class.c, function sẽ thực hiện các bước sau: + Tạo cấu trúc Kset “class_kset” và thêm vào thư mục /sys/class bằng function kset_create_and_add() 4. Tại platform_bus_init của driver/base/platform.c, function sẽ thực hiện các bước sau: + device_register(&platform_bus); hàm này trong drivers/base/core.c thực hiện device_initialize() khởi tạo device struct set dev->kobj.kset = devices_kset initialize dev->kobj với ktype= devices_ktype device_add() thêm platform vào /sys/device/platform hàm device_add ngoài ra còn thực hiện các action quan trọng khác như bus_add_device(): thêm device vào bus list của devices bus_probe_device(): thăm dò driver cho thiết bị mới nếu bus cho phép nó device_attach(): đính device cho một driver bằng duyệt các drivers mà bus có bằng lời gọi driver_probe_device + bus_register(&platform_bus); hàm này trong drivers/base/bus.c thực hiện đăng ký driver-core subsystem và đăng ký children subsystem priv->subsys.kobj.kset = bus_kset priv->subsys.kobj.ktype = &bus_ktype priv->driver_autoprobe =1 priv->devices_kset = kset_create_and_add(“devices”, NULL, &priv->subsys.kobj) priv->drivers_kset = kset_create_and_add(“drivers”, NULL, &priv->subsys.kobj) với 2 lời gọi hàm kset_create_and_add mà ta sẽ có thêm /sys/bus/platform/devices, /sys/bus/platform/drivers

\=> Như vậy sau khi gọi driver_init(), thì một loạt các sysfs được tạo ra, tạo thành cấu trúc cơ bản của cấu trúc hình cây sysfs. tiếp theo các module drivers sẽ lần lượt được gọi qua kernel_init> do_basic_setup > do_initcalls() mỗi module driver, sẽ gọi các hàm đăng ký và thêm vào trong cấu trúc các sysfs. \=> các driver này sẽ được sử dụng như thế nào? các sysfs này sẽ được gọi khi khởi động android, hoặc được gọi khi các application trên android truy cập tới.

Khi viết các driver, trong các module driver thường sử dụng như platform_bus_registry,…vậy nó có tác dụng gì? – Ta hãy xem xét ví dụ đơn giản về uart8250_device linux-3.5_tiny4412/drivers/tty/serial/8250/8250.c module_init(serial8250_init);

uart_register_driver(&serial8250_reg); serial8250_isa_devs = platform_device_alloc(“serial8250”,PLAT8250_DEV_LEGACY); platform_device_add(serial8250_isa_devs); serial8250_register_ports(&serial8250_reg, &serial8250_isa_devs->dev); platform_driver_register(&serial8250_isa_driver);

trong đó: linux-3.5_tiny4412/drivers/tty/serial/8250/8250.c serial8250_reg serial8250_isa_driver static struct platform_driver serial8250_isa_driver = { .probe = serial8250_probe, .remove = __devexit_p(serial8250_remove), .suspend = serial8250_suspend, .resume = serial8250_resume, .driver = { .name = “serial8250”, .owner = THIS_MODULE, }, }; static struct uart_driver serial8250_reg = { .owner = THIS_MODULE, .driver_name = “serial”, .dev_name = “ttyS”, .major = TTY_MAJOR, .minor = 64, .cons = SERIAL8250_CONSOLE, };

– với platform_device_add(serial8250_isa_devs); trong /drivers/base/platform.c thêm một platform device vào cấu trúc cây device với struc platform_device * pdev pdev->dev.parent = &platform_bus pdev->dev.bus = & platform_bus_type \=> sẽ thêm một device “pdev->name” vào cấu trúc /sys/device/platform/serial8250 – với platform_driver_register(&serial8250_isa_driver); trong /drivers/base/platform.c khởi tạo một bus driver bởi struct platform_driver *drv drv->driver.bus = &platform_bus_type và đăng ký driver bằng lời gọi driver_register(&drv->driver); trong /driver/base/driver.c driver_find(drv->name, drv->bus); tìm kiếm driver theo tên bus_add_driver(drv); thêm một driver cho bus với struct driver_private *priv struct bus_type *bus bus = bus_get(drv->bus); priv->driver =drv; drv->p = priv; priv->kobject.kset = bus->p->drivers_kset kobject_init_and_add(&priv->kobj, &driver_ktype, NULL, “%s”, drv->name); \=> thêm vào cấu trúc cây /sys/devices/platform/serial8250/driver/serial8250 sau đó bind driver vào devices bằng lệnh driver_attach()… ++ driver_add_groups(drv, drv->groups);

\=> qua 2 phần , ta thấy, kernel với các hàm cơ bản đã xây dựng một cấu trúc sysfs dạng cây cơ bản, sau đó các module driver được gọi, theo đó sẽ bổ sung vào một loạt các sysfs, các sysfs này sẽ được sử dụng khi android khởi động, hoặc các chương trình trên android gọi đến.

khi khởi động kernel, có rất nhiều log được in ra, vấn đề quan tâm của ta ở đây là:

1. đâu là log của các module driver?

2. có bao nhiêu driver được load khi khởi động kernel?

3. làm thế nào để biết vị trí các folder của các driver đó?

Ở đây sẽ dần trả lời 3 câu hỏi này:

1. đâu là log của các module driver?

theo kernel workflow: kernel_init() ->gọi do_basic_setup() ->gọi do_initcalls() -> gọi do_initcall_level() -> gọi do_one_initcall()

tại hàm do_one_initcall() này sẽ gọi toàn bộ các module driver để cài đặt vào kernel.

vậy đặt câu lệnh debug vào trong hàm này như sau:

————————————-

(linux-3.5_tiny4412\init\main.c)

int __init_or_module do_one_initcall(initcall_t fn) { int count = preempt_count(); int ret;

printk(KERN_NOTICE “+ do_one_initcall: %pF \n”, fn); if (initcall_debug) ret = do_one_initcall_debug(fn); else ret = fn(); printk(KERN_NOTICE “+ do_one_initcall: %pF returned %d\n”, fn,ret);

[…]

}

————————–

– Và sau khi biên dịch lại kernel, khởi động với kernel mới ta sẽ có log in ra đầy đủ tất cả các hàm cài đặt cho module drivers:

[ 0.180000] do_basic_setup: do_initcalls [ 0.180000] + do_one_initcall: ipc_ns_init+0x0/0x18 [ 0.180000] + do_one_initcall: ipc_ns_init+0x0/0x18 returned 0 [ 0.180000] + do_one_initcall: init_mmap_min_addr+0x0/0x20 [ 0.180000] + do_one_initcall: init_mmap_min_addr+0x0/0x20 returned 0 [ 0.180000] + do_one_initcall: init_cpufreq_transition_notifier_list+0x0/0x24 [ 0.180000] + do_one_initcall: init_cpufreq_transition_notifier_list+0x0/0x24 returned 0 [ 0.180000] + do_one_initcall: net_ns_init+0x0/0xf0 [ 0.180000] + do_one_initcall: net_ns_init+0x0/0xf0 returned 0

[…]

– Quan sát trong log, thấy có quá nhiều module được gọi khi khởi động kernel, rất nhiều module nếu không debug thì cũng không có log để biết được là nó có được gọi.

– Vậy cái gì qui định cái list các module này?

– các driver cài đặt vào trong kernel thường gọi một câu lệnh module_init(someFunction), câu lệnh này sẽ đăng ký function cài đặt cho driver vào list các function được gọi khi khởi động kernel. Ngay khi biên dịch Kernel danh sách đó được list ra trong file linux-3.5_tiny4412\System.map.

– Quan sát trong file System.map sẽ thấy danh sách các function theo thứ tự hoàn toàn với list các function được gọi khi khởi động kernel, chi tiết như sau:

——–

[…]

c079bb70 T __initcall0_start c079bb70 T __initcall_ipc_ns_init0 c079bb74 T __initcall_init_mmap_min_addr0 c079bb78 T __initcall_init_cpufreq_transition_notifier_list0 c079bb7c T __initcall_net_ns_init0

[…]

——

– Vậy tại sao danh sách các function được gọi lại nằm sau function có tên là __initcall0_start ?

– để biết được điều này ta cần xem lại hàm sau:

—————

static void __init do_initcall_level(int level) { extern const struct kernel_param __start___param[], __stop___param[]; initcall_t *fn;

strcpy(static_command_line, saved_command_line); parse_args(initcall_level_names[level], static_command_line, __start___param, __stop___param – __start___param, level, level, &repair_env_string);

for (fn = initcall_levels[level]; fn < initcall_levels[level+1]; fn++) do_one_initcall(*fn); }

static initcall_t *initcall_levels[] __initdata = { __initcall0_start, __initcall1_start, __initcall2_start, __initcall3_start, __initcall4_start, __initcall5_start, __initcall6_start, __initcall7_start, __initcall_end, };

————————–

– hàm do_initcall_level() này sẽ lấy tất cả các initcall_levels từ 0->7 để truyền cho hàm do_one_initcall(). Như vậy tất cả các function nằm trong mảng __initcall0_start, …, __initcall_end sẽ được hàm do_one_initcall() gọi ra và thực hiện khi khởi động kernel.

– như vậy chỉ bằng một hàm do_one_initcall() là đủ để gọi được tất cả các driver được cài đặt vào kernel, một cách linh động và tùy biến. Các driver được tự do đặt ở bất cứ đâu, và sẽ chắc chắn được gọi mà hoàn toàn không quan tâm gì đến hàm do_one_initcall(), đây là các gọi hàm rất linh động của kernel.

– giờ ta đã có list các functions được gọi khi khởi động kernel, trước khi đi vào trả lời câu hỏi 2, ta hãy xem xét điều gì đã làm với hàm module_init() có thể đăng ký các hàm driver.

– trong linux-3.5_tiny4412_hack_static\include\linux\init.c

——-

define module_init(x) __initcall(x);

define __initcall(fn) device_initcall(fn)

define device_initcall(fn) __define_initcall(“6”,fn,6)

define __define_initcall(level,fn,id) \

static initcall_t __initcall_

fn

id __used \

__attribute__((__section__(“.initcall” level “.init”))) = fn

——

– Như vậy với hàm module_init(somefunction) sẽ tạo ra một liên kết với tên __initcall_somefunction6 chỏ đến hàm somefunction(), và được đặt trong section .initcall6.init, mà .initcall6.init nằm trong __initcall6_start.

– Ta có thể thấy rõ cấu trúc này trong file: include/asm-generic/vmlinux.lds.h = cấu trúc của vmlinux.

—————-

* . = START; * __init_begin = .; * HEAD_TEXT_SECTION * INIT_TEXT_SECTION(PAGE_SIZE) * INIT_DATA_SECTION(…) * PERCPU_SECTION(CACHELINE_SIZE) * __init_end = .;

[…]

define INIT_DATA_SECTION(initsetup_align) \

.init.data : AT(ADDR(.init.data) – LOAD_OFFSET) { \ INIT_DATA \ INIT_SETUP(initsetup_align) \ INIT_CALLS \ CON_INITCALL \ SECURITY_INITCALL \ INIT_RAM_FS \ }

INIT_CALL được định nghĩa như sau:

define INIT_CALLS \

VMLINUX_SYMBOL(__initcall_start) = .; \ *(.initcallearly.init) \ INIT_CALLS_LEVEL(0) \ INIT_CALLS_LEVEL(1) \ INIT_CALLS_LEVEL(2) \ INIT_CALLS_LEVEL(3) \ INIT_CALLS_LEVEL(4) \ INIT_CALLS_LEVEL(5) \ INIT_CALLS_LEVEL(rootfs) \ INIT_CALLS_LEVEL(6) \ INIT_CALLS_LEVEL(7) \ VMLINUX_SYMBOL(__initcall_end) = .;

INIT_CALLS_LEVEL được định nghĩa như sau

define INIT_CALLS_LEVEL(level) \

VMLINUX_SYMBOL(__initcall

level##_start) = .; \

*(.initcall

level##.init) \

*(.initcall

level

s.init)

\=> để cuối cùng ta có: arch/arm/kernel/vmlinux.lds

———-

.init.data : { *(.init.data) *(.meminit.data) *(.init.rodata) . = ALIGN(8); __start_ftrace_events = .; *(_ftrace_events) __stop_ftrace_events = .; *(.meminit.rodata) . = ALIGN(32); __dtb_start = .; *(.dtb.init.rodata) __dtb_end = .; . = ALIGN(16); __setup_start = .; *(.init.setup) __setup_end = .; __initcall_start = .; *(.initcallearly.init) __initcall0_start = .; *(.initcall0.init) *(.initcall0s.init) __initcall1_start = .; *(.initcall1.init) *(.initcall1s.init) __initcall2_start = .; *(.initcall2.init) *(.initcall2s.init) __initcall3_start = .; *(.initcall3.init) *(.initcall3s.init) __initcall4_start = .; *(.initcall4.init) *(.initcall4s.init) __initcall5_start = .; *(.initcall5.init) *(.initcall5s.init) __initcallrootfs_start = .; *(.initcallrootfs.init) *(.initcallrootfss.init) __initcall6_start = .; *(.initcall6.init) *(.initcall6s.init) __initcall7_start = .; *(.initcall7.init) *(.initcall7s.init) __initcall_end = .; __con_initcall_start = .; *(.con_initcall.init) __con_initcall_end = .; __security_initcall_start = .; *(.security_initcall.init) __security_initcall_end = .; . = ALIGN(4); __initramfs_start = .; *(.init.ramfs) . = ALIGN(8); *(.init.ramfs.info) }

———————————–

\=> đây chính là lý giải cho driver được gọi nhờ cấu trúc của vmlinux, khi do_one_initcall gọi lần lượt các __initcall_start, … ,_initcall_end, thì .các .initcall0.init,…, được gọi. Theo đó các driver đăng ký trong các section .initcall đó sẽ thứ tự được gọi ra và thực thi khi kernel khởi động.

– Vậy là câu hỏi 1 đã được trả lời, và trả lời dài quá phải không ?!

2. có bao nhiêu driver được load khi khởi động kernel?

– qua phần trả lời của câu hỏi 1, ta chỉ còn việc liệt kê tất cả các function được gọi trong __initcall6_start của system.map thì sẽ có bấy nhiêu driver được cài đặt vào kernel theo câu lệnh modul_init().

– mỗi bảng mạch và mỗi mục đích khác nhau cho kernel, thì file system.map cũng sẽ khác nhau, số lượng driver được cài đặt vào cũng sẽ khác nhau. Nhưng qua system.map ta có thể thống kê được chúng.

3. làm thế nào để biết vị trí các folder của các driver đó?

– có quá nhiều các driver được cài đặt vào trong kernel, ví dụ ta muốn chỉnh sửa xem xét một driver nào đó như network chẳng hạn vậy có thể bắt đầu từ đâu?

– System map chỉ lưu tên function được gọi, nhưng qua đó không thể biết function đó được gọi từ một file nào và vị trí của nó ở đâu, để ta có thể sửa chữa debug nó.

– để trả lời câu hỏi này ta phải sử dụng “–cref -Map linux.map”

– trong file: linux-3.5_tiny4412_hack_static\scripts\link-vmlinux.sh modify hàm vmlinux_link như sau

—————-

vmlinux_link() { local lds=”${objtree}/${KBUILD_LDS}” printf ” ===========\n”

if [ “${SRCARCH}” != “um” ]; then ${LD} ${LDFLAGS} ${LDFLAGS_vmlinux} -o ${2} \ -T ${lds} ${KBUILD_VMLINUX_INIT} \ –start-group ${KBUILD_VMLINUX_MAIN} –end-group \ –cref -Map linux.map \ ${1} else ${CC} ${CFLAGS_vmlinux} -o ${2} \ -Wl,-T,${lds} ${KBUILD_VMLINUX_INIT} \ -Wl,–start-group \ ${KBUILD_VMLINUX_MAIN} \ -Wl,–end-group \ –cref -Map linux.map \ -lutil ${1} rm -f linux fi }

————————-

– với dòng lệnh được thêm vào trên, có tác dụng tạo ra file linux.map tương tự như system.map nhưng có bổ sung đầy đủ các thông tin như vị trí các file được biên dịch, và vẫn có đầy đủ các function được gọi trong nó khi khởi động kernel.

– nhưng sẽ có một chú ý quan trọng trong đó, trước tiên hãy quan sát file linux.map được tạo ra

\>> biên dịch lại file vmlinux bằng câu lệnh: make vmlinux

sau khi biên dịch thành công, một file linux.map được tạo ra, ta hay quan sát file này:

———–

0xc08a2be8 __initcall_start = . *(.initcallearly.init) .initcallearly.init 0xc08a2be8 0x4 arch/arm/kernel/built-in.o .initcallearly.init 0xc08a2bec 0x4 arch/arm/mm/built-in.o .initcallearly.init 0xc08a2bf0 0x4 arch/arm/mach-exynos/built-in.o .initcallearly.init 0xc08a2bf4 0x1c kernel/built-in.o 0xc08a2c10 __initcall0_start = .

[…]

*(.initcall6.init) .initcall6.init 0xc08a2e04 0xc arch/arm/kernel/built-in.o .initcall6.init 0xc08a2e10 0x8 arch/arm/mach-exynos/built-in.o .initcall6.init 0xc08a2e18 0x8 arch/arm/plat-samsung/built-in.o .initcall6.init 0xc08a2e20 0x60 kernel/built-in.o .initcall6.init 0xc08a2e80 0x2c mm/built-in.o

[…]

———————————————

– Thấy rằng sau __initcall_start các __initcall0_start,… được gọi, có tên file và đường dẫn, nhưng dường như tên các hàm được gọi đã không còn nữa. vậy chúng đã đi đâu hết và nguyên nhân tại sao?

– Nguyên nhân chính là biến static của định nghĩa __define_initcall() trong file include/linux/init.h

define __define_initcall(level,fn,id) \

static initcall_t __initcall_

fn

id __used \

__attribute__((__section__(“.initcall” level “.init”))) = fn

– ví dụ khi đăng ký module driver, phải gọi hàm module_init, hàm này sẽ gọi đến __define_initcall-> khởi tạo biến static với tên __initcall_somefunction6, kernel thiết kế biến này là static để không bị lỗi khi tạo mới trùng tên biến. nhờ thế mà các module_init có thể thoải mái đặt tên function cần đăng ký mà không sợ bị lỗi biên dịch khi trùng tên.

– lợi điểm đó biến thành nhược điểm khiến ta không thể export ra được file linux.map với đầy đủ thông tin mong muốn.

– vậy phải giải quyết như thế nào.

+ đổi lại biến static thành biến thường

+ hack kernel-> đổi tên tất các các module bị trùng tên khi đăng ký

  1. đổi lại biến static thành biến thường

define __define_initcall(level,fn,id) \

initcall_t __initcall_

fn

id __used \

__attribute__((__section__(“.initcall” level “.init”))) = fn

  1. hack kernel-> đổi tên tất các các module bị trùng tên khi đăng ký

– với file system.map và excel tools, lọc tất cả những file trùng tên ta có bảng sau

__initcall_dev_init6 2 __initcall_dw_mci_init6 2 __initcall_hid_init6 3 __initcall_init6 2 __initcall_nf_defrag_init6 2 __initcall_sd_driver_init6 45 __initcall_usb_serial_module_init6 45

\=> ví dụ __initcall_dev_init6 2 : nghĩa là __initcall_nf_defrag_init6 được gọi 2 lần, nghĩa là đoạn lệnh module_init(nf_defrag_init) được gọi 2 lần ở đâu đó

\=> khi biên dịch: make vmlinux sẽ báo lỗi duplicate như sau

net/ipv6/built-in.o:(.initcall6.init+0x3c): multiple definition of `__initcall_nf_defrag_init6′ net/ipv4/built-in.o:(.initcall6.init+0x24): first defined here make[1]: *** [net/built-in.o] Error 1 make: *** [net] Error 2

\=> dùng bộ ultrafileSearch ta sẽ thấy module_init(nf_defrag_init) được gọi trong 2 file sau:

net/ipv4/netfilter/nf_defrag_ipv4.c net/ipv4/netfilter/nf_defrag_ipv6_hooks.c

\=> công việc cuối cùng chỉ còn là đổi tên nf_defrag_init, và định nghĩa trong hàm exit của nó (vì thường khi trùng hàm module_init thì cũng bị trùng tên hàm module_exit) và biên dịch lại: make vmlinux thì lỗi này sẽ không còn nữa:

– cứ như vậy fix hết các duplicate function thì công đoạn hack kernel kết thúc,

– và ta hãy xem thành quả đạt được nhé:

————————-

0xc079bb48 __initcall_start = . *(.initcallearly.init) .initcallearly.init 0xc079bb48 0x4 arch/arm/kernel/built-in.o 0xc079bb48 __initcall_init_hw_perf_eventsearly .initcallearly.init 0xc079bb4c 0x4 arch/arm/mm/built-in.o 0xc079bb4c __initcall_init_static_idmapearly .initcallearly.init 0xc079bb50 0x4 arch/arm/mach-exynos/built-in.o 0xc079bb50 __initcall_exynos4_l2x0_cache_initearly

[…]

*(.initcall0.init) .initcall0.init 0xc079bb70 0x4 ipc/built-in.o 0xc079bb70 __initcall_ipc_ns_init0 .initcall0.init 0xc079bb74 0x4 security/built-in.o 0xc079bb74 __initcall_init_mmap_min_addr0 .initcall0.init 0xc079bb78 0x4 drivers/built-in.o 0xc079bb78 __initcall_init_cpufreq_transition_notifier_list0

[…]

—————–

– như vậy là file linux.map đã hiển thị đầy đủ thông tin, các function có trong system.map đã có đầy đủ trong linux.map, thêm vào đó là thông tin file và đường dẫn cụ thể, dễ dàng cho việc tìm kiếm và chỉnh sửa.

– vậy là thêm với linux.map ta đã nắm được toàn bộ cấu trúc và vị trí của các module driver được cài đặt khi khởi động kernel.

\=> 3 câu hỏi đã được trả lời, và hơi dài một chút !

Tiny4412 mặc định sử dụng superboot để khởi động và load kernel, android, trong khi việc sử dụng uboot vẫn dễ hiểu và thân thiện hơn.

sử dụng uboot cho tiny4412 được public trên mạng, hay bộ tiny4412 đi cùng đĩa dvd cũng đã cung cấp toàn bộ chức năng khởi động uboot này.

nguyên tắc như sau: dùng uboot load các file ramdisk-u.img, zImage trên phân vùng số 1 (fat32) của thẻ nhớ lên RAM, sau đó khởi động chúng trên ram => 3 bước như sau:

1. copy các file ramdisk-u.img, zImage lên phân vùng số 1 fat32 của thẻ nhớ.

2. copy file system.img và user.img vào phân vùng số 2 và số 3 của thẻ nhớ.

3. đặt lệnh khởi động uboot load các file này.

bước 1 & bước 2: xem bài hướng dẫn ext4 và sdmmc

sau khi đã format phân vùng số 1 thành fat32, dùng window copy file ramdisk-u.img, zImage lên thẻ nhớ (lúc này window chỉ nhận được phân vùng fat32)

sau khi đã copy file ext4 lên phân vùng số 2 như bài hướng dẫn trước Định dạng ext4 cho sdmmc & ghi file lên phân vùng ext4, thì mới bắt đầu bước tiếp theo

bước 3: Đặt lệnh khởi động từ thẻ nhớ cho uboot

setenv bootcmd ‘mmc init; fatload mmc 0:1 0x41000000 ramdisk-u.img; fatload mmc 0:1 0x40008000 zImage; bootm 0x40008000 41000000’

setenv bootargs ‘console=ttySAC0,115200n8 androidboot.console=ttySAC0 ctp=2 skipcali=y uhost0=y vmalloc=512m lcd=S70’

saveenv; reset;

\==> chỉ bằng 2 lệnh đơn giản trên là tiny4412 đã có thể khởi động được kernel và android. Tuy nhiên android cấu hình các thông số khác nhau, để load hoàn chỉnh được android, thì cần set đúng các thông số bootargs.

– ví dụ sử dụng bootargs sau sẽ load kernel, android, nhưng chỉ chạy ở dạng câu lệnh (console).

setenv bootargs console=ttySAC0,115200n8 androidboot.console=ttySAC0 lcd=S700

\=> để khởi động android thành công với uboot cần nghiên cứu kỹ hơn phần android.

(Bài viết cho tiny4412)

kernel 4412 khi khởi động xong sẽ mount vào phân vùng ext4 của thẻ nhớ để tìm kiếm filesystem để khởi động android.

Vì thế filesystem của android phải là định dạng ext4, và được ghi vào phân vùng ext4 => 3 bước:

1. định dạng phân vùng ext4 cho thẻ nhớ.

2. chuyển đổi systemfile thành định dạng ext4 (system.ext4.img)

3. ghi file ext4 vào phân vùng filesystem

\=>1: định dạng phân vùng ext4 cho thẻ nhớ

1.1 format file bằng window (fast format): bỏ thẻ nhớ vào máy tính, nháy chuột phải chọn format fat32

1.2 phân vùng thẻ nhớ bằng câu lệnh của uboot:

fdisk -c 0 320 806 518

(format thẻ nhớ thành 4 phân vùng 320Mb, 806Mb, 518Mb, và phân vùng phần còn lại của thẻ nhớ)

theo thứ tự phân vùng còn lại số 1, vùng 320 Mb số 2, 806Mb số 3, 518Mb số 4

1.3 định dạng phân vùng tự do số 1 thành phân vùng fat32 để lưu file, bằng câu lệnh uboot

fatformat mmc 0:1

1.4 kiểm tra phân vùng thẻ nhớ đã định dạng bằng câu lệnh uboot

fdisk -l

\====output:====

Disk /dev/sdb: 3965 MB, 3965190144 bytes 244 heads, 31 sectors/track, 1023 cylinders, total 7744512 sectors Units = sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disk identifier: 0x00000000

Device Boot Start End Blocks Id System /dev/sdb1 3517260 7601819 2042280 c W95 FAT32 (LBA) /dev/sdb2 136152 794219 329034 83 Linux ==>system /dev/sdb3 794220 2450735 828258 83 Linux ==>user /dev/sdb4 2450736 3517259 533262 83 Linux ==>cache

\==> phân vùng cần quan tâm là phân vùng số 2: /dev/sdb2

1.5 định dạng phân vùng số 2 & 3 thành ext4 bằng câu lệnh linux ubuntu

mkfs.ext4 /dev/sdb2 mkfs.ext4 /dev/sdb3

bước 2: chuyển đổi định dạng filesystem.img thành ext4

sau khi biên dịch android, system.img có thể được biên dịch theo định dạng yaffs,… vì thế cần chuyển đổi lại thành định dạng ext4,

download tool hoặc sử dụng tool đã có sẵn bộ source android

out/host/linux-x86/bin/simg2img

hoặc download từ link sau: http://web.djodjo.org/?a=download:android:tools:x86_linux:ext4tools

giải nén trên ubuntu rồi thực hiện lệnh chuyển đổi

./img_ext4_tools/simg2img system.img system.ext4.img

sau khi chuyển đổi thành công, file system.ext4.img sẵn sàng cho việc ghi vào phân vùng ext4 để khởi động android.

bước 3: ghi file system.ext4.img vào phân vùng filesystem ( phân vùng số 2 /dev/sdb02)

nguyên lý đơn giản là tạo 2 thư mục trên ubuntu, rồi mount filesystem.ext4 và phân vùng số 2 vào đó

sau đó thực hiện lệnh copy giữ 2 thư mục này, là việc ghi file system.ext4.img lên phân vùng filesystem thành công, chi tiết các lệnh sau: