ตัวเชื่อมโยงแบบไดนามิกจัดการกับความท้าทายสองประการในการออกแบบ Treble VNDK:
- ไลบรารีที่ใช้ร่วมกันของ SP-HAL และการพึ่งพา รวมถึงไลบรารี VNDK-SP ถูกโหลดเข้าสู่กระบวนการเฟรมเวิร์ก ควรมีกลไกป้องกันความขัดแย้งของสัญลักษณ์
-
dlopen()
และandroid_dlopen_ext()
สามารถแนะนำการพึ่งพารันไทม์บางอย่างที่ไม่สามารถมองเห็นได้ในขณะสร้างและอาจตรวจพบได้ยากโดยใช้การวิเคราะห์แบบคงที่
ความท้าทายทั้งสองนี้สามารถแก้ไขได้โดยกลไก เนมสเปซตัวเชื่อมโยง กลไกนี้จัดทำโดยตัวเชื่อมโยงแบบไดนามิก มันสามารถแยกไลบรารีที่ใช้ร่วมกันในเนมสเปซตัวเชื่อมโยงที่แตกต่างกัน เพื่อให้ไลบรารีที่มีชื่อไลบรารีเดียวกันแต่ใช้สัญลักษณ์ต่างกันจะไม่ขัดแย้งกัน
ในอีกทางหนึ่ง กลไกเนมสเปซของลิงเกอร์จัดเตรียมความยืดหยุ่นเพื่อให้บางไลบรารีที่แบ่งใช้สามารถเอ็กซ์พอร์ตโดยเนมสเปซของลิงเกอร์และใช้โดยเนมสเปซตัวเชื่อมโยงอื่น ไลบรารีที่ใช้ร่วมกันที่ส่งออกเหล่านี้สามารถกลายเป็นอินเทอร์เฟซการเขียนโปรแกรมแอปพลิเคชันที่เป็นสาธารณะสำหรับโปรแกรมอื่นในขณะที่ซ่อนรายละเอียดการใช้งานภายในเนมสเปซของตัวเชื่อมโยง
ตัวอย่างเช่น /system/lib[64]/libcutils.so
และ /system/lib[64]/vndk-sp-${VER}/libcutils.so
เป็นไลบรารีที่ใช้ร่วมกันสองไลบรารี ไลบรารีทั้งสองนี้สามารถมีสัญลักษณ์ต่างกันได้ มีการโหลดลงในเนมสเปซตัวเชื่อมโยงที่แตกต่างกันเพื่อให้โมดูลเฟรมเวิร์กสามารถพึ่งพา /system/lib[64]/libcutils.so
และไลบรารีที่ใช้ร่วมกันของ SP-HAL สามารถพึ่งพา /system/lib[64]/vndk-sp-${VER}/libcutils.so
ในอีกทางหนึ่ง /system/lib[64]/libc.so
เป็นตัวอย่างของห้องสมุดสาธารณะที่ส่งออกโดยเนมสเปซของตัวเชื่อมโยงและนำเข้าไปยังเนมสเปซของตัวเชื่อมโยงจำนวนมาก การขึ้นต่อกันของ /system/lib[64]/libc.so
เช่น libnetd_client.so
ถูกโหลดลงในเนมสเปซที่ /system/lib[64]/libc.so
อยู่ เนมสเปซอื่นจะไม่สามารถเข้าถึงการอ้างอิงเหล่านั้นได้ กลไกนี้สรุปรายละเอียดการใช้งานในขณะที่ให้อินเทอร์เฟซสาธารณะ
มันทำงานอย่างไร?
ตัวเชื่อมโยงแบบไดนามิกมีหน้าที่โหลดไลบรารีที่ใช้ร่วมกันที่ระบุในรายการ DT_NEEDED
หรือไลบรารีที่ใช้ร่วมกันที่ระบุโดยอาร์กิวเมนต์ของ dlopen()
หรือ android_dlopen_ext()
ในทั้งสองกรณี ตัวเชื่อมโยงแบบไดนามิกจะค้นหาเนมสเปซของตัวเชื่อมโยงที่ผู้โทรอยู่และพยายามโหลดการขึ้นต่อกันในเนมสเปซตัวเชื่อมโยงเดียวกัน ถ้าตัวเชื่อมโยงแบบไดนามิกไม่สามารถโหลดไลบรารีที่แบ่งใช้ลงในเนมสเปซของตัวเชื่อมโยงที่ระบุได้ โปรแกรมจะขอ เนมสเปซของตัวเชื่อมโยง ที่เชื่อมโยงสำหรับไลบรารีที่ใช้ร่วมกันที่ส่งออก
รูปแบบไฟล์การกำหนดค่า
รูปแบบไฟล์คอนฟิกูเรชันขึ้นอยู่กับรูปแบบไฟล์ INI ไฟล์กำหนดค่าทั่วไปมีลักษณะดังนี้:
dir.system = /system/bin dir.system = /system/xbin dir.vendor = /vendor/bin [system] additional.namespaces = sphal,vndk namespace.default.isolated = true namespace.default.search.paths = /system/${LIB} namespace.default.permitted.paths = /system/${LIB}/hw namespace.default.asan.search.paths = /data/asan/system/${LIB}:/system/${LIB} namespace.default.asan.permitted.paths = /data/asan/system/${LIB}/hw:/system/${LIB}/hw namespace.sphal.isolated = true namespace.sphal.visible = true namespace.sphal.search.paths = /odm/${LIB}:/vendor/${LIB} namespace.sphal.permitted.paths = /odm/${LIB}:/vendor/${LIB} namespace.sphal.asan.search.paths = /data/asan/odm/${LIB}:/odm/${LIB} namespace.sphal.asan.search.paths += /data/asan/vendor/${LIB}:/vendor/${LIB} namespace.sphal.asan.permitted.paths = /data/asan/odm/${LIB}:/odm/${LIB} namespace.sphal.asan.permitted.paths += /data/asan/vendor/${LIB}:/vendor/${LIB} namespace.sphal.links = default,vndk namespace.sphal.link.default.shared_libs = libc.so:libm.so namespace.sphal.link.vndk.shared_libs = libbase.so:libcutils.so namespace.vndk.isolated = true namespace.vndk.search.paths = /system/${LIB}/vndk-sp-29 namespace.vndk.permitted.paths = /system/${LIB}/vndk-sp-29 namespace.vndk.links = default namespace.vndk.link.default.shared_libs = libc.so:libm.so [vendor] namespace.default.isolated = false namespace.default.search.paths = /vendor/${LIB}:/system/${LIB}
ไฟล์การกำหนดค่าประกอบด้วย:
- คุณสมบัติการแม็พส่วนไดเร็กทอรีหลายรายการในตอนเริ่มต้นสำหรับตัวเชื่อมโยงแบบไดนามิกเพื่อเลือกส่วนที่มีผล
- ส่วนคอนฟิกูเรชันเนมสเปซตัวเชื่อมโยงหลายส่วน:
- แต่ละส่วนประกอบด้วยเนมสเปซหลายรายการ (จุดยอดของกราฟ) และลิงก์สำรองหลายรายการระหว่างเนมสเปซ (ส่วนโค้งของกราฟ)
- เนมสเปซแต่ละรายการมีการแยก เส้นทางการค้นหา เส้นทางที่อนุญาต และการตั้งค่าการมองเห็นเป็นของตัวเอง
ตารางด้านล่างอธิบายความหมายของแต่ละคุณสมบัติโดยละเอียด
คุณสมบัติการแมปส่วนไดเร็กทอรี
คุณสมบัติ | คำอธิบาย | ตัวอย่าง |
---|---|---|
| พาธไปยังไดเร็กทอรีที่ใช้ส่วน แต่ละคุณสมบัติแม็พไฟล์เรียกทำงานภายใต้ไดเร็กทอรีกับส่วนคอนฟิกูเรชันเนมสเปซของลิงเกอร์ อาจมีคุณสมบัติสองรายการ (หรือมากกว่า) ที่มี | สิ่งนี้บ่งชี้ว่าการกำหนดค่าที่ระบุในส่วน การกำหนดค่าที่ระบุในส่วน |
คุณสมบัติสัมพันธ์
คุณสมบัติ | คำอธิบาย | ตัวอย่าง |
---|---|---|
additional. namespaces | รายการเนมสเปซเพิ่มเติมที่คั่นด้วยเครื่องหมายจุลภาค (นอกเหนือจากเนมสเปซ | สิ่งนี้บ่งชี้ว่ามีสามเนมสเปซ ( |
namespace. name . links | รายการเนมสเปซทางเลือกที่คั่นด้วยจุลภาค หากไม่พบไลบรารีที่แชร์ในเนมสเปซปัจจุบัน ตัวเชื่อมโยงแบบไดนามิกจะพยายามโหลดไลบรารีที่แชร์จากเนมสเปซทางเลือก เนมสเปซที่ระบุที่จุดเริ่มต้นของรายการมีลำดับความสำคัญสูงกว่า | หากไลบรารีที่ใช้ร่วมกันหรือไฟล์เรียกทำงานร้องขอไลบรารีที่แบ่งใช้ที่ไม่สามารถโหลดลงใน จากนั้น ถ้าไลบรารีที่ใช้ร่วมกันไม่สามารถโหลดจากเนมสเปซ สุดท้าย หากความพยายามทั้งหมดล้มเหลว ตัวเชื่อมโยงแบบไดนามิกจะส่งกลับข้อผิดพลาด |
namespace. name . link. other . shared_libs | รายการไลบรารีที่แบ่งใช้ที่คั่นด้วยโคลอนซึ่งสามารถค้นหาได้ในเนมสเปซ คุณสมบัตินี้ใช้กับ | สิ่งนี้บ่งชี้ว่าลิงก์ทางเลือกยอมรับเฉพาะ |
namespace. name . link. other . allow_all_shared_libs | ค่าบูลีนที่ระบุว่าสามารถค้นหาไลบรารีที่แบ่งใช้ทั้งหมดในเนมสเปซ คุณสมบัตินี้ใช้กับ | สิ่งนี้บ่งชี้ว่าชื่อไลบรารีทั้งหมดสามารถเดินผ่านลิงก์สำรองจาก |
คุณสมบัติเนมสเปซ
คุณสมบัติ | คำอธิบาย | ตัวอย่าง |
---|---|---|
namespace. name . isolated | ค่าบูลีนที่ระบุว่าไดนามิกลิงเกอร์ควรตรวจสอบว่าไลบรารีที่แบ่งใช้อยู่ที่ใด หาก หากการ | สิ่งนี้บ่งชี้ว่า เฉพาะไลบรารีที่แบ่งใช้ใน |
namespace. name . search.paths | รายการไดเร็กทอรีที่คั่นด้วยโคลอนเพื่อค้นหาไลบรารีที่แบ่งใช้ ไดเร็กทอรีที่ระบุใน เมื่อ ตัวอย่างเช่น หาก | สิ่งนี้บ่งชี้ว่าไดนามิกลิงก์เกอร์ค้นหา |
namespace. name . asan.search.paths | รายการไดเร็กทอรีที่คั่นด้วยโคลอนเพื่อค้นหาไลบรารีที่แบ่งใช้เมื่อเปิดใช้งาน AddressSanitizer (ASan) | สิ่งนี้บ่งชี้ว่าเมื่อเปิดใช้งาน ASan ตัวเชื่อมโยงแบบไดนามิกจะค้นหา |
namespace. name . permitted.paths | รายการไดเร็กทอรีที่คั่นด้วยโคลอน (รวมถึงไดเร็กทอรีย่อย) โดยที่ตัวเชื่อมโยงแบบไดนามิกสามารถโหลดไลบรารีที่แบ่งใช้ (นอกเหนือจาก ไลบรารีที่แบ่งใช้ที่อยู่ภายใต้ไดเร็กทอรีย่อยของ หาก | สิ่งนี้บ่งชี้ว่าไลบรารีที่แบ่งใช้ภายใต้ ตัวอย่างเช่น หากไม่มี |
namespace. name . asan.permitted.paths | รายการไดเร็กทอรีที่คั่นด้วยโคลอนซึ่งตัวเชื่อมโยงแบบไดนามิกสามารถโหลดไลบรารีที่แบ่งใช้เมื่อเปิดใช้งาน ASan | สิ่งนี้บ่งชี้ว่าเมื่อเปิดใช้งาน ASan ไลบรารีที่แบ่งใช้ภายใต้ |
namespace. name . visible | ค่าบูลีนที่ระบุว่าโปรแกรม (นอกเหนือจาก หาก หาก | สิ่งนี้บ่งชี้ว่า |
การสร้างเนมสเปซตัวเชื่อมโยง
ใน Android 11 การกำหนดค่าตัวเชื่อมโยงจะถูกสร้างขึ้นที่รันไทม์ภายใต้ /linkerconfig
แทนที่จะใช้ไฟล์ข้อความธรรมดาใน ${android-src}/system/core/rootdir/etc
คอนฟิกูเรชันถูกสร้างขึ้นในเวลาบูตตามสภาวะแวดล้อมรันไทม์ ซึ่งรวมถึงรายการต่อไปนี้:
- หากอุปกรณ์รองรับ VNDK
- เวอร์ชัน VNDK เป้าหมายของพาร์ติชันผู้จัดจำหน่าย
- เวอร์ชัน VNDK ของพาร์ติชันผลิตภัณฑ์
- โมดูล APEX ที่ติดตั้งแล้ว
การกำหนดค่าตัวเชื่อมโยงถูกสร้างขึ้นโดยการแก้ไขการพึ่งพาระหว่างเนมสเปซของตัวเชื่อมโยง ตัวอย่างเช่น หากมีการอัปเดตใดๆ บนโมดูล APEX ที่มีการอัปเดตการขึ้นต่อกัน การกำหนดค่าตัวเชื่อมโยงจะถูกสร้างขึ้นเพื่อสะท้อนถึงการเปลี่ยนแปลงเหล่านี้ รายละเอียดเพิ่มเติมในการสร้างการกำหนดค่าตัวเชื่อมโยงสามารถพบได้ใน ${android-src}/system/linkerconfig
การแยกเนมสเปซตัวเชื่อมโยง
มีการกำหนดค่าสามประเภท ขึ้นอยู่กับค่าของ PRODUCT_TREBLE_LINKER_NAMESPACES
และ BOARD_VNDK_VERSION
ใน BoardConfig.mk
การกำหนดค่าที่เกี่ยวข้องจะถูกสร้างขึ้นในเวลาบูต
PRODUCT_TREBLE_ LINKER_NAMESPACES | BOARD_VNDK_ VERSION | การกำหนดค่าที่เลือก | ข้อกำหนด VTS |
---|---|---|---|
true | current | VNDK | บังคับสำหรับอุปกรณ์ที่เปิดตัวด้วย Android 9 หรือสูงกว่า |
ว่างเปล่า | VNDK Lite | บังคับสำหรับอุปกรณ์ที่เปิดตัวด้วย Android 8.x | |
false | ว่างเปล่า | Legacy | สำหรับอุปกรณ์ที่ไม่ใช่เสียงแหลม |
การกำหนดค่า VNDK Lite แยกไลบรารีที่ใช้ร่วมกัน SP-HAL และ VNDK-SP ใน Android 8.0 ไฟล์นี้ต้องเป็นไฟล์การกำหนดค่าสำหรับตัวเชื่อมโยงแบบไดนามิกเมื่อ PRODUCT_TREBLE_LINKER_NAMESPACES
เป็น true
การกำหนดค่า VNDK ยังแยกไลบรารีที่ใช้ร่วมกัน SP-HAL และ VNDK-SP นอกจากนี้ การกำหนดค่านี้ยังมีการแยกตัวเชื่อมโยงแบบไดนามิกทั้งหมด ช่วยให้มั่นใจได้ว่าโมดูลในพาร์ติชันระบบจะไม่ขึ้นอยู่กับไลบรารีที่แบ่งใช้ในพาร์ติชันของผู้จัดจำหน่ายและในทางกลับกัน
ใน Android 8.1 หรือสูงกว่า การกำหนดค่า VNDK เป็นการกำหนดค่าเริ่มต้น และขอแนะนำเป็นอย่างยิ่งให้เปิดใช้งานการแยกตัวเชื่อมโยงแบบไดนามิกแบบเต็มโดยการตั้งค่า BOARD_VNDK_VERSION
current
ไฟล์ .
การกำหนดค่า VNDK
คอนฟิกูเรชัน VNDK แยกการพึ่งพาไลบรารีที่แบ่งใช้ระหว่างพาร์ติชันระบบและพาร์ติชันของผู้ขาย เมื่อเทียบกับการกำหนดค่าที่กล่าวถึงในส่วนย่อยก่อนหน้านี้ ความแตกต่างจะสรุปได้ดังนี้:
กระบวนการกรอบงาน
-
default
,vndk
,sphal
และrs
เนมสเปซจะถูกสร้างขึ้น - เนมสเปซทั้งหมดจะถูกแยกออก
- ไลบรารีที่แบ่งใช้ของระบบถูกโหลดลงในเนมสเปซ
default
- SP-HAL ถูกโหลดลงในเนมสเปซ
sphal
- ไลบรารีที่แบ่งใช้ VNDK-SP โหลดลงในเนมสเปซ
vndk
-
กระบวนการของผู้จำหน่าย
-
default
,vndk
และเนมสเปซsystem
จะถูกสร้างขึ้น - เนมสเปซ
default
จะถูกแยกออก - ไลบรารีที่แบ่งใช้ของผู้จัดจำหน่ายถูกโหลดลงในเนมสเปซ
default
- ไลบรารีที่แบ่งใช้ VNDK และ VNDK-SP ถูกโหลดลงในเนมสเปซ
vndk
- LL-NDK และการขึ้นต่อกันถูกโหลดลงในเนมสเปซ
system
-
ความสัมพันธ์ระหว่างเนมสเปซตัวเชื่อมโยงมีภาพประกอบด้านล่าง

ในภาพด้านบน LL-NDK และ VNDK-SP ย่อ มาจากไลบรารีที่ใช้ร่วมกันต่อไปนี้:
- LL-NDK
-
libEGL.so
-
libGLESv1_CM.so
-
libGLESv2.so
-
libGLESv3.so
-
libandroid_net.so
-
libc.so
-
libdl.so
-
liblog.so
-
libm.so
-
libnativewindow.so
-
libneuralnetworks.so
-
libsync.so
-
libvndksupport.so
-
libvulkan.so
-
- VNDK-SP
-
android.hardware.graphics.common@1.0.so
-
android.hardware.graphics.mapper@2.0.so
-
android.hardware.renderscript@1.0.so
-
android.hidl.memory@1.0.so
-
libRSCpuRef.so
-
libRSDriver.so
-
libRS_internal.so
-
libbase.so
-
libbcinfo.so
-
libc++.so
-
libcutils.so
-
libhardware.so
-
libhidlbase.so
-
libhidlmemory.so
-
libhidltransport.so
-
libhwbinder.so
-
libion.so
-
libutils.so
-
libz.so
-
คุณสามารถดูรายละเอียดเพิ่มเติมใน /linkerconfig/ld.config.txt
จากอุปกรณ์
การกำหนดค่า VNDK Lite
ตั้งแต่ Android 8.0 เป็นต้นไป ตัวเชื่อมโยงแบบไดนามิกได้รับการกำหนดค่าให้แยกไลบรารีที่ใช้ร่วมกันของ SP-HAL และ VNDK-SP เพื่อให้สัญลักษณ์ไม่ขัดแย้งกับไลบรารีที่ใช้ร่วมกันของเฟรมเวิร์กอื่น ความสัมพันธ์ระหว่างเนมสเปซตัวเชื่อมโยงแสดงอยู่ด้านล่าง

LL-NDK และ VNDK-SP ย่อ มาจากไลบรารีที่ใช้ร่วมกันต่อไปนี้:
- LL-NDK
-
libEGL.so
-
libGLESv1_CM.so
-
libGLESv2.so
-
libc.so
-
libdl.so
-
liblog.so
-
libm.so
-
libnativewindow.so
-
libstdc++.so
(ไม่อยู่ในการกำหนดค่า) -
libsync.so
-
libvndksupport.so
-
libz.so
(ย้ายไปที่ VNDK-SP ในการกำหนดค่า)
-
- VNDK-SP
-
android.hardware.graphics.common@1.0.so
-
android.hardware.graphics.mapper@2.0.so
-
android.hardware.renderscript@1.0.so
-
android.hidl.memory@1.0.so
-
libbase.so
-
libc++.so
-
libcutils.so
-
libhardware.so
-
libhidlbase.so
-
libhidlmemory.so
-
libhidltransport.so
-
libhwbinder.so
-
libion.so
-
libutils.so
-
ตารางด้านล่างแสดงรายการการกำหนดค่าเนมสเปซสำหรับกระบวนการเฟรมเวิร์ก ซึ่งคัดลอกมาจากส่วน [system]
ในการกำหนดค่า VNDK Lite
เนมสเปซ | คุณสมบัติ | ค่า |
---|---|---|
default | search.paths | /system/${LIB} /odm/${LIB} /vendor/${LIB} /product/${LIB} |
isolated | false | |
sphal | search.paths | /odm/${LIB} /vendor/${LIB} |
permitted.paths | /odm/${LIB} /vendor/${LIB} | |
isolated | true | |
visible | true | |
links | default,vndk,rs | |
link.default.shared_libs | LL-NDK | |
link.vndk.shared_libs | VNDK-SP | |
link.rs.shared_libs | libRS_internal.so | |
vndk (สำหรับ VNDK-SP) | search.paths | /odm/${LIB}/vndk-sp /vendor/${LIB}/vndk-sp /system/${LIB}/vndk-sp-${VER} |
permitted.paths | /odm/${LIB}/hw /odm/${LIB}/egl /vendor/${LIB}/hw /vendor/${LIB}/egl /system/${LIB}/vndk-sp-${VER}/hw | |
isolated | true | |
visible | true | |
links | default | |
link.default.shared_libs | LL-NDK | |
rs (สำหรับ RenderScript) | search.paths | /odm/${LIB}/vndk-sp /vendor/${LIB}/vndk-sp /system/${LIB}/vndk-sp-${VER} /odm/${LIB} /vendor/${LIB} |
permitted.paths | /odm/${LIB} /vendor/${LIB} /data (สำหรับเคอร์เนล RS ที่คอมไพล์แล้ว) | |
isolated | true | |
visible | true | |
links | default,vndk | |
link.default.shared_libs | LL-NDKlibmediandk.so libft2.so | |
link.vndk.shared_libs | VNDK-SP |
ตารางด้านล่างแสดงการกำหนดค่าเนมสเปซสำหรับกระบวนการของผู้ขาย ซึ่งคัดลอกมาจากส่วน [vendor]
ในการกำหนดค่า VNDK Lite
เนมสเปซ | คุณสมบัติ | ค่า |
---|---|---|
default | search.paths | /odm/${LIB} /odm/${LIB}/vndk /odm/${LIB}/vndk-sp /vendor/${LIB} /vendor/${LIB}/vndk /vendor/${LIB}/vndk-sp /system/${LIB}/vndk-${VER} /system/${LIB}/vndk-sp-${VER} /system/${LIB} (เลิกใช้แล้ว)/product/${LIB} (เลิกใช้งานแล้ว) |
isolated | false |
รายละเอียดเพิ่มเติมสามารถพบได้ใน /linkerconfig/ld.config.txt
จากอุปกรณ์
ประวัติเอกสาร
การเปลี่ยนแปลงของ Android 11
- ใน Android 11 ไฟล์
ld.config.*.txt
แบบคงที่จะถูกลบออกจาก codebase และ LinkerConfig จะสร้างไฟล์เหล่านี้ในรันไทม์แทน
Android 9 เปลี่ยนไป
- ใน Android 9 เนมสเปซตัวเชื่อมโยง
vndk
จะถูกเพิ่มไปยังกระบวนการของผู้จัดจำหน่าย และไลบรารีที่ใช้ร่วมกันของ VNDK จะถูกแยกออกจากเนมสเปซตัวเชื่อมโยงเริ่มต้น - แทนที่
PRODUCT_FULL_TREBLE
ด้วยPRODUCT_TREBLE_LINKER_NAMESPACES
ที่เฉพาะเจาะจงมากขึ้น - Android 9 เปลี่ยนชื่อของไฟล์การกำหนดค่าตัวเชื่อมโยงแบบไดนามิกต่อไปนี้
Android 8.x Android 9 คำอธิบาย ld.config.txt.in
ld.config.txt
สำหรับอุปกรณ์ที่มีการแยกเนมสเปซตัวเชื่อมโยงรันไทม์ ld.config.txt
ld.config.vndk_lite.txt
สำหรับอุปกรณ์ที่มีการแยกเนมสเปซตัวเชื่อมโยง VNDK-SP ld.config.legacy.txt
ld.config.legacy.txt
สำหรับอุปกรณ์รุ่นเก่าที่ใช้ Android 7.x หรือต่ำกว่า - ลบ
android.hardware.graphics.allocator@2.0.so
- มีการเพิ่มพาร์ติชัน
product
และodm