Rahasia API perangkat Android. Laporan Yandex

Salah satu tantangan utama pengembangan Android adalah fragmentasi. Hampir setiap produsen mengubah Android sesuai kebutuhan mereka. Pengembang Andrey Makeev mencantumkan perbedaan antara implementasi vendor dan Proyek Open Source Android asli. Dari laporan tersebut Anda dapat mempelajari cara memanfaatkan fitur individual firmware pada perangkat yang berbeda.


- Saya sudah pemrograman sejak sekolah, saya telah mengembangkannya untuk Android selama tiga tahun. Dari jumlah tersebut, saya menghabiskan satu tahun di Yandex, berpartisipasi dalam proyek-proyek seperti Launcher dan Telepon.



Saya ingin berbicara tentang bagaimana fragmentasi API perangkat Android terlihat - dari luar, dari sisi pengembang aplikasi, dan dari dalam, dari sudut pandang pengembang platform dan ponsel.

Laporan saya terdiri dari dua bagian. Pertama, mari kita bicara tentang bagaimana API terfragmentasi secara eksternal. Kemudian kita akan membaca kode - kita akan mencari tahu bagaimana fitur unik dari telepon abstrak direalisasikan, bagaimana pengembangan dibangun.

Fragmentasi API adalah salah satu parameter yang digunakan untuk memecah perangkat. Yang paling jelas dan paling sederhana adalah fragmentasi menurut SDK Android, kami temui setiap hari, secara harfiah sejak hari pertama pengembangan untuk Android. Kita tahu apa dan di mana versi API itu muncul, bahwa itu dihapus, bahwa itu didukung, tetapi masih tersedia, dan mana yang sudah hilang. Sebagai aturan, kami menggunakan berbagai pustaka dukungan dari Google untuk menyederhanakan kehidupan kami. Banyak yang telah dilakukan untuk kita.





Dalam kode kami, tampilannya kira-kira seperti ini: kami mengaktifkan beberapa fungsi, mematikan beberapa - tergantung pada versi SDK tempat kami saat ini. Jika Anda menggunakan, mereka biasanya melakukan hal yang sama, tetapi di dalam.

Kami tidak akan fokus pada jenis fragmentasi ini. Kontra ini diketahui semua orang - kami terpaksa menyimpan seluruh armada perangkat dengan versi yang berbeda untuk setidaknya menguji aplikasi kami. Selain itu, kami dipaksa untuk menulis kode tambahan. Ini sangat tidak nyaman ketika Anda baru saja mulai mengembangkan untuk Android dan tiba-tiba ternyata: Anda perlu mempelajari apa yang ada di sana dua atau tiga tahun yang lalu untuk mendukung beberapa perangkat lama. Aspek positif: API berkembang, teknologi bergerak maju, Android mendapatkan pengguna baru, menjadi lebih nyaman bagi pengembang dan pengguna.

Bagaimana kita bekerja dengan ini? Kami juga menggunakan perpustakaan dan sangat senang ketika kami menolak untuk mendukung versi yang lebih lama. Saya pikir dalam kehidupan setiap orang yang telah melakukan ini selama lebih dari setahun, ada momen seperti itu. Ini hanya kebahagiaan. Ini adalah opsi fragmentasi yang jelas dan sederhana. Selanjutnya adalah fragmentasi tipe Android. Ada beberapa di antaranya. Android TV berbicara untuk dirinya sendiri, Android Auto terutama ditujukan untuk radio mobil, Android Things - untuk IoT dan perangkat yang disematkan serupa. W adalah Wear OS, mantan Android Watch, menonton untuk Android. Kami akan mencoba mempertimbangkan bagaimana ini terlihat dari sisi pengembang. Dan yang paling menarik, mari kita coba mempertimbangkan bagaimana tampilannya dari dalam.



Ambil dua contoh dari developer.android.com. Yang pertama adalah Wear OS. Apa yang kita butuhkan untuk membuat aplikasi? Kami menambahkan dependensi compileOnly untuk build.gradle dan menulis dua baris tambahan di manifes: using-feature android.hardware.type.watch dan uses-library, yang sesuai dengan nama paket yang sama dengan perpustakaan yang kami sambungkan.



