Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> ระบบ >> Android

เพิ่มความน่าเชื่อถือของ Bluetooth Android:เคล็ดลับที่ได้รับการพิสูจน์แล้วสำหรับการเชื่อมต่อที่สอดคล้องกัน

เพิ่มความน่าเชื่อถือของ Bluetooth Android:เคล็ดลับที่ได้รับการพิสูจน์แล้วสำหรับการเชื่อมต่อที่สอดคล้องกัน

คุณอาจเคยเกิดเหตุการณ์เช่นนี้มาก่อน:หูฟังไร้สายของคุณเชื่อมต่อได้อย่างสมบูรณ์ในวันหนึ่ง และวันต่อมาก็ทำเหมือนกับว่าไม่เคยเจอโทรศัพท์ของคุณเลย หรือสมาร์ทวอทช์ของคุณหล่นลงระหว่างการวิ่ง บลูทูธใช้งานได้อย่างน่าทึ่ง แต่จะน่าหงุดหงิดเมื่อไม่ได้ใช้งาน

ฉันทำงานเป็นวิศวกรซอฟต์แวร์บลูทูธบนอุปกรณ์สวมใส่ได้ เช่น แว่นตาอัจฉริยะ และฉันใช้เวลามากกว่าที่จะยอมรับว่าทำไมสิ่งเหล่านี้ถึงพัง

ในบทความนี้ ฉันจะให้คุณดูเบื้องหลัง:วิธีการทำงานของ Bluetooth Stack ของ Android จริงๆ เหตุใดบางครั้งจึงคาดเดาไม่ได้ และสิ่งที่คุณสามารถทำได้ในฐานะนักพัฒนาซอฟต์แวร์เพื่อทำให้แอปหรือระบบของคุณเชื่อถือได้มากขึ้น

บลูทูธเป็นภาษาอังกฤษธรรมดา

โดยแก่นแท้แล้ว บลูทูธเป็นเพียงการสนทนาระหว่างอุปกรณ์สองเครื่อง แต่นี่ไม่ใช่การสื่อสารง่ายๆ เพียงสายเดียว เพราะมีหลายชั้นซ้อนกัน

  • วิทยุ (คอนโทรลเลอร์): ส่งและรับสัญญาณจริงผ่านตัวกลางอากาศ

  • สมองของซอฟต์แวร์ (Host Stack): ตัดสินใจว่าจะพูดคุยกับใครและอย่างไร รวมถึงต้องการหรือไม่

  • โปรไฟล์: กำหนดวัตถุประสงค์ของการสนทนา เช่น การสตรีมเพลงหรือการซิงค์ข้อมูลด้านสุขภาพ

  • โปรโตคอล: กำหนดวิธีการพูดคุยกับอุปกรณ์อื่น

บลูทูธมี "รสชาติ" ใหญ่ๆ สองประการ:

  • คลาสสิก (BR/EDR): ใช้สำหรับสิ่งต่างๆ เช่น หูฟังและชุดอุปกรณ์ติดรถยนต์ สามารถยกน้ำหนักได้มากขึ้น

  • พลังงานต่ำ (LE): ใช้สำหรับวงฟิตเนส บีคอน และอุปกรณ์สวมใส่ส่วนใหญ่ สามารถคงอยู่ได้นานขึ้น

อุปกรณ์สมัยใหม่ส่วนใหญ่ใช้ทั้งสองอย่างพร้อมกัน นั่นทรงพลังมาก แต่ยังเปิดประตูให้มีสิ่งผิดพลาดอีกมากมาย

เหตุใด Android จึงเพิ่มนิสัยแปลกๆ ของตัวเอง

เพิ่มความน่าเชื่อถือของ Bluetooth Android:เคล็ดลับที่ได้รับการพิสูจน์แล้วสำหรับการเชื่อมต่อที่สอดคล้องกัน

บน Android บลูทูธไม่ได้เป็นเพียงแพ็คเกจเดียวเท่านั้น มันเป็นห่วงโซ่ของชิ้นส่วนที่เคลื่อนไหว:

  • แอปของคุณเรียก 09 .

  • สิ่งเหล่านี้จะเข้าสู่บริการของระบบ เช่น 12 .

  • จากนั้นเป็นโค้ดเนทิฟผ่าน JNI (อินเทอร์เฟซดั้งเดิมของ Java)

  • จากนั้นไปที่สแต็ก Bluetooth ของผู้จำหน่ายชิป .

  • ในที่สุดก็กระทบกับฮาร์ดแวร์วิทยุ .

