Google is committed to advancing racial equity for Black communities. See how.
Trang này được dịch bởi Cloud Translation API.
Switch to English

Gỡ lỗi âm thanh

Bài viết này mô tả một số mẹo và thủ thuật để gỡ lỗi âm thanh Android.

Tee Sink

"Tách chìm" là một tính năng gỡ lỗi AudioFlinger, chỉ có sẵn trong các bản dựng tùy chỉnh, để giữ lại một đoạn ngắn của âm thanh gần đây để phân tích sau này. Điều này cho phép so sánh giữa những gì đã thực sự được phát hoặc ghi lại với những gì được mong đợi.

Để bảo mật, theo mặc định, bồn rửa tee bị tắt ở cả thời gian biên dịch và thời gian chạy. Để sử dụng bồn rửa tee, bạn sẽ cần phải kích hoạt nó bằng cách biên dịch lại và cũng bằng cách thiết lập một thuộc tính. Đảm bảo tắt tính năng này sau khi bạn gỡ lỗi xong; không nên bật bồn rửa tee trong các phiên bản sản xuất.

Hướng dẫn trong phần này dành cho Android 7.x trở lên. Đối với Android 5.x và 6.x, thay thế /data/misc/audioserver bằng /data/misc/media . Ngoài ra, bạn phải sử dụng một bản dựng userdebug hoặc eng. Nếu bạn sử dụng bản dựng userdebug, hãy tắt tính năng xác thực bằng:

adb root && adb disable-verity && adb reboot

Thiết lập thời gian biên dịch

  1. cd frameworks/av/services/audioflinger
  2. Chỉnh sửa Configuration.h
  3. Uncomment #define TEE_SINK .
  4. Xây dựng lại libaudioflinger.so .
  5. adb root
  6. adb remount
  7. Đẩy hoặc đồng bộ libaudioflinger.so mới với /system/lib của thiết bị.

Thiết lập thời gian chạy

  1. adb shell getprop | grep ro.debuggable
    Xác nhận rằng đầu ra là: [ro.debuggable]: [1]
  2. adb shell
  3. ls -ld /data/misc/audioserver

    Xác nhận rằng đầu ra là:

    drwx------ media media ... media
    

    Nếu thư mục không tồn tại, hãy tạo nó như sau:

    mkdir /data/misc/audioserver
    chown media:media /data/misc/audioserver
    
  4. echo af.tee=# > /data/local.prop
    Trong đó giá trị af.tee là một số được mô tả bên dưới.
  5. chmod 644 /data/local.prop
  6. reboot

Giá trị cho tài sản af.tee

Giá trị của af.tee là một số từ 0 đến 7, thể hiện tổng của một số bit, mỗi bit cho mỗi đối tượng. Xem mã tại AudioFlinger::AudioFlinger() trong AudioFlinger.cpp để biết giải thích về từng bit, nhưng ngắn gọn:

  • 1 = đầu vào
  • 2 = Đầu ra FastMixer
  • 4 = AudioRecord và AudioTrack cho mỗi bản nhạc

Chưa có bit cho bộ đệm sâu hoặc bộ trộn thông thường, nhưng bạn có thể nhận được kết quả tương tự bằng cách sử dụng "4."

