یک روتر مرزی اندروید بسازید

منبع را در جستجوی کد اندروید مشاهده کنید

اگر یک دستگاه Android یا فروشنده تراشه Thread نیستید، می‌توانید اکنون مطالعه را متوقف کنید.

این سند شما را در مراحل ساخت یک دستگاه Thread Border Router جدید مبتنی بر Android با آخرین کد منبع AOSP راهنمایی می کند. با دنبال کردن این سند، یاد خواهید گرفت:

  1. ساختار کلی و وضعیت پشتیبانی Thread در اندروید
  2. چگونه سرویس Thread HAL خود را ایجاد کنید
  3. چگونه دستگاه خود را با Google Home سازگار کنیم
  4. چگونه Thread Border Router خود را تست کنیم

اگر به پشتیبانی نیاز دارید، مشکلی را در GitHub ثبت کنید یا اگر سؤالی دارید، یک Dicussion را باز کنید.

نمای کلی

پشته Thread Android بر اساس OpenThread و ot-br-posix است که توسط Google در GitHub منبع باز هستند. همانطور که OpenThread در یک مخزن عمومی GitHub توسعه می یابد، بنابراین پشته Thread Android در پایگاه کد عمومی AOSP توسعه می یابد. همه ویژگی ها و رفع اشکال ابتدا در AOSP ارسال می شوند. این به فروشندگان اجازه می‌دهد تا بدون انتظار برای نسخه‌های معمولی اندروید، آخرین نسخه‌های Thread را اتخاذ کنند.

معماری

کل پشته Thread Android از دو جزء اصلی تشکیل شده است: پشته Thread هسته در یک پارتیشن سیستم عمومی و سرویس Thread HAL در یک پارتیشن فروشنده. فروشندگان دستگاه معمولاً فقط به مراقبت و ساخت سرویس HAL نیاز دارند.

android-thread-arch

در اینجا خلاصه‌ای از نحوه عملکرد پشته Thread Android آورده شده است: - یک سرویس سیستم Java Thread در سرور سیستم وجود دارد که کل پشته را مدیریت می‌کند - API سیستم Thread را ارائه می‌کند، رابط تونل thread-wpan را ایجاد می‌کند، شبکه Thread را ثبت می‌کند. سرویس اتصال و قابلیت های مسیریابی مرزی و پروکسی تبلیغاتی را پیاده سازی می کند. - پشته اصلی Thread / OpenThread در یک فرآیند بومی مستقل غیرمجاز میزبانی می شود که ot-daemon نام دارد. ot-daemon مستقیماً توسط سرویس سیستم جاوا از طریق APIهای خصوصی AIDL مدیریت می شود و از طریق Thread HAL API به رادیو سخت افزار Thread دسترسی پیدا می کند. - یک سرویس Thread HAL ارائه شده توسط فروشنده باید Thread HAL API را پیاده سازی کند. معمولاً به عنوان یک RCP کار می کند و پروتکل اسپینل را پیاده سازی می کند.

کد کجاست؟

محیط توسعه را تنظیم کنید

فروشندگان دستگاه های اندرویدی که قبلاً یک محیط توسعه اندروید برای دستگاه ایجاد کرده اند، می توانند از این بخش صرف نظر کنند.

اگر تازه وارد اکوسیستم اندروید هستید یا فروشنده سیلیکونی هستید که می‌خواهید تراشه Thread خود را با اندروید سازگار کنید و برای فروشندگان دستگاه‌ها پشتیبانی کنید، به خواندن ادامه دهید.

کد لبه برنامه‌نویس اندروید را دنبال کنید

برای راه‌اندازی محیط توسعه اندروید خود برای اولین بار، از لبه کد زیر استفاده کنید: https://source.android.com/docs/setup/start . در پایان این کد لبه، شما قادر خواهید بود یک دستگاه Cuttlefish شبیه سازی شده را از روی کد منبع بسازید و اجرا کنید.

سرویس Thread HAL خود را بسازید

Thread in Cuttlefish را امتحان کنید

Cuttlefish یک دستگاه اندروید مجازی است. قبل از شروع ساخت سرویس HAL خود، بهتر است Thread را در Cuttlefish امتحان کنید تا بفهمید HAL چگونه کار می کند.