ผู้ผลิตโทรศัพท์ทุกรายจัดส่งชิป Bluetooth และเฟิร์มแวร์ที่แตกต่างกันเล็กน้อย นั่นหมายความว่าแอปบลูทูธเดียวกันนี้อาจทำงานแตกต่างออกไปใน Samsung, Pixel หรือโทรศัพท์ราคาประหยัดอื่นๆ ที่ใช้ Android

ปัญหาที่แท้จริงเบื้องหลัง “มันเพิ่งตัดการเชื่อมต่อ”

ต่อไปนี้เป็นอาการปวดหัวทั่วไปบางส่วนที่ฉันเห็น อธิบายง่ายๆ:

ปัญหาความผูกพัน (ปัญหา "กุญแจหาย")

เมื่ออุปกรณ์ Bluetooth สองเครื่องจับคู่กัน อุปกรณ์จะแลกเปลี่ยนคีย์การเข้ารหัส (คีย์ลิงก์สำหรับ Classic, Long Term Keys สำหรับ LE) และจัดเก็บไว้ในหน่วยความจำแบบไม่ลบเลือน ปุ่มเหล่านี้คือสิ่งที่ทำให้อุปกรณ์จดจำกันได้ในภายหลังและเชื่อมต่อใหม่อย่างปลอดภัยโดยไม่ต้องถามผู้ใช้อีก

ปัญหา "หน่วยความจำไม่ตรงกัน" เกิดขึ้นเมื่อคีย์ที่จัดเก็บไว้ในอุปกรณ์เครื่องหนึ่งไม่ตรงกับอีกเครื่องอีกต่อไป สาเหตุนี้อาจเกิดจาก:

  • การอัปเดตเฟิร์มแวร์หรืออัปเกรดระบบปฏิบัติการที่จะล้างข้อมูลหรือสร้างคีย์ใหม่

  • การรีเซ็ตเป็นค่าเริ่มต้นจากโรงงานหรือ "ลืมอุปกรณ์" ที่ด้านหนึ่ง แต่ไม่ใช่อีกด้านหนึ่ง

  • คีย์เสียหายหรือถูกไล่ออกโดยระบบเพื่อเพิ่มพื้นที่จัดเก็บข้อมูล

จากมุมมองของผู้ใช้ อุปกรณ์อาจยังคงดูอยู่ จับคู่แล้ว (แสดงในเมนู Bluetooth) แต่การเชื่อมต่อล้มเหลวอย่างลึกลับโดยมีข้อผิดพลาดเช่น "การรับรองความถูกต้องล้มเหลว" หรือ "การเข้ารหัสไม่เพียงพอ" วิธีเดียวที่จะแก้ได้คือลบอุปกรณ์ทั้งสองด้านแล้วจับคู่ใหม่ ซึ่งถือว่าไร้สาระสำหรับผู้ใช้ที่ไม่เชี่ยวชาญด้านเทคนิค

เวลาไม่ตรงกัน

อุปกรณ์บลูทูธไม่เพียงแค่แชททุกเมื่อที่ต้องการ แต่ยังเห็นด้วยกับช่วงเวลาการเชื่อมต่อ ซึ่งเป็นกำหนดเวลาที่แต่ละฝ่ายจะ "ตื่น" และแลกเปลี่ยนแพ็กเก็ต ลองนึกถึงการที่คนสองคนตกลงที่จะพบกันทุกๆ 30 นาทีที่ร้านกาแฟ

ไม่ตรงกันเกิดขึ้นเมื่อ:

  • ทั้งสองฝ่ายเจรจาในช่วงเวลาที่แตกต่างกันแต่ไม่ได้ตกลงกันทั้งหมด (เช่น ฝ่ายหนึ่งคิดว่าเป็น 30 มิลลิวินาที อีกฝ่ายหนึ่งคิดว่า 50 มิลลิวินาที)

  • การอัปเดตเฟิร์มแวร์หรือการเปลี่ยนแปลงการกำหนดค่าของฝ่ายหนึ่งจะเปลี่ยนแปลงนโยบายกำหนดเวลา

  • สภาวะทางวิทยุทำให้ฝ่ายหนึ่งพลาดการเช็คอินตามกำหนดเวลาหลายรายการ ทำให้นาฬิกาห่างกัน

  • ตรรกะการประหยัดพลังงาน (เช่น โทรศัพท์เข้าสู่โหมด Doze) จะขยายช่วงเวลาออกไปอย่างเงียบๆ