Kiểm tra và thu thập dữ liệu

  1. Chạy kiểm tra âm thanh của bạn.
  2. adb shell dumpsys media.audio_flinger
  3. Tìm một dòng trong dumpsys xuất dumpsys như sau:
    tee copied to /data/misc/audioserver/20131010101147_2.wav
    Đây là tệp .wav PCM.
  4. Sau đó, adb pull bất kỳ tệp /data/misc/audioserver/*.wav nào quan tâm; lưu ý rằng tên tập tin bãi theo dõi cụ thể không xuất hiện trong dumpsys đầu ra, nhưng vẫn lưu vào /data/misc/audioserver khi theo dõi việc đóng cửa.
  5. Xem lại các tệp kết xuất để biết các mối quan tâm về quyền riêng tư trước khi chia sẻ với người khác.

Gợi ý

Hãy thử những ý tưởng sau để có thêm kết quả hữu ích:

  • Tắt âm thanh chạm và tiếng bấm phím để giảm gián đoạn trong đầu ra thử nghiệm.
  • Tối đa hóa tất cả các khối lượng.
  • Tắt các ứng dụng tạo âm thanh hoặc ghi âm từ micrô, nếu chúng không quan tâm đến thử nghiệm của bạn.
  • Bãi chứa dành riêng cho tuyến đường chỉ được lưu khi tuyến đường được đóng lại; bạn có thể cần buộc đóng một ứng dụng để kết xuất dữ liệu theo dõi cụ thể của nó
  • dumpsys ngay sau khi kiểm tra; có một số lượng hạn chế của không gian ghi âm có sẵn.
  • Để đảm bảo bạn không mất các tệp kết xuất, hãy tải chúng lên máy chủ lưu trữ của bạn theo định kỳ. Chỉ một số tệp kết xuất hạn chế được lưu giữ; bãi chứa cũ hơn sẽ bị loại bỏ sau khi đạt đến giới hạn đó.

Khôi phục

Như đã lưu ý ở trên, không nên bật tính năng bồn rửa bóng. Khôi phục bản dựng và thiết bị của bạn như sau:

  1. Hoàn nguyên các thay đổi mã nguồn thành Configuration.h
  2. Xây dựng lại libaudioflinger.so .
  3. Đẩy hoặc đồng bộ libaudioflinger.so khôi phục vào /system/lib của thiết bị.
  4. adb shell
  5. rm /data/local.prop
  6. rm /data/misc/audioserver/*.wav
  7. reboot

media.log

Macro ALOGx

API ghi nhật ký ngôn ngữ Java tiêu chuẩn trong Android SDK là android.util.Log .

API ngôn ngữ C tương ứng trong Android NDK là __android_log_print khai báo trong <android/log.h> .

Trong phần gốc của khuôn khổ Android, chúng tôi thích các macro có tên ALOGE , ALOGW , ALOGI , ALOGV , v.v. Chúng được khai báo trong <utils/Log.h> và cho mục đích của bài viết này, chúng tôi sẽ gọi chung chúng là ALOGx .

Tất cả các API này đều dễ sử dụng và dễ hiểu, vì vậy chúng có sức lan tỏa rộng khắp nền tảng Android. Đặc biệt là mediaserver quá trình, trong đó bao gồm các máy chủ âm thanh AudioFlinger, sử dụng ALOGx rộng rãi.

Tuy nhiên, có một số hạn chế đối với ALOGx và bạn bè:

  • Họ dễ bị "spam nhật ký": bộ đệm nhật ký là tài nguyên dùng chung nên có thể dễ dàng bị tràn do các mục nhật ký không liên quan, dẫn đến bỏ sót thông tin. Biến thể ALOGV bị tắt tại thời điểm biên dịch theo mặc định. Nhưng tất nhiên, thậm chí nó có thể dẫn đến spam nhật ký nếu nó được bật.
  • Các lệnh gọi của hệ thống hạt nhân cơ bản có thể bị chặn, có thể dẫn đến đảo ngược ưu tiên và do đó, các phép đo rối loạn và không chính xác. Đây là mối quan tâm đặc biệt đối với các luồng quan trọng về thời gian như FastMixerFastCapture .
  • Nếu một nhật ký cụ thể bị vô hiệu hóa để giảm spam nhật ký, thì bất kỳ thông tin nào đã được nhật ký đó ghi lại sẽ bị mất. Không thể kích hoạt một nhật ký cụ thể trở về trước, sau khi rõ ràng rằng nhật ký sẽ rất thú vị.

NBLOG, media.log và MediaLogService

Các API NBLOG và quy trình media.log liên quan và dịch vụ MediaLogService cùng nhau tạo thành một hệ thống ghi nhật ký mới hơn cho phương tiện và được thiết kế đặc biệt để giải quyết các vấn đề ở trên. Chúng tôi sẽ sử dụng một cách lỏng lẻo thuật ngữ "media.log" để chỉ cả ba, nhưng nói một cách chính NBLOG thì NBLOG là API ghi nhật ký C ++, media.log là tên quy trình Linux và MediaLogService là một dịch vụ liên kết Android để kiểm tra nhật ký.

"Dòng thời gian" media.log là một loạt các mục nhập nhật ký có thứ tự tương đối được giữ nguyên. Theo quy ước, mỗi luồng nên sử dụng dòng thời gian của riêng nó.

Những lợi ích

Lợi ích của hệ thống media.log là nó:

  • Không spam nhật ký chính trừ khi và cho đến khi nó cần thiết.
  • Có thể được kiểm tra ngay cả khi mediaserver bị treo hoặc bị treo.
  • Không chặn theo dòng thời gian.
  • Cung cấp ít xáo trộn hơn cho hiệu suất. (Tất nhiên không có hình thức ghi nhật ký nào là hoàn toàn không xâm phạm.)

Ngành kiến ​​trúc

Sơ đồ dưới đây cho thấy mối quan hệ của mediaserver quá trình và init quá trình, trước khi media.log được giới thiệu:

Kiến trúc trước media.log

Hình 1. Kiến trúc trước media.log

Điểm đáng chú ý:

  • init dĩa và giám đốc điều hành mediaserver .
  • init phát hiện cái chết của mediaserver , và tái dĩa khi cần thiết.
  • ALOGxALOGx không được hiển thị.

Sơ đồ dưới đây cho thấy mối quan hệ mới của các thành phần, sau khi media.log được thêm vào kiến ​​trúc:

Kiến trúc sau media.log

Hình 2. Kiến trúc sau media.log

Những thay đổi quan trọng:

  • Khách hàng sử dụng NBLOG API để tạo các mục nhập nhật ký và nối chúng vào một bộ đệm tròn trong bộ nhớ dùng chung.
  • MediaLogService có thể kết xuất nội dung của bộ đệm tròn bất kỳ lúc nào.
  • Bộ đệm tròn được thiết kế theo cách sao cho bất kỳ lỗi nào của bộ nhớ dùng chung sẽ không làm hỏng MediaLogService và nó vẫn có thể kết xuất nhiều bộ đệm không bị ảnh hưởng bởi lỗi đó.
  • Bộ đệm tròn không chặn và không khóa cho cả việc viết các mục nhập mới và đọc các mục nhập hiện có.
  • Không có lệnh gọi hệ thống hạt nhân nào được yêu cầu để ghi vào hoặc đọc từ bộ đệm tròn (ngoại trừ dấu thời gian tùy chọn).

Sử dụng ở đâu

Kể từ Android 4.4, chỉ có một số điểm nhật ký trong AudioFlinger sử dụng hệ thống media.log . Mặc dù các API mới không dễ sử dụng như ALOGx , nhưng chúng cũng không quá khó. Chúng tôi khuyến khích bạn tìm hiểu hệ thống ghi nhật ký mới cho những trường hợp không thể thiếu nó. Đặc biệt, nó được khuyến nghị cho các luồng AudioFlinger phải chạy thường xuyên, định kỳ và không bị chặn như các FastMixerFastCapture .

Cách sử dụng

Thêm nhật ký

Đầu tiên, bạn cần thêm nhật ký vào mã của mình.

Trong FastMixerFastCapture , hãy sử dụng mã như sau:

logWriter->log("string");
logWriter->logf("format", parameters);
logWriter->logTimestamp();

Vì dòng thời gian NBLog này chỉ được sử dụng bởi các FastMixerFastCapture , nên không cần loại trừ lẫn nhau.

Trong các chuỗi AudioFlinger khác, hãy sử dụng mNBLogWriter :

mNBLogWriter->log("string");
mNBLogWriter->logf("format", parameters);
mNBLogWriter->logTimestamp();

Đối với các luồng không phải FastMixerFastCapture , dòng thời gian NBLog của NBLog có thể được sử dụng bởi cả chính luồng đó và bằng các hoạt động kết dính. NBLog::Writer không cung cấp bất kỳ loại trừ lẫn nhau ngầm nào trên mỗi dòng thời gian, vì vậy hãy đảm bảo rằng tất cả nhật ký xảy ra trong ngữ cảnh nơi lưu trữ mutex mLock .

Sau khi bạn đã thêm nhật ký, hãy xây dựng lại AudioFlinger.

Thận trọng: Cần có dòng thời gian NBLog::Writer riêng cho mỗi luồng, để đảm bảo an toàn cho luồng, vì các mốc thời gian bỏ qua các mutexes theo thiết kế. Nếu bạn muốn nhiều luồng sử dụng cùng một dòng thời gian, bạn có thể bảo vệ bằng mutex hiện có (như đã mô tả ở trên cho mLock ). Hoặc bạn có thể sử dụng trình bao bọc NBLog::LockedWriter thay vì NBLog::Writer . Tuy nhiên, điều này phủ nhận lợi ích chính của API này: hành vi không chặn của nó.

API NBLog đầy đủ có tại frameworks/av/include/media/nbaio/NBLog.h .

Bật media.log

media.log bị tắt theo mặc định. Nó chỉ hoạt động khi thuộc tính ro.test_harness1 . Bạn có thể kích hoạt nó bằng cách:

adb root
adb shell
echo ro.test_harness=1 > /data/local.prop
chmod 644 /data/local.prop
reboot

Kết nối bị mất trong khi khởi động lại, vì vậy:

adb shell
Lệnh ps media bây giờ sẽ hiển thị hai quá trình:
  • media.log
  • người trung gian

Lưu ý quá trình ID của mediaserver cho sau này.

Hiển thị các mốc thời gian

Bạn có thể yêu cầu kết xuất nhật ký theo cách thủ công bất cứ lúc nào. Lệnh này hiển thị nhật ký từ tất cả các mốc thời gian hoạt động và gần đây, sau đó xóa chúng:

dumpsys media.log

Lưu ý rằng theo thiết kế các mốc thời gian là độc lập và không có cơ sở để hợp nhất các mốc thời gian.

Khôi phục nhật ký sau cái chết của máy chủ trung gian

Bây giờ hãy thử giết mediaserver quá trình: kill -9 # , trong đó # là quá trình ID bạn đã nói trước đó. Bạn sẽ thấy kết xuất từ media.log trong logcat chính, hiển thị tất cả các nhật ký dẫn đến sự cố.

dumpsys media.log