Bagaimana kita menerapkan sesuatu? Kami membuat Aktivitas, hanya dalam hal ini kami tidak mengeluarkan aktivitas standar yang biasa kami gunakan untuk bekerja, dan bahkan bukan aktivitas komposit, tetapi WearableActivity, dan memanggil metode khusus untuknya, dalam hal ini setAmbientEnabled (). Jadi, kami memiliki dependensi compileOnly, yaitu, ia tidak masuk ke program aplikasi kami. Penggunaan-perpustakaan, yang, tampaknya, memaksa OS untuk menghubungkan kelas-kelas ini dan kode ini kepada kami dalam runtime pada perangkat, dan kelas-kelas baru yang kami gunakan.



API Android Things praktis tidak berbeda. Kami tidak meresepkan penggunaan-fitur, hanya menggunakan-perpustakaan, compileOnly-dependensi.



Kami membuat aktivitas, dalam hal ini unik untuk Android Things API, kelas PeripheralManager. Kami sedang polling GPIO dan berusaha untuk berjanji.



Bagaimana perilaku aplikasi di ponsel Anda? Ada dua opsi.



Jika kami mengindikasikan bahwa menggunakan-library android: required = ”true”, maka kami tidak memenuhi persyaratan wajib PackageManager untuk menginstal aplikasi, dan pada dasarnya menolak untuk menginstalnya. Jika kami menentukan android: required = ”false”, maka aplikasi akan diinstal, tetapi ketika kami mencoba mengakses kelas PeripheralManager, kami mendapatkan NoClassDefFoundError, karena tidak ada kelas seperti itu di Android standar.

Apa kesimpulannya? Kami menghubungkan dependensi compileOnly hanya untuk dapat menghubunginya selama perakitan, dan kelas yang kami gunakan menunggu kami di perangkat, mereka terhubung menggunakan garis-garis tertentu dalam manifes. Terkadang kami meresepkan fitur yang lebih sering diperlukan untuk membedakan di Google Play perangkat yang aplikasi ini dapat atau tidak dapat didistribusikan.

Saya tidak dapat memilih sisi negatif dari jenis fragmentasi ini. Hanya mereka yang berkembang yang akan menceritakan banyak kisah tentang bagaimana mereka bertemu serangga asing yang benar-benar tidak dapat dipahami yang tidak mereka temui di telepon. Sisi positifnya adalah ini adalah pasar tambahan, pengguna tambahan, pengalaman tambahan, selalu bagus.

Bagaimana cara mengatasinya? Tulis lebih banyak aplikasi. Rekomendasi umum adalah untuk menulis lebih dari satu versi aplikasi untuk semua jenis Android, tetapi masih melakukan yang berbeda. Seharusnya ada lebih sedikit untuk jam tangan, untuk Android Hal-hal praktis tidak ada apa pun yang tertulis di telepon yang cocok, dan sebagainya. Dan gunakan pustaka yang disediakan pengembang Android dan, terkadang, pengembang perangkat memberi kami.

Jenis fragmentasi yang paling sedikit dipelajari berikutnya adalah fragmentasi produsen. Setiap produsen, setelah menerima kode sumber - dalam kasus yang jarang terjadi adalah AOSP, lebih sering itu entah bagaimana dimodifikasi oleh pengembang perangkat keras - membuat perubahan padanya. Sebagai aturan, kita belajar tentang efek negatif dari jenis fragmentasi ini dari bukan saluran terbaik - dari ulasan negatif di Google Play, karena seseorang telah merusak sesuatu. Atau kita belajar ini dari analytics crash, ketika tiba-tiba sesuatu crash dengan cara yang tidak dapat dipahami, hanya pada beberapa perangkat tertentu. Dalam kasus terbaik, kita belajar ini dari QA kami, ketika ada sesuatu yang pecah selama pengujian mereka pada perangkat tertentu.