สิ่งนี้อธิบายว่าทำไมการเชื่อมต่ออาจทำงานได้ดีในตอนแรกแต่เริ่มล้มเหลวในภายหลัง:อุปกรณ์เริ่มซิงค์ตามช่วงเวลา แต่นโยบายหรือพฤติกรรมของฝ่ายหนึ่งเปลี่ยนไป จากมุมมองของผู้ใช้ ดูเหมือนว่าเสียงติดขัด อินพุตล่าช้า (บนตัวควบคุมเกม) หรือการตัดการเชื่อมต่อแบบสุ่มหลังจาก “ก่อนหน้านี้ทำงานได้ดี”

การตัดการเชื่อมต่อที่ไม่คาดคิด

เมื่อการเชื่อมต่อ Bluetooth สิ้นสุดลง เลเยอร์วิทยุ (ตัวควบคุม) และสแต็ก OS ระดับที่สูงกว่า (โฮสต์) ควรจะแลกเปลี่ยนสัญญาณที่ชัดเจน ตัวควบคุมส่งเหตุการณ์ HCI Disconnection Complete (โดยพื้นฐานแล้ว:“ลาก่อน เสร็จแล้ว” ). จากนั้นโฮสต์ควรอัปเดตสถานะภายใน ล้างเซสชัน GATT/ACL และเตรียมพร้อมสำหรับการเชื่อมต่อใหม่

แต่ในทางปฏิบัติ สิ่งนี้ไม่ได้เข้ากันเสมอไป:

  • บางครั้งตัวควบคุมบอกลาอย่างชัดเจน แต่สแต็กโฮสต์ไม่อัปเดตสถานะอย่างถูกต้อง แอปยังคง "คิดว่า" การเชื่อมต่อทำงานอยู่ ดังนั้นความพยายามในการเชื่อมต่อใหม่จึงล้มเหลวโดยไม่แจ้งให้ทราบ

  • บางแพลตฟอร์มแคชสถานะการเชื่อมต่ออย่างรุนแรง (โดยเฉพาะ iOS) หากระบบปฏิบัติการเชื่อว่าการเชื่อมต่อยังคงใช้งานได้ ระบบจะไม่พยายามเชื่อมต่อใหม่จนกว่าคุณจะสลับบลูทูธหรือรีบูต

  • สภาวะการแข่งขันอาจเกิดขึ้นได้หากเหตุการณ์การตัดการเชื่อมต่อเกิดขึ้นในขณะที่การดำเนินการอื่น (เช่น การค้นหาบริการ การเชื่อมต่อ หรือการตั้งค่าการเข้ารหัส) อยู่ระหว่างดำเนินการ ระบบปฏิบัติการอาจสับสนว่าอุปกรณ์แท้จริงอยู่ในสถานะใด ใน.

  • ในอุปกรณ์บางชนิด ความพยายามในการเชื่อมต่อใหม่อย่างรวดเร็วหลังจากการตัดการเชื่อมต่อที่เรียบร้อยขัดแย้งกับตัวจับเวลาคูลดาวน์ภายใน ตัวควบคุมเพิกเฉยต่อแอปดังกล่าว โดยปล่อยให้แอปรออยู่

จากมุมมองของผู้ใช้ อุปกรณ์ดูเหมือน "ติดอยู่" วิธีเดียวที่จะกู้คืนได้คือการสลับบลูทูธ รีสตาร์ทแอป หรือเปิดปิดอุปกรณ์เสริม แม้ว่าในทางเทคนิคแล้วไม่มีอะไร "ล้มเหลว"

นักพัฒนาซอฟต์แวร์สามารถปรับปรุงให้ดีขึ้นได้อย่างไร