یک سرویس Thread HAL پیش‌فرض در Cuttlefish ارائه می‌شود و با RCP شبیه‌سازی شده پیاده‌سازی می‌شود که بسته‌ها را از طریق سوکت UDP به و از یک رادیوی Thread (802.15.4) شبیه‌سازی شده دریافت می‌کند.

در نمونه Cuttlefish، یک "ThreadNetworkDemoApp" از قبل نصب شده است. آن برنامه را باز کنید تا دستگاه Cuttlefish را به یک شبکه Thread پیش فرض بپیوندید.

demoapp-screenshot

همچنین ابزارهای خط فرمان ot-ctl و ot-cli-ftd برای پیکربندی شبکه Thread برای آزمایش ارائه شده است. این ابزارها از تمام دستورات OpenThread CLI که ممکن است قبلاً با آنها آشنا باشید پشتیبانی می کنند.

شما می توانید سیاهههای مربوط به سرویس Cutttlefish Thread HAL را توسط:

adb logcat | egrep -i threadnetwork-service

07-21 10:43:05.048     0     0 I init    : Parsing file /apex/com.android.hardware.threadnetwork/etc/threadnetwork-service.rc...
07-21 10:59:27.233   580   580 W android.hardware.threadnetwork-service: ThreadChip binder is unlinked
07-21 10:59:27.233   580   580 I android.hardware.threadnetwork-service: Close IThreadChip successfully
07-21 10:59:27.385   580   580 I android.hardware.threadnetwork-service: Open IThreadChip successfully

یا grep برای گزارش های ot-daemon توسط:

adb logcat | egrep -i ot-daemon
07-21 10:43:48.741     0     0 I init    : starting service 'ot-daemon'...
07-21 10:43:48.742     0     0 I init    : Created socket '/dev/socket/ot-daemon/thread-wpan.sock', mode 660, user 1084, group 1084
07-21 10:43:48.762     0     0 I init    : ... started service 'ot-daemon' has pid 2473
07-21 10:46:26.320  2473  2473 I ot-daemon: [I] P-Daemon------: Session socket is ready
07-21 10:46:30.290  2473  2473 W ot-daemon: [W] P-Daemon------: Daemon read: Connection reset by peer
07-21 10:48:07.264  2473  2473 I ot-daemon: [INFO]-BINDER--: Start joining...
07-21 10:48:07.267  2473  2473 I ot-daemon: [I] Settings------: Saved ActiveDataset
07-21 10:48:07.267  2473  2473 I ot-daemon: [I] DatasetManager: Active dataset set
07-21 10:48:07.273  2473  2473 I ot-daemon: [I] DnssdServer---: Started
07-21 10:48:07.273  2473  2473 I ot-daemon: [N] Mle-----------: Role disabled -> detached
07-21 10:48:07.273  2473  2473 I ot-daemon: [I] Mle-----------: AttachState Idle -> Start
07-21 10:48:07.273  2473  2473 I ot-daemon: [I] Notifier------: StateChanged (0x111fd11d) [Ip6+ Role LLAddr MLAddr KeySeqCntr Ip6Mult+ Channel PanId NetName ExtPanId ...
07-21 10:48:07.273  2473  2473 I ot-daemon: [I] Notifier------: StateChanged (0x111fd11d) ... NetworkKey PSKc SecPolicy NetifState ActDset]

سرویس Cuttlefish Thread HAL از سرویس پیش‌فرض Thread HAL به‌علاوه باینری RCP شبیه‌سازی شده OpenThread استفاده می‌کند، بخش بعدی را برای نحوه عملکرد آن ببینید.

سرویس پیش فرض HAL

یک سرویس HAL پیش فرض همراه با Thread HAL API گنجانده شده است. سرویس HAL پیش فرض از دستگاه های RCP شبیه سازی شده و واقعی پشتیبانی می کند. یک URL اختیاری دستگاه RCP دریافت می کند و اگر URL ارائه نشده باشد، به طور پیش فرض به دستگاه RCP شبیه سازی شده تبدیل می شود.

در فایل hardware/interfaces/threadnetwork/aidl/default/threadnetwork-service.rc :

service vendor.threadnetwork_hal /apex/com.android.hardware.threadnetwork/bin/hw/android.hardware.threadnetwork-service
    class hal
    user thread_network