Tentang topik ini, saya punya kisah yang luar biasa dari Peluncur pengembangan kami. Kami mendapat laporan bug di mana aktivitasnya tidak mencapai layar penuh, dan wallpaper default favorit kami tidak ditampilkan sama sekali. Itu tidak diterjemahkan, sebuah jendela kosong menunjukkan. Kami bahkan tidak memiliki perangkat untuk memperbanyaknya. Dengan merentangkan ke layar, kami masih dapat menemukan perangkat low-end yang tidak berfungsi, dan cukup mudah memperbaiki semuanya menggunakan android: resizeableActivity = "true" dalam manifes. Dengan wallpaper, semuanya ternyata jauh lebih rumit. Sekitar dua hari kami mencoba menjangkau dan mendapatkan informasi lebih rinci. Pada akhirnya, mereka menemukan bahwa pada sejumlah perangkat baik codec untuk decoding jpeg progresif diimplementasikan dengan bug, ketika beberapa algoritma kompresi digunakan pada hasil masing-masing. Dalam hal ini, kami hanya menulis lint-check, yang gagal dibangun ketika membangun aplikasi, jika kami menempatkan wallpaper yang dikodekan secara progresif di apk itu sendiri. Recoded semua wallpaper, mengulangi situasi di backend, yang mendistribusikan sisa set wallpaper, dan semuanya berfungsi dengan baik. Tapi itu memakan waktu sekitar dua hari proses.



Ini terlihat seperti ini dalam kode. Tidak menyenangkan, tetapi sayangnya, seperti itu. Biasanya baris ini muncul setelah debugging yang panjang.



Jaminan apa yang diberikan Google kepada kami untuk memastikan bahwa API tidak terlalu rusak sehingga aplikasi pada prinsipnya tidak berfungsi? Pertama-tama, ada CDD, yang menjelaskan apa yang mungkin dan apa yang tidak bisa diubah, apa yang kompatibel ke belakang dan apa yang tidak. Ini adalah dokumen beberapa lusin halaman dengan rekomendasi umum, yang, tentu saja, tidak akan mencakup semua kasus. Untuk mencakup lebih banyak kasus, ada CTS, yang harus diselesaikan agar ponsel menerima sertifikasi dari Google dan layanan Google dapat digunakan darinya. Ini adalah sekitar 350.000 tes otomatis. Ada juga CTS Verifier, APK reguler yang dapat Anda pasang di ponsel Anda untuk melakukan serangkaian pemeriksaan. Omong-omong, jika Anda membeli telepon dengan tangan, Anda dapat memeriksanya seperti itu.

Dengan munculnya Treble, proyek VTS muncul, lebih besar kemungkinannya bagi pengembang tingkat yang lebih rendah. Ini memeriksa API driver, yang, dimulai dengan Project Treble, versi dan juga menjalani tes serupa. Selain itu, para pengembang ponsel itu sendiri adalah orang-orang sehat yang ingin aplikasi Android berfungsi dengan baik untuk mereka, tetapi ini harapan yang sangat-sangat. Sisi negatifnya adalah kami menemukan bug yang tidak terduga yang tidak dapat diprediksi hingga aplikasi diluncurkan pada perangkat. Sekali lagi, kami dipaksa untuk membeli, di samping fakta bahwa versi berbeda dari API, ada juga perangkat tambahan dari produsen yang berbeda untuk memeriksa mereka.

Tetapi ada aspek positifnya. Paling tidak, fitur yang paling sering diterapkan oleh pabrikan masuk ke dalam Android itu sendiri. Seseorang mungkin ingat bahwa API Sidik Jari standar muncul lebih lambat dari perangkat yang dapat membuka kunci layar dengan sidik jari. Sekarang, menurut Pengembang XDA, Android API juga ingin membuka kunci menggunakan kamera di wajah, tetapi ini belum akurat. Kami kemungkinan akan mencari tahu tentang hal ini bersama Anda.

Selain itu, pengembang perangkat itu sendiri, ketika mereka membuat API non-standar, mereka dapat, dan banyak menerbitkan perpustakaan untuk bekerja dengan API mereka untuk pengembang biasa. Dan jika Anda belum pernah melakukan ini sebelumnya, saya menyarankan Anda untuk melihat statistik penggunaan aplikasi Anda, lihat apa produsen paling populer, dan lihat portal pengembang situs mereka. Saya pikir Anda akan terkejut bahwa banyak memiliki API dengan fitur perangkat keras yang menarik, fitur keamanan, layanan cloud, atau hal lain yang menarik. Dan pada pandangan pertama tampaknya liar untuk menulis fitur terpisah untuk perangkat individu, tetapi selain perangkat ada juga produsen prosesor, yang bahkan lebih kecil, yang juga mengimplementasikan API mereka. Sebagai contoh, Qualcomm memiliki akselerasi perangkat keras yang luar biasa untuk mengenali gambar dari kamera, yang dapat Anda gunakan, mereka bahkan memiliki deskripsi yang baik tentang mereka.