หากคุณกำลังสร้างแอปบลูทูธ นิสัยบางส่วนที่ช่วยบรรเทาความเจ็บปวดได้มากมีดังนี้:

ตรวจสอบอุปกรณ์ที่ถูกผูกมัดก่อน

สาเหตุที่พบบ่อยที่สุดประการหนึ่งของการเชื่อมต่อล้มเหลวคือข้อมูลการเชื่อมต่อที่ไม่ตรงกัน:โทรศัพท์และอุปกรณ์เสริมไม่ได้ใช้คีย์เข้ารหัสเดียวกันอีกต่อไป แม้ว่าอุปกรณ์จะปรากฏใน UI แต่ระบบปฏิบัติการก็อาจสูญเสียคีย์ไปแล้ว

ก่อนที่จะพยายามเชื่อมต่อ ให้ค้นหารายการอุปกรณ์ที่เชื่อมโยงของระบบด้วย 24 เสมอ . ตัวอย่างเช่น:

if (adapter.getBondedDevices().contains(targetDevice)) {
 targetDevice.connectGatt(context, false, gattCallback);
} else {
 showToast("Please re-pair this device to restore the connection.");
}

สิ่งนี้ทำให้แน่ใจได้ว่าคุณจะพยายามเชื่อมต่ออย่างปลอดภัยกับอุปกรณ์ที่ระบบปฏิบัติการยังคงเชื่อถือเท่านั้น หากอุปกรณ์เป้าหมายไม่อยู่ในรายการเชื่อมโยง คุณสามารถให้คำแนะนำที่ชัดเจนแก่ผู้ใช้ (“โปรดจับคู่อุปกรณ์นี้ใหม่”) แทนที่จะปล่อยให้ผู้ใช้มีข้อผิดพลาดในการเชื่อมต่อที่ทำให้สับสน

จัดการการโทรกลับอย่างระมัดระวัง

ข้อผิดพลาดเล็กๆ น้อยๆ อีกประการหนึ่งคือการสมมติว่า 30 เหตุการณ์หมายถึงการเชื่อมต่อสำเร็จ ในความเป็นจริง 40 สามารถรายงานสถานะที่เชื่อมต่อได้แม้ว่าการดำเนินการพื้นฐานจะล้มเหลว แต่ผลลัพธ์ที่แท้จริงจะอยู่ใน 58 อาร์กิวเมนต์ เพื่อหลีกเลี่ยงการไล่ตามการเชื่อมต่อ Phantom ให้ตรวจสอบทั้ง 65 เสมอ และ 70 :

if (status == BluetoothGatt.GATT_SUCCESS &&
 newState == BluetoothProfile.STATE_CONNECTED) {
 gatt.discoverServices();
} else {
 gatt.close();
}

รูปแบบนี้ป้องกันไม่ให้คุณพยายามค้นหาบริการบนการเชื่อมต่อที่ไม่ทำงาน และช่วยให้แน่ใจว่าเซสชันเก่าจะถูกปิดทันที ปล่อยให้สแต็กพร้อมสำหรับการลองใหม่ทั้งหมด

คาดหวังความล้มเหลว

การเชื่อมต่อ Bluetooth จะล้มเหลวตลอดเวลาในโลกแห่งความเป็นจริง - อุปกรณ์อยู่นอกระยะ สัญญาณรบกวนที่เพิ่มขึ้นอย่างรวดเร็วในย่านความถี่ 2.4 GHz หรือวิทยุไม่ว่าง สิ่งที่แย่ที่สุดที่แอปสามารถทำได้คือลองใหม่ทันทีในวงที่แน่นหนา ซึ่งจะทำให้แบตเตอรี่หมดและทำให้สแตกไม่เสถียร

แนวทางที่ดีกว่าคือการใช้การถอยกลับแบบเอ็กซ์โปเนนเชียลดังนี้:

long delay = (long) Math.min(250 * Math.pow(2, attempt), 30000);
new Handler(Looper.getMainLooper()).postDelayed(connectAction, delay);

ซึ่งหมายความว่าการลองใหม่ครั้งแรกของคุณเกิดขึ้นอย่างรวดเร็ว (~250 ms) แต่การลองใหม่ครั้งต่อไปช้าลง (500 ms, 1 วินาที, 2 วินาที…) ต่อยอดที่สูงสุดที่สมเหตุสมผล Backoff ทำให้แอปของคุณมีความยืดหยุ่นโดยไม่ต้องมีคลื่นวิทยุหรือระบบปฏิบัติการมากเกินไป