این معادل است با:

service vendor.threadnetwork_hal /apex/com.android.hardware.threadnetwork/bin/hw/android.hardware.threadnetwork-service spinel+hdlc+forkpty:///apex/com.android.hardware.threadnetwork/bin/ot-rcp?forkpty-arg=1
    class hal
    user thread_network

برای دستگاه های RCP واقعی، از هر دو رابط SPI و UART پشتیبانی می کند و می توانید دستگاه را به ترتیب با schema spinel+spi:// ، spinel+hdlc+uart:// و spinel+socket:// مشخص کنید.

APEX فروشنده را درک کنید

مشابه پشته Thread در ماژول خط اصلی Tethering، سرویس پیش‌فرض Thread HAL در Cuttlefish در یک ماژول APEX نیز بسته‌بندی شده است. اما این یک ماژول APEX فروشنده است که در /vendor/apex/ نصب می شود (مصنوعات موجود در ماژول به /apex/com.android.hardware.threadnetwork/ از حالت فشرده خارج می شوند).

apex {
    name: "com.android.hardware.threadnetwork",
    manifest: "manifest.json",
    file_contexts: "file_contexts",
    key: "com.android.hardware.key",
    certificate: ":com.android.hardware.certificate",
    updatable: false,
    vendor: true,

    binaries: [
        "android.hardware.threadnetwork-service",
        "ot-rcp",
    ],

    prebuilts: [
        "threadnetwork-default.xml", // vintf_fragment
        "threadnetwork-service.rc", // init_rc
        "android.hardware.thread_network.prebuilt.xml", // permission
    ],
}

چند پیکربندی مهم وجود دارد که هنگام ساخت ماژول HAL APEX خود باید به آنها توجه کنید یا تغییراتی در آنها ایجاد کنید:

  • file_contexts : این فایل‌های باینری/داده ارائه‌شده در این ماژول APEX یا فایل‌هایی را که سرویس HAL باید به آنها دسترسی داشته باشد (مثلاً دستگاه RCP) توصیف می‌کند. این به شما این امکان را می دهد که قوانین سیاست گذاری خاصی را برای سرویس HAL خود برای دسترسی به دستگاه RCP سخت افزاری مشخص کنید.

  • binaries : فایل باینری ارائه شده در این ماژول APEX

  • threadnetwork-service.rc : نحوه راه اندازی سرویس HAL. در اینجا باید مسیر دستگاه RCP را مشخص کنید.

  • android.hardware.thread_network.prebuilt.xml : ویژگی سخت افزار android.hardware.thread_network را تعریف می کند. این برای سیستم Android لازم است تا بداند دستگاه شما از سخت افزار Thread پشتیبانی می کند. در غیر این صورت، پشته Thread Android فعال نخواهد شد.

سرویس HAL خود را ایجاد کنید

چه یک توسعه دهنده دستگاه اندرویدی یا یک فروشنده سیلیکون باشید، باید با ساخت سیستم عامل OT RCP برای تراشه Thread خود آشنا باشید. در دستورالعمل های زیر فرض می شود که تراشه سخت افزاری به درستی سیم کشی و تایید شده است.

ساده ترین راه برای ساخت HAL APEX ایجاد یک APEX جدید با باینری ها و پیش ساخته های HAL APEX پیش فرض است. به عنوان مثال، اگر شرکت شما Banana است و دستگاه RCP روی دستگاه شما /dev/ttyACM0 است، Thread HAL APEX شما به شکل زیر خواهد بود:

  • Android.bp :
  prebuilt_etc {
    name: "banana-threadnetwork-service.rc",
    src: "banana-threadnetwork-service.rc",
    installable: false,
  }

  apex {
    name: "com.banana.android.hardware.threadnetwork",
    manifest: "manifest.json",
    file_contexts: "file_contexts",
    key: "com.android.hardware.key",
    certificate: ":com.android.hardware.certificate",
    updatable: false,
    vendor: true,

    binaries: [
        "android.hardware.threadnetwork-service",
    ],

    prebuilts: [
        "banana-threadnetwork-service.rc",
        "threadnetwork-default.xml",
        "android.hardware.thread_network.prebuilt.xml",
    ],
  }
  • file_contexts :
  (/.*)?                                                      u:object_r:vendor_file:s0
  /etc(/.*)?                                                  u:object_r:vendor_configs_file:s0
  /bin/hw/android\.hardware\.threadnetwork-service            u:object_r:hal_threadnetwork_default_exec:s0
  /dev/ttyACM0                                                u:object_r:threadnetwork_rcp_device:s0