Dengan demikian, siapa pun dari Anda bisa mendapatkan manfaat bahkan dari jenis fragmentasi ini. Apa yang kita lakukan dengan ini? Dalam hal apapun jangan ragu untuk melaporkan bug dan mengirim laporan bug ke pengembang perangkat dan bahkan pengembang Android. Karena jika ada API yang layak ditulis tes CTS rusak, maka akan ditulis - dan ada preseden seperti itu - dan setelah itu API menjadi lebih andal.

Pelajari Android, pelajari apa yang produsen tawarkan, jangan bersumpah dengan mereka - bekerja dengan mereka.

Seperti apa bentuknya dari dalam? Bagaimana saya bisa menerapkan beberapa fitur yang akan unik untuk ponsel kami dan menggunakan API ini dari aplikasi Android biasa?



Sedikit teori. Bagaimana pengembang Android sendiri menggambarkan perangkat AOSP internal? Lapisan atas adalah aplikasi yang ditulis oleh Anda atau oleh pengembang ponsel itu sendiri, yang tidak memiliki hak tinggi, hanya menggunakan API standar. Ini adalah framework, ini adalah kelas yang bukan bagian dari aplikasi Anda, seperti Activity, Parcelable, Bundle - mereka adalah bagian dari sistem, mereka disebut sebagai framework. Kelas-kelas yang tersedia untuk Anda di perangkat. Berikutnya adalah layanan sistem. Inilah yang menghubungkan Anda ke sistem: ActivityManagerService, WindowManagerService, PackageManagerService, yang mengimplementasikan sisi internal interaksi dengan sistem.

Berikutnya adalah Hardware Abstraction Layer, ini adalah lapisan atas driver, yang berisi semua logika untuk ditampilkan di layar, untuk berinteraksi dengan Bluetooth dan sejenisnya. Kernel adalah lapisan bawah driver, manajemen sistem. Mereka yang tahu apa inti dan wajahnya, tidak perlu mengatakannya, tetapi Anda bisa berbicara untuk waktu yang lama.



Bagaimana tampilannya di perangkat? Aplikasi kita berinteraksi tidak hanya dengan kerangka kerja standar, tetapi juga dapat berinteraksi dengan kerangka kerja kustom pabrikan. Juga, melalui kerangka kerja ini, dapat berkomunikasi dengan layanan kustom. Jika ini adalah fitur bawaan atau level rendah, maka HAL ditulis untuk mereka, dan bahkan driver di tingkat kernel, jika perlu.



Bagaimana kita menulis fitur kita? Rencananya sederhana: Anda perlu menulis kerangka kerja yang tidak jauh berbeda dari perpustakaan yang ditulis sebagian besar pengembang Android, saya pikir Anda semua tahu ini. Anda perlu menulis layanan sistem, yang merupakan aplikasi biasa, hanya dengan seperangkat hak yang tidak biasa dalam sistem. Dan jika perlu, Anda dapat menulis HAL, tetapi kami menghilangkan ini. Anda dapat menulis driver Anda sendiri di tingkat kernel, tetapi kami juga tidak akan mempertimbangkannya. Dan tulis aplikasi klien yang akan menggunakan semua ini.



Agar kita dapat berinteraksi dengan sistem, kita perlu menulis semacam kontrak, dan untuk ini sudah ada mekanisme yang baik untuk antarmuka AIDL. Ini hanya semacam antarmuka yang dengannya sistem menghasilkan kelas tambahan yang dapat kami perpanjang, yang dengannya komunikasi antarproses antara aplikasi Anda dan layanan sistem dilakukan.



Selanjutnya, kami menulis kerangka kerja, pustaka kami, yang menampung implementasi antarmuka ini, dan mem-proksi semua panggilan ke sana. Jika Anda tertarik, maka ActivityManager, PackageManager, WindowManager bekerja dengan cara yang sama. Ada sedikit lebih banyak logika daripada yang telah kami terapkan di sini, tetapi intinya hanya itu.