ใช้เครื่องมือที่เหมาะสม

หากไม่สามารถมองเห็นสิ่งที่เกิดขึ้นภายใต้ประทุน ปัญหาการเชื่อมต่อจะดูแบบสุ่ม เครื่องมืออย่าง nRF Connect ช่วยให้คุณสามารถสแกน เชื่อมต่อ และเรียกใช้การดำเนินการ GATT กับอุปกรณ์ของคุณได้อย่างโต้ตอบ ในขณะที่บันทึกการสอดแนม Bluetooth HCI ของ Android จะเผยให้เห็นแพ็กเก็ตจริงที่มีการแลกเปลี่ยน ตัวอย่างเช่น:

Settings.Secure.putInt(context.getContentResolver(), "bluetooth_hci_log", 1);

เมื่อเปิดใช้งานแล้ว คุณจะบันทึกการติดตาม Logcat และยืนยันว่าความล้มเหลวเกิดจากคีย์ที่หายไปหรือไม่ (85 ) เวลาไม่ตรงกัน หรือการรบกวน การใช้เครื่องมือเหล่านี้ไม่เพียงช่วยให้คุณแก้ไขจุดบกพร่องของแอปเท่านั้น แต่ยังพิสูจน์ได้ว่าปัญหาอยู่ที่โค้ด ระบบปฏิบัติการ หรือเฟิร์มแวร์เสริมของคุณ

เพิ่มความน่าเชื่อถือของ Bluetooth Android:เคล็ดลับที่ได้รับการพิสูจน์แล้วสำหรับการเชื่อมต่อที่สอดคล้องกัน

บทเรียนที่ยิ่งใหญ่

การทำงานกับ Bluetooth ทำให้ฉันได้เรียนรู้บทเรียนที่เกี่ยวข้องกับวิศวกรรมโดยทั่วไป:

  • ระบบไร้สายไม่เคยสมบูรณ์แบบ ดังนั้นจงสร้างโดยคำนึงถึงการฟื้นฟูอยู่เสมอ

  • บันทึกและเมตริกไม่ใช่ทางเลือก พวกมันคือแผนที่ของคุณท่ามกลางความสับสนวุ่นวาย

  • วิธีแก้ปัญหาที่ง่ายที่สุดมักจะอยู่รอดได้ดีที่สุดในโลกที่วุ่นวาย

บทสรุป

บลูทูธยุ่งเหยิงเพราะเป็นสายโซ่ของฮาร์ดแวร์ เฟิร์มแวร์ และซอฟต์แวร์ที่พยายามร่วมมือกัน บน Android ชิปและผู้จำหน่ายที่หลากหลายทำให้มีความซับซ้อนมากขึ้น

แต่นั่นไม่ได้หมายความว่าคุณทำอะไรไม่ถูก ด้วยการทำความเข้าใจวิธีการทำงานของเลเยอร์และออกแบบแอปของคุณด้วยการลองใหม่ การตรวจสอบ และการบันทึกที่เหมาะสม คุณสามารถทำให้ Bluetooth รู้สึก "แปลก" น้อยลงสำหรับผู้ใช้ของคุณ

ครั้งต่อไปที่หูฟังเอียร์บัดของคุณทำงานผิดปกติ คุณจะรู้ว่าไม่ใช่คุณ บลูทูธเป็นเพียงบลูทูธ

นี่เป็นบทความแรกจากบทความจำนวนหนึ่งที่ฉันจะเขียนเกี่ยวกับการพัฒนา Bluetooth ในตอนถัดไป เราจะเจาะลึกลงไปถึงวิธีสร้างไคลเอ็นต์และเซิร์ฟเวอร์ Bluetooth Low Energy (BLE) GATT ที่ปลอดภัยบน Android คอยติดตาม!

เรียนรู้การเขียนโค้ดฟรี หลักสูตรโอเพ่นซอร์สของ freeCodeCamp ช่วยให้ผู้คนมากกว่า 40,000 คนได้งานในตำแหน่งนักพัฒนา เริ่มต้น