مسیرهای فایل در ستون اول مربوط به /apex/com.android.hardware.threadnetwork/ هستند.

  • threadnetwork-service.rc :
  service vendor.threadnetwork_hal /apex/com.android.hardware.threadnetwork/bin/hw/android.hardware.threadnetwork-service spinel+hdlc+uart:///dev/ttyACM0?uart-baudrate=115200
    class hal
    user root
  • manifest.json :
  {
    "name": "com.android.hardware.threadnetwork",
    "version": 1
  }

با فرض اینکه در حال ساخت یک دستگاه جدید به نام Orange هستید، دایرکتوری پیکربندی خاص دستگاه شما به صورت زیر خواهد بود:

device/banana/orange/threadnetwork/
    sepolicy/
    Android.bp
    file_contexts
    manifest.json
    threadnetwork-default.xml
    threadnetwork-service.rc

بخش بعدی را ببینید که چه قوانین sepolicy باید در فهرست sepolicy/ زیر دایرکتوری اضافه شود.

قوانین سیاست برای دستگاه RCP

به‌طور پیش‌فرض، سرویس Thread HAL شما به دستگاه RCP دسترسی ندارد (به عنوان مثال /dev/ttyACM0 )، قوانین sepolicy سفارشی باید به فهرست sepolicy/ اضافه شوند.

یک فایل sepolicy/threadnetwork_hal.te جدید با محتوای زیر ایجاد کنید:

type threadnetwork_rcp_device, dev_type;

# Allows the Thread HAL service to read / write the Thread RCP device
allow hal_threadnetwork_default threadnetwork_rcp_device:chr_file rw_file_perms;

کنار هم قرار دهید

اکنون تقریباً تمام کدهای مورد نیاز برای افزودن Thread را تمام کرده اید، آخرین مرحله اضافه کردن Thread HAL APEX و قوانین sepolicy به تصویر دستگاه شما است.

می توانید این کار را با افزودن کد زیر به Makefile دستگاه خود (به عنوان مثال device.mk ) انجام دهید:

PRODUCT_PACKAGES += com.banana.hardware.threadnetwork
BOARD_SEPOLICY_DIRS += device/banana/orange/threadnetwork/sepolicy

اگر همه چیز کار کند، اکنون می توانید گزارش سرویس Thread HAL را مشابه موارد زیر مشاهده کنید:

adb logcat | egrep -i threadnetwork-service
08-13 13:26:41.751   477   477 I android.hardware.threadnetwork-service: ServiceName: android.hardware.threadnetwork.IThreadChip/chip0, Url: spinel+spi
08-13 13:26:41.751   477   477 I android.hardware.threadnetwork-service: Thread Network HAL is running
08-13 13:26:55.165   477   477 I android.hardware.threadnetwork-service: Open IThreadChip successfully

و گزارش ot-daemon به صورت زیر خواهد بود:

adb logcat -s ot-daemon
08-13 13:26:55.157  1019  1019 I ot-daemon: [NOTE]-AGENT---: Running OTBR_AGENT/Unknown
08-13 13:26:55.157  1019  1019 I ot-daemon: [NOTE]-AGENT---: Thread version: 1.3.0
08-13 13:26:55.157  1019  1019 I ot-daemon: [NOTE]-AGENT---: Thread interface: thread-wpan
08-13 13:26:55.157  1019  1019 I ot-daemon: [NOTE]-AGENT---: Backbone interface is not specified
08-13 13:26:55.157  1019  1019 I ot-daemon: [NOTE]-AGENT---: Radio URL: threadnetwork_hal://binder?none
08-13 13:26:55.157  1019  1019 I ot-daemon: [NOTE]-ILS-----: Infra link selected:
08-13 13:26:55.160  1019  1019 I ot-daemon: [I] Platform------: [HAL] Wait for getting the service android.hardware.threadnetwork.IThreadChip/chip0 ...
08-13 13:26:55.165  1019  1019 I ot-daemon: [I] Platform------: [HAL] Successfully got the service android.hardware.threadnetwork.IThreadChip/chip0
08-13 13:26:55.275  1019  1019 I ot-daemon: [I] P-RadioSpinel-: RCP reset: RESET_UNKNOWN
08-13 13:26:55.276  1019  1019 I ot-daemon: [I] P-RadioSpinel-: Software reset RCP successfully
08-13 13:26:55.277  1019  1019 I ot-daemon: [I] P-RadioSpinel-: RCP reset: RESET_POWER_ON
08-13 13:26:55.322  1019  1019 I ot-daemon: [I] ChildSupervsn-: Timeout: 0 -> 190
08-13 13:26:55.324  1019  1019 I ot-daemon: [I] RoutingManager: Initializing - InfraIfIndex:0
08-13 13:26:55.324  1019  1019 I ot-daemon: [I] InfraIf-------: Init infra netif 0
08-13 13:26:55.324  1019  1019 I ot-daemon: [I] Settings------: Read BrUlaPrefix fd7b:cc45:ff06::/48
08-13 13:26:55.324  1019  1019 I ot-daemon: [N] RoutingManager: BR ULA prefix: fd7b:cc45:ff06::/48 (loaded)
08-13 13:26:55.324  1019  1019 I ot-daemon: [I] RoutingManager: Generated local OMR prefix: fd7b:cc45:ff06:1::/64
08-13 13:26:55.324  1019  1019 I ot-daemon: [N] RoutingManager: Local on-link prefix: fdde:ad00:beef:cafe::/64
08-13 13:26:55.324  1019  1019 I ot-daemon: [I] RoutingManager: Enabling

سفارشی سازی

ماژول خط اصلی Thread (در واقع بخشی از ماژول "Tethering" است) چند پیکربندی قابل همپوشانی را ارائه می دهد که می تواند توسط فروشندگان برای سفارشی کردن رفتار پشته مشخص شود. برای مشاهده لیست کامل به config_thread.xml مراجعه کنید.

به طور معمول، شما باید config_thread_vendor_name ، config_thread_vendor_oui و config_thread_model_name به مقدار فروشنده یا محصول خود تغییر دهید. این مقادیر در سرویس mDNS _meshcop._udp که همیشه توسط Thread Border Router تبلیغ می شود، گنجانده می شود.

برای افزودن همپوشانی، باید یک هدف جدید ConnectivityOverlayOrange runtime_resource_overlay برای دستگاه Orange خود ایجاد کنید. یک پوشه ConnectivityOverlay/ در زیر device/banana/orange/rro_overlays ایجاد کنید و محتوای زیر را در آن ایجاد کنید:

device/banana/orange/rro_overlays/ConnectivityOverlay/
  res
    values
      config_thread.xml
  Android.bp
  AndroidManifest.xml
  • Android.bp :
  package {
      default_applicable_licenses: ["Android-Apache-2.0"],
  }

  runtime_resource_overlay {
      name: "ConnectivityOverlayOrange",
      manifest: "AndroidManifest.xml",
      resource_dirs: ["res"],
      certificate: "platform",
      product_specific: true,
      sdk_version: "current",
  }
  • AndroidManifest.xml :
  <!-- Orange overlays for the Connectivity module -->
  <manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.banana.android.connectivity.resources.orange"
      android:versionCode="1"
      android:versionName="1.0">
      <application android:hasCode="false" />

      <!-- If your device uses google-signed mainline modules, the targetPackage
      needs to be "com.google.android.connectivity.resources", otherise, it
      should be "com.android.connectivity.resources"
      -->
      <overlay
          android:targetPackage="com.google.android.connectivity.resources"
          android:targetName="ServiceConnectivityResourcesConfig"
          android:isStatic="true"
          android:priority="1"/>
  </manifest>
  
  • config_thread.xml :
  <string translatable="false" name="config_thread_vendor_name">Banana Inc.</string>
  <string translatable="false" name="config_thread_vendor_oui">AC:DE:48</string>
  <string translatable="false" name="config_thread_model_name">Orange</string>
  

مشابه HAL APEX، باید اپلیکیشن همپوشانی را به فایل device.mk خود اضافه کنید:

PRODUCT_PACKAGES += \
    ConnectivityOverlayOrange</code>

اگر همه چیز کار کند، خواهید دید که ot-daemon نام فروشنده و مدل را در همان ابتدای گزارش ثبت می کند:

adb logcat -s ot-daemon
07-22 15:31:37.693  1472  1472 I ot-daemon: [I] P-Daemon------: Session socket is ready
07-22 15:31:37.693  1472  1472 I ot-daemon: [I] Cli-----------: Input: state
07-22 15:31:37.693  1472  1472 I ot-daemon: [I] Cli-----------: Output: disabled
07-22 15:31:37.693  1472  1472 I ot-daemon: [I] Cli-----------: Output: Done
07-22 15:31:37.693  1472  1472 W ot-daemon: [W] P-Daemon------: Daemon read: Connection reset by peer
07-22 15:31:50.091  1472  1472 I ot-daemon: [I] P-Daemon------: Session socket is ready
07-22 15:31:50.091  1472  1472 I ot-daemon: [I] Cli-----------: Input: factoryreset
07-22 15:31:50.092  1472  1472 I ot-daemon: [I] Settings------: Wiped all info
07-22 15:31:50.092  1472  1472 I ot-daemon: [INFO]-ADPROXY-: Stopped
07-22 15:31:50.092  1472  1472 I ot-daemon: [INFO]-DPROXY--: Stopped
07-22 15:31:50.092  1472  1472 I ot-daemon: [INFO]-BA------: Stop Thread Border Agent
07-22 15:31:50.092  1472  1472 I ot-daemon: [INFO]-BA------: Unpublish meshcop service Banana Inc. Orange #4833._meshcop._udp.local
07-22 15:31:50.092  1472  1472 I ot-daemon: [INFO]-MDNS----: Removing service Banana Inc. Orange #4833._meshcop._udp
07-22 15:31:50.092  1472  1472 I ot-daemon: [INFO]-MDNS----: Unpublishing service Banana Inc. Orange #4833._meshcop._udp listener ID = 0

با Google Home سازگار باشد

علاوه بر این، اگر می‌خواهید مسیریاب مرزی خود را توسط اکوسیستم Google Home استفاده کنید، می‌توانید این پیکربندی را در config_thread.xml مشخص کنید:

<string-array name="config_thread_mdns_vendor_specific_txts">
  <item>vgh=1</item>
</string-array>

تست کردن

اکنون دستگاه شما باید با مشخصات Thread 1.3+ Border Router سازگار باشد. قبل از ارسال آن به برنامه صدور گواهینامه Thread، برای اطمینان از سازگاری، باید چند تست Android xTS انجام دهید.

  • تست VTS مطمئن می شود که سرویس Thread HAL همانطور که انتظار می رود در دستگاه شما کار می کند. می توانید تست ها را با دستور اجرا کنید

    atest VtsHalThreadNetworkTargetTest

  • آزمایش CTS اطمینان حاصل می کند که API های Thread همانطور که انتظار می رود در دستگاه شما کار می کنند. می توانید تست ها را با دستور اجرا کنید

    atest CtsThreadNetworkTestCases

  • تست یکپارچه سازی تضمین کیفیت بیشتری از نحوه عملکرد کد خط اصلی Thread در دستگاه شما ارائه می دهد. می توانید تست ها را با دستور اجرا کنید

    atest ThreadNetworkIntegrationTests

همچنین می‌توانید دستورالعمل‌های بیشتری درباره نحوه اجرای تست‌های VTS/CTS/MTS با مجموعه‌های آزمایشی منتشر شده پیدا کنید:

با برنامه آزمایشی Thread تست کنید

مشابه دستگاه Cuttlefish، می توانید برنامه آزمایشی Thread را به تصویر سیستم خود اضافه کنید:

# ThreadNetworkDemoApp for testing
PRODUCT_PACKAGES_DEBUG += ThreadNetworkDemoApp

توجه داشته باشید که باید آن را فقط به نوع اشکال‌زدایی/انگلیسی اضافه کنید (به عنوان مثال PRODUCT_PACKAGES_DEBUG ) زیرا قرار نیست این مورد در ساخت کاربر برای مصرف‌کنندگان نهایی گنجانده شود.