Kami menerapkan kerangka kerja, kami perlu menulis layanan sistem yang akan menerima data kami dari sisi sistem, dalam hal ini kami mengirim dan membaca integer. Kami membuat kelas, itu juga memperluas antarmuka yang dihasilkan dari AIDL pada slide sebelumnya. Kami membuat bidang di mana kami menulis nilai, membaca, menulis setter, pengambil. Satu-satunya hal adalah bahwa tidak ada cukup kunci, tetapi mereka tidak muat pada slide sangat banyak, mereka harus dilakukan.



Selanjutnya, agar layanan sistem ini tersedia, kita harus mendaftarkannya di manajer layanan sistem, dan dalam hal ini adalah kelas yang sama yang tidak tersedia untuk aplikasi biasa. Ini tersedia tepat untuk mereka yang ada di platform di partisi sistem. Kami mendaftarkan layanan hanya di Application.onCreate (), membuatnya tersedia dengan nama kelas yang kami buat.

Apa yang kita perlukan untuk onCreate () untuk memulai dan layanan kita untuk dimuat ke dalam memori? Kami menulis dalam manifes di aplikasi android: persistent = ”true”. Ini berarti bahwa ini adalah proses yang persisten, harus dalam memori terus-menerus, karena menjalankan fungsi sistem.



Juga dalam manifes itu sendiri kita dapat menentukan android: sharedUserId, dalam sistem kasus ini, tetapi dapat berupa berbagai ID yang berbeda, mereka memungkinkan aplikasi untuk mendapatkan hak yang lebih luas dalam sistem, berinteraksi dengan berbagai API dan layanan yang tidak tersedia untuk aplikasi biasa.

Dalam hal ini, misalnya, kami tidak menggunakan yang seperti ini.



Kami menulis kerangka kerja, menulis layanan sistem. Kami akan menghilangkan mekanisme di dalamnya, ini adalah topik yang agak rumit, layak mendapat laporan terpisah.

Bagaimana cara menyampaikan kerangka kerja ke pengembang aplikasi? Dua format. Kami dapat mengeluarkan kelas lengkap dan membuat perpustakaan lengkap yang Anda kompilasi ke dalam aplikasi Anda, dan semua logika akan menjadi bagian dari dexes Anda.

Atau Anda dapat mendistribusikan kerangka kerja dalam bentuk kelas rintisan, relatif yang hanya dapat Anda tautkan selama kompilasi dan berharap bahwa kelas-kelas ini akan menunggu Anda dengan cara yang sama dengan contoh-contoh sebelumnya dari berbagai versi Android pada perangkat itu sendiri. Anda dapat mendistribusikannya baik melalui repositori Maven reguler yang semua orang tahu, atau melalui Android Studio sdkmanager, mirip dengan cara Anda menginstal versi baru SDK. Sulit untuk mengatakan metode mana yang lebih nyaman. Lebih nyaman bagi saya secara pribadi untuk menghubungkan Maven.



Kami sedang menulis aplikasi sederhana. Dengan cara yang akrab, kami menghubungkan dependensi compileOnly, hanya sekarang perpustakaan kami. Kami meresepkan kegunaan-pustaka yang kami tulis dan yang diletakkan di perangkat. Kami menulis Activity, mendapatkan akses ke kelas-kelas ini, berinteraksi dengan sistem. Jadi akan sangat mungkin untuk menerapkan semua fitur: transfer data ke beberapa perangkat tambahan, fitur perangkat keras tambahan, dll.

Dengan demikian, semua pengembang membuat fitur unik perangkat tersedia untuk pengembang. Terkadang ini adalah API pribadi yang hanya memberikan kepada mitra. Terkadang mereka bersifat publik dan yang dapat Anda temukan di portal pengembang. Ada cara lain untuk mengimplementasikan hal-hal seperti itu, tetapi saya menggambarkan metode yang dianggap sebagai yang utama di Google dan di antara pengembang Android.

Anda tidak boleh memperlakukan pengembang perangkat sebagai orang yang merusak aplikasi Anda. Ini adalah pengembang yang sama, mereka menulis kode yang sama, pada tingkat yang hampir sama. Menulis laporan bug, itu sangat membantu, saya sering menganalisisnya. Tulis lebih banyak aplikasi dan manfaatkan peluang yang disediakan oleh Android dan perangkat itu sendiri. Saya memiliki semuanya.

Source: https://habr.com/ru/post/id448126/


All Articles