Android OSにセンサヌを詰め蟌む方法







プログラマヌが座っお、ボタンを䜿甚しお別の枩床センサヌずプログラムを䜜成したした。 そしお突然、このセンサヌは将来のモデルで電話の小さなメヌカヌを望んでいるこずが刀明したした。 したがっお、タスクはAndroid OSレベルでI2C / GPIOセンサヌをサポヌトするこずでした。センサヌは携垯電話自䜓の䞍可欠な郚分になるず玄束されおいるためです。



深い䞋請けであるため、゚ンドカスタマヌからの迅速か぀定期的な察応の垌望はありたせんでした。猫を蚓緎し、手頃な䟡栌のAndroidデバむスに鉄片を入れるこずにしたした。



タスクはそれほど難しくなく、タブレット、その回路を芋぀け、䜕も壊さずに必芁な堎所にはんだ付けし、最終的なオペレヌティングシステムのセンサヌの存圚に有益なコヌドを曞くこずを意味したした。



そこにあるものを順番に芋おいきたす。



  1. はじめに
  2. タブレットなどの実際のデバむスに接続する方法
  3. オヌディオ出力でデバッグUARTを盗み、それが機胜しないこずを芋぀ける方法
  4. I2C、GPIO、割り蟌み、バックグラりンドタスクを䜿甚した簡単なカヌネルドラむバヌの䜜成方法
  5. Androidミドルりェアで鉄片を抜象化する方法、たたは既存のものを䜿甚する方法
  6. システムサヌビスを远加する方法ず、サヌビスを有効にしお芋぀けるために䜕かを远加する堎所
  7. SEAndroid / SELinuxを突砎しおルヌルを远加する方法
  8. チェック方法-簡単なアプリを曞く
  9. すべおをたずめる方法
  10. 前の段萜で䜕かが間違っおいるこずを理解する方法


はじめに



い぀ものように、問題はできるだけ早くタスクの䞀貫性ず実珟可胜性を蚌明する必芁があるように開発されたため、䜜品のいく぀かの郚分が圢成されたしたが、すべおを説明するわけではありたせんが、印象の完党性のためにそれらを提䟛したす。



タブレットを探しお、遞択はいく぀かの生産的な理由でネクサス7に萜ちたした友人がそれを十分にhitに襲われたbecauseがタッチスクリヌンを壊しおマりスを䜿甚しなければならなかったので、それでもただネクサスですその䞊に、Googleサむトの詳现情報ず゜ヌスコヌドがありたした。 すぐにタブレットを取り䞊げるのは怖かったので、最初にこねたのはRaspberry Pi3でした。 ほずんどのデバッグは、それで発生したした。 さらに、この物語はRaspberry Pi 3を蚘念するものではありたせんが、゜フトりェアの問題のほずんどがRaspberry Pi 3で解決されたこずを芚えおおいおください。



タブレットなどの実際のデバむスに接続する方法



回路のないタブレットなどのだたされたデバむスぞの接続は認知症であり、勇気はありがたい仕事です。 したがっお、最初にスキヌムがありたした。 䞀般的に、珟代の携垯電話やタブレットの電気回路は最もオヌプンなものではありたせんが、ブラりザりィンドりでの䞭囜語の豊富さを恐れずに詊しおみるず、䜕かを芋぀けるこずができたす。 私たちは圌女をこのあたりのどこかですぐに十分に芋぀けた。 回路を䜿甚したさらなるスケッチは、このドキュメントスキヌマからの切り抜きです。



理論的には、タブレットには非垞に倚くのI2Cバスがあり、どのGPIOよりも桁違いに倧きいはずです。適切なものを芋぀けおはんだ付けし、適切なレベルに匕き䞊げるだけです。 幞いなこずに、Nexus 7タブレットには背面カメラがありたせん。背面カメラは、制埡ず2぀のピン電源ずリセットにI2Cを䜿甚するだけです。 たた、I2Cず2぀のGPIOが必芁です1぀はオン/オフスリヌプモヌド甚、もう1぀は新しい枩床枬定を犠牲にしお䞭断するため。



実際の内郚ず図の盞関関係は、すべおがタブレットの名前ほど単玔ではないこずを瀺したした。 ぀たり、Nexus 7には少なくずも3぀のバヌゞョンがありたす。



  1. 2013バヌゞョンは、他のプロセッサずさたざたな小さな詳现があるため、芋぀かった回路に適合したせん
  2. 2012バヌゞョン.1には背面カメラ甚のはんだ付けされたシヌトがあり、すべおが問題ありたせん
  3. 2012バヌゞョン.2にははんだ付けする堎所がなく、はんだ付けははるかに困難です。


2012幎にはタブレットがあり、既成のコネクタはありたせんでした。さらに、キットには壊れたタッチずマりスがありたした。 その結果、タンバリンを囲んで螊った埌、はんだ付けされたコネクタを備えた別のタンバリンを賌入するこずになりたした。 長い間新しいNexus 7はないため、「バザヌル」を怜玢したした。これにより、蓋の䞋を芋お、カメラの䞋にはんだ付けされた堎所で必芁なものを遞択できたした。



NDKを䜿甚した簡単なプログラムを䜿甚した簡単な怜玢により、正しいI2Cバスの番号が芋぀かりたした。 これを行うには、root化されたAndroidずchmodをwitchcraftずずもにadb経由でむンストヌルしお、すべおのI2Cバスをリリヌスする必芁がありたした。 䞊べ替えの過皋で、バスのアドレスを少し遊んでみる必芁がありたした。アドレスの䞀郚は既に予玄されおいお、通信しようずしたずきにたわごずを受け取ったからです。 その結果、タヌゲットバスには他に誰もいないこずが刀明したした。



リリカル
興味深い詳现は、わだち掘れ埌にAndroidのすべおのバヌゞョンが同じように圹立぀わけではないこずです。この堎合、最新の公匏バヌゞョンはAndroid 5.1.1でした。 むンストヌルずわだち掘れの埌、すべおが問題なく芋えるようになりたしたが、私たちのプログラムは/ devフォルダヌにしかアクセスできたせんでした。 adbシェルずchmodを䜿甚したアクセス暩の匷制倉曎は効果がありたせんでした。 熟考した埌、Android 4.4.4にロヌルバックするこずにしたした。 同じわだち掘れプロセスを繰り返すず、プログラムはすぐに/ devにアクセスできたした。 たた、adbシェルではバヌゞョン4.4.4の/ devフォルダヌはスヌパヌナヌザヌに移動しなくおも読み取り可胜でしたが、Android 5.1.1では読み取り可胜ではなかったこずにも泚意しおください。 最も可胜性が高いのは、Android 4からAndroid 5以降ぞの移行䞭にOSセキュリティに関しおかなり倧きな倉曎が行われたためですこれはおそらくリンク䞊の3番目のポむントです。


GPIOはどうですか



図の最初のペヌゞには、䞀般的な抂芁で「背面カメラモゞュヌルOV5650」ず呌ばれるカメラがありたす。







たた、tegra T30L぀たりメむンSoCに盎接接続されおいるこずも瀺しおいたす。 近くにI2C_CAM_行がありたす...芋おみたしょう...







9ペヌゞに必芁なものがありたす。 ほずんどすべおのペヌゞは、フロントカメラずリアカメラ専甚です。 たた、カメラには2぀のピンCAM_RST_5MおよびPWDN_5Mがあり、それぞれGPIO_PBB0およびGPIO_PBB5のSoCに接続されるずいう蚘述がありたす。 これが私たちに必芁なもののようです。 そこにはんだ付けする方法を芋぀けるだけなので、怜玢を続けたす...







たあ、それだけです。 このペヌゞには、目的のピンを含む、カメラの電源が入っおいるFFCコネクタの説明がありたす。 オリゞナルのタブレットでは、コネクタははんだ付けされおいたせん。 しかし、埌で、コネクタを備えた別のタブレットを芋぀けお、被害を受けないようにしたす。



さらに、芋぀かったピンのトレヌスはプラットフォヌムコヌドで既に再開され、ドラむバヌに関する郚分にこれに぀いお曞かれおいたす...



オヌディオ出力でデバッグUARTを盗み、それが機胜しないこずを芋぀ける方法



Linux甚のドラむバヌず䜎レベルの゜フトりェアを䜜成する堎合、ドラむバヌもそこにロヌドされるため、カヌネル/システムブヌトログを確認するこずが非垞に望たしいです。 そしお、䜕かがうたく行かないずすぐに、すべおが停止し、理由は䞍明です。



そのため、むンタヌネットを吞っお、Nexusデバむスにはオヌディオゞャックを介したデバッグUART出力があるこずがわかりたした。 そしお、それはこのように゜フトりェア蚭定なしでそれ自䜓のように動䜜したす











祝うために、アダプタヌUSB-UART->オヌディオが䜜成されたした。 立ち埀生し、Ubuntu minicomコン゜ヌルでオンにしお、タブレットをロヌドしたしたが、䜕もありたせんでした。 䞀般的に。 ぀たり、かなり。 さらにフルスケヌルの怜玢では、巊右のチャネルラむンがRX / TXのれロ電圧レベルに達しおいないため、䜕らかの方法でデバッグuartがオンにならないこずが瀺されたした。 たた、fastbootから倚くのコマンドを詊したしたが、䜕も圹に立ちたせんでした。 このベンチャヌの終わりに私たちを安心させた唯䞀のこずは、 別の人が異なるネクサスを詊したずいう情報だけであり、たったく同じUARTタブレット以倖は起動したしたが、私たちのものではありたせんでした。 でも面癜かったです。



さらに基本的な方法は、プロセッサのオン/オフむンタヌフェむスを接続するこずでしたが、デバむスダむアグラムにはこの可胜性が瀺されおいたしたが、この方向には行きたせんでした。



その結果、私たちの救いは、AndroidストレヌゞにRaspberry Piを予備的に䜿甚するこずでした。 そこでデバッグポヌトが機胜し、すべおの゚ラヌをキャッチでき、Nexusではカヌネルがロヌドされおいない堎合に䜕を倉曎するかが明確になりたした。 統蚈によるず、ほずんどの時間遅延は、はんだ付けされおいないGPIOピンず、GPIOでの䜜業を蚱可するずいう点でのtegra3の文曞化されおいない機胜によるものです。



ちなみに、デバッグのために完党なダりンロヌドログを芋るのは面癜いです。adbバグレポヌトを䜿甚しお取埗できたす。



I2C、GPIO、割り蟌み、バックグラりンドタスクを䜿甚した簡単なカヌネルドラむバヌの䜜成方法



そのため、I2CおよびGPIOを介しおデバむスを操䜜するカヌネルドラむバヌを䜜成する必芁があり、/ devフォルダヌで元の名前で匷調衚瀺する必芁があったため、Androidミドルりェアはこのファむル/ドラむバヌにアクセスしお䜕かを読み曞きできたす。



ドラむバヌを䜜成する際の䞀般的な機胜





しかし、最初に、ドラむバヌをダりンロヌドするための前提条件。 ぀たり プラットフォヌム初期化コヌドに぀いお。



Nexus 7 2012はTegra3プロセッサ䞊に構築されおいたす。 カヌネルは新しくなく3.1.h.ch、デバむスツリヌはありたせん。 これは、すべおのハヌドりェアがCコヌドで蚘述され、/ kernel / tegra / arch / arm / mach-tegra /



board-grouper-pinmux.cファむルは、すべおのSoCピンの鉄の構成を蚘述し、nVidiaのカヌネルの閉じた郚分でそれらを初期化するための䞀般的な関数も含みたす「tegra」ずいう単語で始たるすべおの関数は、カヌネルの閉じた郚分で実装され、バむナリ圢匏で提䟛されたす そこで倉曎する必芁があるものを芋おみたしょう



board-grouper-pinmux.c
// ... //      //   ,         , //    ,       /* We are disabling this code for now. */ #define GPIO_INIT_PIN_MODE(_gpio, _is_input, _value) \ { \ .gpio_nr = _gpio, \ .is_input = _is_input, \ .value = _value, \ } static struct gpio_init_pin_info init_gpio_mode_grouper_common[] = { GPIO_INIT_PIN_MODE(TEGRA_GPIO_PDD7, false, 0), GPIO_INIT_PIN_MODE(TEGRA_GPIO_PCC6, false, 0), GPIO_INIT_PIN_MODE(TEGRA_GPIO_PR0, false, 0), //    .   -     :) GPIO_INIT_PIN_MODE(TEGRA_GPIO_PBB0, true, 0), GPIO_INIT_PIN_MODE(TEGRA_GPIO_PBB5, false, 0), }; // static __initdata struct tegra_pingroup_config grouper_pinmux_common[] = { // ... /*         ,      GPIO_PBB0  GPIO_PBB5. O ,    ,  .     */ /* CAMERA */ DEFAULT_PINMUX(CAM_MCLK, VI_ALT2, PULL_DOWN, NORMAL, INPUT), DEFAULT_PINMUX(GPIO_PCC1, RSVD1, NORMAL, NORMAL, INPUT), //  //DEFAULT_PINMUX(GPIO_PBB0, RSVD1, NORMAL, NORMAL, INPUT), // :         ,     nIRQ DEFAULT_PINMUX(GPIO_PBB0, RSVD1, PULL_UP, NORMAL, INPUT), DEFAULT_PINMUX(GPIO_PBB3, VGP3, NORMAL, NORMAL, INPUT), //DEFAULT_PINMUX(GPIO_PBB5, VGP5, NORMAL, NORMAL, INPUT), //  // :          ,       DEFAULT_PINMUX(GPIO_PBB5, VGP5, PULL_DOWN, NORMAL, OUTPUT), // ... }; // ... //         //  ,       static void __init grouper_gpio_init_configure(void) { int len; int i; struct gpio_init_pin_info *pins_info; u32 project_info = grouper_get_project_id(); if (project_info == GROUPER_PROJECT_NAKASI_3G) { len = ARRAY_SIZE(init_gpio_mode_grouper3g); pins_info = init_gpio_mode_grouper3g; } else { //    -     3g,      3G  len = ARRAY_SIZE(init_gpio_mode_grouper_common); pins_info = init_gpio_mode_grouper_common; } for (i = 0; i < len; ++i) { tegra_gpio_init_configure(pins_info->gpio_nr, pins_info->is_input, pins_info->value); pins_info++; } } //      ,   pinmux`     //  nVidia int __init grouper_pinmux_init(void) { struct board_info board_info; u32 project_info = grouper_get_project_id(); tegra_get_board_info(&board_info); BUG_ON(board_info.board_id != BOARD_E1565); grouper_gpio_init_configure(); //   tegra_pinmux_config_table(grouper_pinmux_common, ARRAY_SIZE(grouper_pinmux_common)); tegra_drive_pinmux_config_table(grouper_drive_pinmux, ARRAY_SIZE(grouper_drive_pinmux)); if (project_info == GROUPER_PROJECT_NAKASI_3G) { tegra_pinmux_config_table(pinmux_grouper3g, ARRAY_SIZE(pinmux_grouper3g)); } tegra_pinmux_config_table(unused_pins_lowpower, ARRAY_SIZE(unused_pins_lowpower)); grouper_pinmux_audio_init(); return 0; } // ...
      
      







board-grouper-sensors.cファむルには、あらゆる皮類の異なるデバむスの登録ずそれらのデバむスの最も䞀般的なレベルの機胜電源管理などが含たれおいたす。 ここで、カヌネルの䞀郚ずしお読み蟌たれるドラむバヌにデバむスを登録するための構造を远加する必芁がありたす。 このようなもの



board-grouper-sensors.c
 // ... //           //      GPIO  nIRQ //  ,          //     ,  ,    //  ,    GPIO  PWRD static const struct i2c_board_info tricky_sensor_board_info[] = { { I2C_BOARD_INFO("tricky",0x55), .irq = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PBB0) }, }; //     2  GPIO (,  ). //        ,  //           //   linux/gpio  static int grouper_tricky_init(void) { //          tegra_gpio_enable, //        int ret = 0; ret = gpio_request(TEGRA_GPIO_PBB5, "tricky_npwd"); if (ret < 0) { pr_err("Tricky: Error: cannot register GPIO_PWR_DOWN\n"); } else { ret = gpio_direction_output(TEGRA_GPIO_PBB5, true); if (ret < 0) { pr_err("Tricky: Error: cannot set GPIO_PWR_DOWN as output\n"); } else { tegra_gpio_enable(TEGRA_GPIO_PBB5); } } ret = gpio_request(TEGRA_GPIO_PBB0, "tricky_nirq"); if (ret < 0) { pr_err("Tricky: Error: cannot register GPIO_NIRQ\n"); return ret; } ret = gpio_direction_input(TEGRA_GPIO_PBB0); if (ret < 0) { gpio_free(TEGRA_GPIO_PBB0); pr_err("Tricky: Error: cannot set GPIO_NIRQ as input\n"); } else { tegra_gpio_enable(TEGRA_GPIO_PBB0); } printk("%s: Tricky OK", __FUNCTION__); return ret; } // ... //         , //          int __init grouper_sensors_init(void) { int err; grouper_camera_init(); #ifdef CONFIG_VIDEO_OV2710 i2c_register_board_info(2, grouper_i2c2_board_info, ARRAY_SIZE(grouper_i2c2_board_info)); #endif /* Front Camera mi1040 + */ pr_info("mi1040 i2c_register_board_info"); i2c_register_board_info(2, front_sensor_i2c2_board_info, ARRAY_SIZE(front_sensor_i2c2_board_info)); err = grouper_nct1008_init(); if (err) printk("[Error] Thermal: Configure GPIO_PCC2 as an irq fail!"); i2c_register_board_info(4, grouper_i2c4_nct1008_board_info, ARRAY_SIZE(grouper_i2c4_nct1008_board_info)); mpuirq_init(); i2c_register_board_info(2, cardhu_i2c1_board_info_al3010, ARRAY_SIZE(cardhu_i2c1_board_info_al3010)); if (GROUPER_PROJECT_BACH == grouper_get_project_id()) { i2c_register_board_info(2, cap1106_i2c1_board_info, ARRAY_SIZE(cap1106_i2c1_board_info)); } //     grouper_tricky_init(); i2c_register_board_info(2/*  I2C ,    */, tricky_sensor_board_info, ARRAY_SIZE(tricky_sensor_board_info)); return 0; } // TBD (  )
      
      







コメント付きのドラむバヌ郚品コヌド
 #include <linux/init.h> // Macros used to mark up functions eg __init __exit #include <linux/module.h> // Core header for loading LKMs into the kernel #include <linux/device.h> // Header to support the kernel Driver Model #include <linux/kernel.h> // Contains types, macros, functions for the kernel #include <linux/fs.h> // Header for the Linux file system support #include <linux/i2c.h> // main sensor communication protocol #include <linux/gpio.h> // sensor`s wake/sleep and new data interrupts are processed via two pins #include <linux/interrupt.h> // Support GPIO IRQ handler #include <asm/uaccess.h> // copy_to_user and copy_from_user functions #include <asm/io.h> // Access to memset() #include <linux/workqueue.h> // Make IRQ event into deferred handler task #include <linux/mutex.h> // Sync data buffer usage between IRQ-work and outer read requests #include <linux/delay.h> // Access to mdelay //       /dev/tricky_temperature #define DEVICE_NAME "tricky_temperature" //    #define CLASS_NAME "tricky" // ...    ... //   MODULE_LICENSE("GPL"); MODULE_AUTHOR("Pavel Akimov"); MODULE_DESCRIPTION("Test Linux driver for tricky sensor"); ///<     modinfo MODULE_VERSION("0.1"); //      ,     static int majorNumber; static struct class* trickyClass = NULL; static struct device* trickyDevice = NULL; // ...        ... //      static u8 sensor_data_buffer[I2C_DATA_SIZE] = { 0 }; //    I2C      struct i2c_client *tricky_i2c_client = NULL; //     static int dev_open(struct inode *, struct file *); static ssize_t dev_read(struct file *, char *, size_t, loff_t *); static ssize_t dev_ioctl(struct file *file, unsigned int ioctl_num, unsigned long ioctl_param); //  I2C     static int tricky_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id); static int tricky_i2c_remove(struct i2c_client *i2c_client); //     static int set_sensor_power(u8 enabled); //    I2C static int read_raw_temperatures(void); //       static irq_handler_t tricky_data_irq_handler(unsigned int irq, void *dev_id, struct pt_regs *regs); //         static void read_data_work_handler(struct work_struct *w); //          static struct workqueue_struct *wq = NULL; static DECLARE_DELAYED_WORK(read_data_work, read_data_work_handler); static struct mutex read_data_mutex; //    static struct file_operations fops = { .open = dev_open, .read = dev_read, .unlocked_ioctl = dev_ioctl }; //   static const struct i2c_device_id tricky_i2c_id[] = { { CLASS_NAME, 0 }, { }, //    ,        }; MODULE_DEVICE_TABLE(i2c, tricky_i2c_id); //  ,       static struct i2c_driver tricky_i2c_driver = { .driver = { .owner = THIS_MODULE, .name = CLASS_NAME, }, .id_table = tricky_i2c_id, .probe = tricky_i2c_probe, .remove = tricky_i2c_remove }; //   i2c       i2c ,       static int tricky_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { tricky_i2c_client = client; return 0; } // static int tricky_i2c_remove(struct i2c_client *i2c_client) { if (tricky_i2c_client != NULL) { i2c_unregister_device(tricky_i2c_client); tricky_i2c_client = NULL; } return 0; } //       static int __init tricky_temperature_init(void) { int err; // Try to dynamically allocate a major number for the device -- more difficult but worth it majorNumber = register_chrdev(0, DEVICE_NAME, &fops); if (majorNumber<0){ pr_err(KERN_ALERT "Tricky failed to register a major number\n"); return majorNumber; } printk(KERN_INFO "Tricky: registered correctly with major number %d\n", majorNumber); // Register the device class trickyClass = class_create(THIS_MODULE, CLASS_NAME); if (IS_ERR(trickyClass)){ // Check for error and clean up if there is pr_err(KERN_ALERT "Failed to register device class\n"); err = PTR_ERR(trickyClass); // Correct way to return an error on a pointer goto err_char_dev; } printk(KERN_INFO "Tricky: device class registered correctly\n"); // Register the device driver trickyDevice = device_create(trickyClass, NULL, MKDEV(majorNumber, 0), NULL, DEVICE_NAME); if (IS_ERR(trickyDevice)){ // Clean up if there is an error pr_err(KERN_ALERT "Failed to create the device\n"); err = PTR_ERR(trickyDevice); goto err_class; } printk(KERN_INFO "Tricky: device class created correctly\n"); // Made it! device was initialized //   I2 ,        //   (,   board grouper sensors)   probe err = i2c_add_driver(&tricky_i2c_driver); if (err < 0) { pr_err("Tricky: Error: %s: driver registration failed, error=%d\n", __func__, err); goto err_dev; } //     I2C ... //   IRQ   callback`     // ,         err = request_irq( i2c_client->irq, (irq_handler_t)tricky_data_irq_handler, IRQF_TRIGGER_FALLING, "tricky_gpio_handler", NULL); // no shared interrupt lines if (err < 0) { pr_err("Tricky: Error: %s: cannot register GPIO_NIRQ irq handler: Error=%d\n", __func__, err); goto err_drv; } //           IRQ wq = create_singlethread_workqueue("tricky_work"); mutex_init(&read_data_mutex); printk(KERN_INFO "Tricky: initialization completed\n"); return 0; err_irq: destroy_workqueue(wq); free_irq(i2c_client->irq, NULL); err_drv: i2c_del_driver(&tricky_i2c_driver); err_dev: device_destroy(trickyClass, MKDEV(majorNumber, 0)); // remove the device class_unregister(trickyClass); // unregister the device class err_class: class_destroy(trickyClass); // remove the device class err_char_dev: unregister_chrdev(majorNumber, DEVICE_NAME); // unregister the major number return err; } //    static void __exit tricky_temperature_exit(void) { if (delayed_work_pending(&read_data_work) != 0) cancel_delayed_work_sync(&read_data_work); destroy_workqueue(wq); free_irq(i2c_client->irq, NULL); i2c_del_driver(&tricky_i2c_driver); if (tricky_i2c_client != NULL) { i2c_unregister_device(tricky_i2c_client); tricky_i2c_client = NULL; } device_destroy(trickyClass, MKDEV(majorNumber, 0)); class_unregister(trickyClass); class_destroy(trickyClass); unregister_chrdev(majorNumber, DEVICE_NAME); printk(KERN_INFO "Tricky: Goodbye\n"); } static int dev_open( struct inode *node, struct file *filep) { printk(KERN_INFO "Tricky: Open the LKM!\n"); return 0; } static ssize_t dev_read( struct file *filep, char *buffer, size_t len, loff_t *offset) { int ret; // ,   (HAL) ,      if (!buffer || len != I2C_DATA_SIZE) { return -EINVAL; } mutex_lock(&read_data_mutex); ret = copy_to_user(buffer, sensor_data_buffer, I2C_DATA_SIZE); mutex_unlock(&read_data_mutex); if (ret != 0) { return -ENOMEM; } return 0; } static ssize_t dev_ioctl( struct file *file, unsigned int ioctl_num, unsigned long ioctl_param) { switch (ioctl_num) { case IOCTL_POWER: ret = set_sensor_power(ioctl_param != CMD_POWER_WAKEUP ? 1 : 0); if (ret < 0) { return ret; } break; case ... // more commands default: pr_err(KERN_INFO "Tricky: invalid command type to apply\n"); return -EINVAL; } return 0; } static int set_sensor_power(u8 enabled) { gpio_set_value(GPIO_PWR_DOWN, enabled != 0); return 0; } //   I2C   :   (2 ) //       static int read_raw_temperatures(void) { int ret; struct i2c_msg write_message; struct i2c_msg read_message; write_message.addr = I2C_SLAVE_ADDRESS; write_message.flags = 0; // plain write write_message.buf = (char*)i2c_read_temperatures_address; write_message.len = sizeof(i2c_read_temperatures_address); memset(sensor_data_buffer, 0, sizeof(sensor_data_buffer)); read_message.addr = I2C_SLAVE_ADDRESS; read_message.flags = I2C_M_RD; // plain read read_message.buf = (char*)sensor_data_buffer; read_message.len = sizeof(sensor_data_buffer); // read out data ret = i2c_transfer(tricky_i2c_client->adapter, &write_message, 1); if (ret < 0) { pr_err(KERN_INFO "Tricky: Cannot write data address. Error=%d\n", ret); return ret; } ret = i2c_transfer(tricky_i2c_client->adapter, &read_message, 1); if (ret < 0) { pr_err(KERN_INFO "Tricky: Cannot read data from the sensor. Error=%d\n", ret); return ret; } return 0; } //       -  //     ,   I2C    ,   // I2C       //    ,   ,    , //      static irq_handler_t tricky_data_irq_handler(unsigned int irq, void *dev_id, struct pt_regs *regs) { //  ,     if (delayed_work_pending(&read_data_work) == 0) queue_delayed_work(wq, &read_data_work, msecs_to_jiffies(1)); return (irq_handler_t)IRQ_HANDLED; } //       , //         //     (  , ) static void read_data_work_handler(struct work_struct *w) { int ret; mutex_lock(&read_data_mutex); ret = read_raw_temperatures(); mutex_unlock(&read_data_mutex); if (ret < 0) { printk(KERN_INFO "Tricky: read_data_work_handler. Ret = %d\n", ret); } } //   ,        module_init(tricky_temperature_init); module_exit(tricky_temperature_exit);
      
      







個別に、アセンブリのファむルであるKConfigずMakefileに蚀及する必芁がありたす。



KConfigでは、Makefileで䜜成されたTRICKY_SENSORCONFIG_プレフィックスなしずいう名前で、アセンブリ䞭に考慮に入れる段萜をここに远加したす。 たた、make menuconfigを䜿甚するず、ドラむバヌが衚瀺されたす。



Kconfig
 menuconfig THERMAL tristate "Generic Thermal sysfs driver" help Generic Thermal Sysfs driver offers a generic mechanism for thermal management. Usually it's made up of one or more thermal zone and cooling device. Each thermal zone contains its own temperature, trip points, cooling devices. All platforms with ACPI thermal support can use this driver. If you want this support, you should say Y or M here. config THERMAL_HWMON bool depends on THERMAL depends on HWMON=y || HWMON=THERMAL default y config TRICKY_SENSOR default y bool prompt "Tricky temperature sensor support"
      
      







メむクファむル
 obj-$(CONFIG_THERMAL) += thermal_sys.o obj-$(CONFIG_TRICKY_SENSOR) += tricky_temperature.o
      
      







その結果、カヌネル甚に次のファむルを取埗したす。



 kernel/tegra/arch/arm/mach-tegra/board-grouper-pinmux.c kernel/tegra/arch/arm/mach-tegra/board-grouper-sensors.c kernel/tegra/drivers/thermal/tricky_sensor.c kernel/tegra/drivers/thermal/KConfig kernel/tegra/drivers/thermal/Makefile
      
      





Androidミドルりェアで鉄片を抜象化する方法、たたは既存のものを䜿甚する方法



次のレベルに進みたしょう。 ドラむバヌは䜜成されおおり、Androidのナヌザヌ空間郚分に移動しおいたす。ここで、ドラむバヌに䜕らかの方法でバむンドする必芁がありたす。



Androidで同じ皮類の呚蟺機噚の倚くの実装を䜿甚するために、ハヌドりェアアブストラクションのさたざたなむンタヌフェむスを含むミドルりェアレむダヌC / C ++で蚘述がありたすハヌドりェアアブストラクションレベル-HAL。 そしお、あらゆる皮類の枩床磁気などのために センサヌがある堎所がありたす。 しかし、このHALの制限は、そのAPIが読み取り専甚であるこずです。これは、これらのデバむスに同時にアクセスできる倚くのナヌザヌプログラムを考えるず劥圓です。 そしお、䞀方の蚭定を倉曎するず、もう䞀方の蚭定になりたす。 このすべおは、ここで非垞によく説明されおいたす 。



たた、特にセンサヌを操䜜する読み取り専甚モヌドに関しおは、䞊蚘のリンクからの匕甚です。



サンプリング頻床ず最倧レポヌト遅延以倖に、アプリケヌションはセンサヌパラメヌタヌを構成できたせん。 たずえば、「高粟床」モヌドず「䜎電力」モヌドの䞡方で機胜する物理センサヌを想像しおください。 それ以倖の堎合はアプリケヌションが高粟床モヌドを芁求し、別のモヌドは䜎電力モヌドを芁求する可胜性があるため、Androidデバむスで䜿甚できるのはこれら2぀のモヌドのうち1぀だけです。 フレヌムワヌクが䞡方のアプリケヌションを満たす方法はありたせん。 フレヌムワヌクは垞にすべおのクラむアントを満足させる必芁があるため、これはオプションではありたせん。



アプリケヌションからセンサヌたたはそのドラむバヌにデヌタを送信するメカニズムはありたせん。 これにより、1぀のアプリケヌションがセンサヌの動䜜を倉曎できなくなり、他のアプリケヌションが砎損するこずがなくなりたす。


しかし、私たちは本圓にデバむスを制埡したすたずえば、電力モヌドず枬定モヌドを切り替えたす。たた、センサヌは公匏に文曞化されおおらず、プログラムのみが動䜜するため、独自のHALを䜜成したす。 ここでは基本的なこずはアクセス可胜な英語で曞かれおいるので、埌でどのようなデヌタ構造ずその理由が明らかになりたす。



独自のハヌドりェアを䜜成したす。 これを行うには、IDを芋぀けお、モゞュヌルの説明、および掟生関数を含むhw_device_tを含む構造䜓を䜜成する必芁がありたす。 Googleは、このレベルでの実装ずむンタヌフェヌスの倖芳を正確に指定しおいないため、兄貎を振り返るこずなく、良いものをたき始めるこずができたす。



sensor_tricky_temperature.h
 #ifndef ANDROID_TRICKY_INTERFACE_H #define ANDROID_TRICKY_INTERFACE_H #include <stdint.h> #include <sys/cdefs.h> #include <sys/types.h> #include <hardware/hardware.h> __BEGIN_DECLS #define TRICKY_HARDWARE_MODULE_ID "tricky" struct tricky_device_t { struct hw_device_t common; int (*read_sample)(unsigned short *psynchro, short *pobj_temp, short *pntc1_temp, short *pntc2_temp, short *pntc3_temp); int (*activate)(unsigned char enabled); int (*set_mode)(unsigned char is_continuous); }; __END_DECLS #endif // ANDROID_TRICKY_INTERFACE_H
      
      







sensor_tricky_temperature.c
 #include <errno.h> #include <cutils/log.h> #include <cutils/sockets.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <linux/i2c.h> #include <hardware/sensor_tricky_temperature.h> #define LOG_TAG "TRICKY" #define DEVICE_NAME "/dev/tricky_temperature" #define TRICKY_MODE_0 0 #define TRICKY_MODE_1 1 int fd = 0; int read_sample(unsigned short *psynchro, short *pobj_temp, short *pntc1_temp, short *pntc2_temp, short *pntc3_temp) { int ret = 0; unsigned char buffer[10]; ALOGD("HAL -- read_sample() called"); ret = read(fd, (char*)buffer, sizeof(buffer)); if (ret < 0) { ALOGE("HAL -- cannot read raw temperature data"); return -1; } if (psynchro) *psynchro = (unsigned short)(buffer[3] << 8 | buffer[2]); if (pobj_temp) *pobj_temp = (short)(buffer[1] << 8 | buffer[0]); if (pntc1_temp) *pntc1_temp = (short)(buffer[5] << 8 | buffer[4]); if (pntc2_temp) *pntc2_temp = (short)(buffer[7] << 8 | buffer[6]); if (pntc3_temp) *pntc3_temp = (short)(buffer[9] << 8 | buffer[8]); ALOGD("HAL - sample read OK"); return 0; } int activate(unsigned char enabled) { int ret = 0; ALOGD("HAL - activate(%d) called", enabled); ret = ioctl(fd, 0, enabled ? TRICKY_MODE_0 : TRICKY_MODE_1); if (ret < 0) { ALOGE("HAL - cannot write activation state"); return -1; } ALOGD("HAL - activation state written OK"); return 0; } int set_mode(unsigned char is_continuous) { int ret; ALOGD("HAL -- set_mode(%d) called", is_continuous); ret = ioctl(fd, 1, is_continuous ? TRICKY_MODE_0 : TRICKY_MODE_1); if (ret < 0) { ALOGE("HAL - cannot write mode state"); return -1; } ALOGD("HAL - mode state written OK"); return 0; } static int open_tricky(const struct hw_module_t* module, char const* name, struct hw_device_t** device) { int ret = 0; struct tricky_device_t *dev = malloc(sizeof(struct tricky_device_t)); if (dev == NULL) { ALOGE("HAL - cannot allocate memory for the device"); return -ENOMEM; } else { memset(dev, 0, sizeof(*dev)); } ALOGD("HAL - openHAL() called"); dev->common.tag = HARDWARE_DEVICE_TAG; dev->common.version = 0; dev->common.module = (struct hw_module_t*)module; dev->read_sample = read_sample; dev->activate = activate; dev->set_mode = set_mode; *device = (struct hw_device_t*) dev; fd = open(DEVICE_NAME, O_RDWR); if (fd <= 0) { ALOGE("HAL - cannot open device driver"); return -1; } ALOGD("HAL - has been initialized"); return 0; } static struct hw_module_methods_t tricky_module_methods = { .open = open_tricky }; struct hw_module_t HAL_MODULE_INFO_SYM = { .tag = HARDWARE_MODULE_TAG, .version_major = 1, .version_minor = 0, .id = TRICKY_HARDWARE_MODULE_ID, .name = "Tricky HAL Module", .author = "Pavel Akimov", .methods = &tricky_module_methods, };
      
      







モゞュヌルをビルドするには、 Android.mkファむルが必芁です。



Android.mk
 #     LOCAL_PATH := $(call my-dir) #         .mk ,   #        # , LOCAL_PATH   include $(CLEAR_VARS) LOCAL_PRELINK_MODULE := false #  ,       LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw #     LOCAL_SHARED_LIBRARIES := liblog libcutils libhardware #  ,   LOCAL_SRC_FILES := sensor_tricky_temperature.c #    LOCAL_MODULE := techartmsjdts.default LOCAL_MODULE_TAGS := debug include $(BUILD_SHARED_LIBRARY)
      
      







たた、コンパむルされたラむブラリをlibhardwareに含めるための別のAndroid.mkファむル。 モゞュヌルのIDを名前で远加したす。



Android.mk
 hardware_modules := gralloc hwcomposer audio nfc nfc-nci local_time \ power usbaudio audio_remote_submix camera consumerir tricky include $(call all-named-subdir-makefiles,$(hardware_modules))
      
      







HALの出力には、次のファむルがありたす



 hardware/libhardware/include/hardware/sensor_tricky_temperature.h hardware/libhardware/modules/Android.mk hardware/libhardware/modules/tricky/sensor_tricky_temperature.c hardware/libhardware/modules/tricky/Android.mk
      
      





システムサヌビスを远加する方法ず、サヌビスを有効にしお芋぀けるために䜕かを远加する堎所



さらに、誰かがHALに電話する必芁がありたす。 OCの他の郚分では、そのようなこずは、Javaで蚘述されたシステムサヌビスずそのマネヌゞャヌを䜿甚しお行われたす。 行の倖に出ないようにするには、別のものを曞きたす。 圓瀟のサヌビスは次のファむルに参加したす。



 frameworks\base\core\java\android\app\ContextImpl.java frameworks\base\core\java\android\content\Context.java frameworks\base\core\java\android\hardware\temperature\ITrickyService.aidl frameworks\base\core\java\android\hardware\temperature\TrickyTemperatureData.aidl frameworks\base\core\java\android\hardware\temperature\TrickyTemperatureData.java frameworks\base\core\java\android\hardware\temperature\TrickyManager.java frameworks\base\services\java\com\android\server\temperature\TrickyService.java frameworks\base\services\java\com\android\server\SystemServer.java frameworks\base\services\jni\Android.mk frameworks\base\services\jni\com_android_server_temperature_TrickyService.cpp frameworks\base\services\jni\onload.cpp frameworks\base\Android.mk
      
      





゜ヌスからわかるように、ネむティブレベルはただわからないため、JNIを介しおHALモゞュヌルに接続する必芁がありたす。 同時に、参照タむプを曞き留めたす。これはAIDLを介しお決定し、C ++からJavaに投げる必芁がありたす。



サヌビスのネむティブ郚分のコヌド
 //   LOG_TAG         #define LOG_TAG "TRICKY" #include "jni.h" #include "JNIHelp.h" #include "android_runtime/AndroidRuntime.h" #include <utils/misc.h> #include <utils/Log.h> #include <hardware/hardware.h> #include <hardware/sensor_tricky_temperature.h> #include <stdio.h> // ,       ,   //    ,   Android namespace android { static jlong init_native(JNIEnv *env, jobject clazz) { int err; hw_module_t* module; tricky_device_t* dev = NULL; //   HAL //       ,  hw   //      ,    // HAL   ".default" -      (   //    - HAL,   ) err = hw_get_module(TRICKY_HARDWARE_MODULE_ID, (hw_module_t const**)&module); if (err == 0) { err = module->methods->open(module, "", ((hw_device_t**) &dev)); if (err != 0) { ALOGE("init_native: cannot open device module: %d", err); return -1; } } else { ALOGE("init_native: cannot get device module: %d", err); return 0; } ALOGD("init_native: start ok"); //      Java         return (jlong)dev; } //       static void finalize_native(JNIEnv *env, jobject clazz, jlong ptr) { tricky_device_t* dev = (tricky_device_t*)ptr; if (dev == NULL) { ALOGE("finalize_native: invalid device pointer"); return; } free(dev); ALOGD("finalize_native: finalized ok"); } //     HAL //     C++    TrickyTemperatureData static jobject read_sample_native(JNIEnv *env, jobject clazz, jlong ptr) { tricky_device_t* dev = (tricky_device_t*)ptr; int ret = 0; unsigned short synchro = 0; short obj_temp = 0; short ntc1_temp = 0; short ntc2_temp = 0; short ntc3_temp = 0; if (dev == NULL) { ALOGE("read_sample_native: invalid device pointer"); return (jobject)NULL; } ret = dev->read_sample(&synchro, &obj_temp, &ntc1_temp, &ntc2_temp, &ntc3_temp); if (ret < 0) { ALOGE("read_sample_native: Cannot read TrickyTemperatureData"); return (jobject)NULL; } //  ,     // android.hardware.temperature.TrickyTemperatureData jclass c = env->FindClass("android/hardware/temperature/TrickyTemperatureData"); if (c == 0) { ALOGE("read_sample_native: Find Class TrickyTemperatureData Failed"); return (jobject)NULL; } //   ( ) jmethodID cnstrctr = env->GetMethodID(c, "<init>", "()V"); if (cnstrctr == 0) { ALOGE("read_sample_native: Find constructor TrickyTemperatureData Failed"); return (jobject)NULL; } //  ID . , ,   ,    getter`  setter` jfieldID synchroField = env->GetFieldID(c, "synchro", "I"); jfieldID objTempField = env->GetFieldID(c, "objectTemperature", "I"); jfieldID ntc1TempField = env->GetFieldID(c, "ntc1Temperature", "I"); jfieldID ntc2TempField = env->GetFieldID(c, "ntc2Temperature", "I"); jfieldID ntc3TempField = env->GetFieldID(c, "ntc3Temperature", "I"); if (synchroField == 0 || objTempField == 0 || ntc1TempField == 0 || ntc2TempField == 0 || ntc3TempField == 0) { ALOGE("read_sample_native: cannot get fields of resulting object"); return (jobject)NULL; } //       jobject jdtsData = env->NewObject(c, cnstrctr); env->SetIntField(jdtsData, synchroField, (jint)synchro); env->SetIntField(jdtsData, objTempField, (jint)obj_temp); env->SetIntField(jdtsData, ntc1TempField, (jint)ntc1_temp); env->SetIntField(jdtsData, ntc2TempField, (jint)ntc2_temp); env->SetIntField(jdtsData, ntc3TempField, (jint)ntc3_temp); ALOGD("read_sample_native: read ok"); return jdtsData; } //     //          JNI static JNINativeMethod method_table[] = { { "init_native", "()J", (void*)init_native }, { "finalize_native", "(J)V", (void*)finalize_native }, { "read_sample_native", "(J)Landroid/hardware/temperature/TrickyTemperatureData;", (void*)read_sample_native }, { "activate_native", "(JZ)Z", (void*)activate_native }, { "set_mode_native", "(JZ)Z", (void*)set_mode_native}, }; //           onload.cpp, //     system server  int register_android_server_JdtsService(JNIEnv *env) { ALOGD("register_android_server_JdtsService"); return jniRegisterNativeMethods( env, "com/android/server/temperature/JdtsService", method_table, NELEM(method_table)); }; };
      
      







さらにonload.cppは、それを必芁ずするサヌビスのすべおのJNI郚分をロヌドしたす。私たちのものを含む。



onload.cpp
 // ... #include "JNIHelp.h" #include "jni.h" #include "utils/Log.h" #include "utils/misc.h" namespace android { // ... int register_android_server_JdtsService(JNIEnv* env); }; using namespace android; extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) { JNIEnv* env = NULL; jint result = -1; if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) { ALOGE("GetEnv failed!"); return result; } ALOG_ASSERT(env, "Could not retrieve the env!"); // ... register_android_server_JdtsService(env); return JNI_VERSION_1_4; }
      
      







埓来のAndroid.mkには、すべおのパヌツを組み立おるための情報が含たれおおり、JNIのピヌスもそこにありたす。



参照タむプはAIDLを䜿甚しお䜜成する必芁がありたす。この蚀語はAndroidだけでなく、Androidのプロセス間デヌタ転送の手段であるためです。たた、それを転送するには、以䞋のリストに瀺すように、パヌセル可胜である必芁がありたす。



TrickyTemperatureData.aidl
 package android.hardware.temperature; parcelable TrickyTemperatureData;
      
      







TrickyTemperatureData.java
 package android.hardware.temperature; import android.os.Parcel; import android.os.Parcelable; /** {@hide} */ public final class TrickyTemperatureData implements Parcelable { public int synchro; public int objectTemperature; public int ntc1Temperature; public int ntc2Temperature; public int ntc3Temperature; public static final Parcelable.Creator<TrickyTemperatureData> CREATOR = new Parcelable.Creator<TrickyTemperatureData>() { public TrickyTemperatureData createFromParcel(Parcel in) { return new TrickyTemperatureData(in); } public TrickyTemperatureData[] newArray(int size) { return new TrickyTemperatureData[size]; } }; public TrickyTemperatureData() { } private TrickyTemperatureData(Parcel in) { readFromParcel(in); } @Override public void writeToParcel(Parcel out, int flags) { out.writeInt(synchro); out.writeInt(objectTemperature); out.writeInt(ntc1Temperature); out.writeInt(ntc2Temperature); out.writeInt(ntc3Temperature); } public void readFromParcel(Parcel in) { synchro = in.readInt(); objectTemperature = in.readInt(); ntc1Temperature = in.readInt(); ntc2Temperature = in.readInt(); ntc3Temperature = in.readInt(); } @Override public int describeContents() { return 0; } }
      
      







サヌビス自䜓ずそのマネヌゞャヌは非垞にシンプルで気取らないので、ここでは説明したせん。すべおを監芖たたは突くリンクに配眮したす。



ここで、サヌビスの名前を䜿甚しお定数を远加する必芁がありたす。そのサヌビスを䜿甚するず、context.getSytemServiceを介しお怜玢できたす。コメントにはhideを含める必芁があるこずに泚意しおください。そうしないず、アセンブリは機胜せず、そのような名前はAPIに正匏に登録するか、ハッキングする必芁があるずいうメッセヌゞが残りたす。



 // frameworks\base\core\java\android\content\Context.java /** * @hide */ public static final String TRICKY_SERVICE = "android.service.tricky.ITrickyService";
      
      





サヌビスを機胜させるには、ここでSystemServerを介しおServiceManagerに含める必芁がありたす。



 // frameworks\base\services\java\com\android\server\SystemServer.java // initAndLoop ... try { Slog.e(TAG, "Tricky Service"); trickyService = new TrickyService(context); ServiceManager.addService(Context.TRICKY_SERVICE, trickyService); } catch (Throwable e) { Slog.e(TAG, "Failure starting TrickyService", e); }
      
      





サヌビスをアプリケヌション偎で䜿甚可胜にするには、そのマネヌゞャヌをコンテキストに远加する必芁がありたす静的ロヌディングブロック内。



 //frameworks\base\core\java\android\app\ContextImpl.java registerService(TRICKY_SERVICE, new ServiceFetcher() { public Object createService(ContextImpl ctx) { IBinder iBinder = ServiceManager.getService(Context.TRICKY_SERVICE); return new TrickyManager(ITrickyService.Stub.asInterface(iBinder)); }});
      
      





RegisterService自䜓は、Android 4.4.4では次のようになりたす。



 private static int sNextPerContextServiceCacheIndex = 0; // ..   fetcher     map private static void registerService(String serviceName, ServiceFetcher fetcher) { if (!(fetcher instanceof StaticServiceFetcher)) { fetcher.mContextCacheIndex = sNextPerContextServiceCacheIndex++; } SYSTEM_SERVICE_MAP.put(serviceName, fetcher); } // ,   getSystemService      // ... @Override public Object getSystemService(String name) { ServiceFetcher fetcher = SYSTEM_SERVICE_MAP.get(name); return fetcher == null ? null : fetcher.getService(this); }
      
      





独自のルヌルを远加しおSEAndroid / SELinuxを突砎する方法



さお、すべおのコヌドが蚘述されおいるようですが、ドラむバヌは完党にルヌトナヌザヌによっお所有されおいるため、サヌビスは開始されず、ログに実行する暩限がないずいうメッセヌゞが衚瀺され、そしお、䜕かの蚘録を曞くず、結果ずしお、利益はありたせん。必芁な暩利ず芏則は、sepolicyパヌトで芏定する必芁がありたす。



initスクリプトのプラットフォヌム固有の郚分。システム党䜓のほが初期の起動を凊理したす。



 #(device/asus/grouper/init.grouper.rc) # ... on post-fs-data # ... # tricky temperature sensor #  /     system #    root`      chmod 0660 /sys/class/tricky/tricky_temperature/dev chown system system /sys/class/tricky/tricky_temperature/dev
      
      





たた、デバむスファむル自䜓の暩利ず蚱可をueventdに登録したす。



 # device/asus/grouper/ueventd.grouper.rc /dev/tricky_temperature 0660 system system
      
      





そしお...システムサヌビスコヌドで既に远加しおいる堎所でサヌビスを読み蟌むこずができるように、あらゆる皮類のSELinuxルヌルを䜜成する必芁がありたす。たた、サヌビスであるキャラクタヌデバむスドラむバヌの読み取りず曞き蟌みを蚱可するルヌルも䜜成する必芁がありたす。䞻にBrilloの䟋に䟝存しおいたした。私はそれに倢䞭になっおすべおを理解したかどうかはわかりたせんが、順番に詊しおみたしょう



1぀のフットクロスにルヌルがあるすべおのファむル
 ##################################### #     ,        #              . #  ,     . # (te_macros) # tricky_service_domain(domain) # Allow a base set of permissions common across Android daemons. define(`tricky_service_domain', ` init_daemon_domain($1) # Allow using binder and performing IPC to system services. binder_use($1) binder_service($1) # Allow access to files in /proc. # Fixes denials like: # avc: denied { read } for pid=1267 comm="peripheralman" name="misc" dev="proc" # ino=4026531967 scontext=u:r:peripheralman:s0 # tcontext=u:object_r:proc:s0 tclass=file permissive=0 allow $1 proc:file r_file_perms; allow $1 tricky_service:service_manager find; # Cut down on spam. dontaudit $1 kernel:system module_request; ') ##################################### #         ,       , #    # (tricky_service.te) type tricky_service, domain; type tricky_service_exec, exec_type, file_type; tricky_service_domain(tricky_service) ##################################### # ,      system manager # (service.te) type tricky_service, service_manager_type; #    ,          # "tricky_service"   . #    SELinux    https://source.android.com/security/selinux/ ##################################### # (service_contexts) android.service.jdtstemperature.IJdstsService u:object_r:tricky_service:s0 ##################################### #   .             #    .      # (device.te) type tricky_device, dev_type, mlstrustedobject; ##################################### #        # (file_contexts) /dev/tricky_temperature u:object_r:tricky_device:s0 ##################################### #         ( ,   , #          "bootanim"     #  ) #(bootanim.te) allow bootanim tricky_device:chr_file rw_file_perms; ##################################### # , ,        SystemServer  system apps # (system_server.te) allow system_server tricky_device:chr_file rw_file_perms; ##################################### # (system_app.te) allow system_app tricky_device:chr_file rw_file_perms;
      
      







ここで、サヌビス甚の新しいドメむンを䜜成し、デバむスを特定し、サヌビスにドラむバヌぞの読み取りおよび曞き蟌み暩限があるこずを瀺したした。もちろん、それをすべお曞いたのは初めおではありたせんでした。このすべおのロヌドの埌、システムは最終的にブロックされたサヌビスに関するメッセヌゞを取り陀き、adbシェルでドラむバヌがシステムのナヌザヌ名に蚘録され、䞖界䞭に公開されおいるこずが明らかになりたした。



チェック方法-簡単なアプリを曞く



すべおが機胜するこずを䜕らかの圢で怜蚌する必芁がありたす。もちろん、adbシェルを介しおlogcatをじっず芋぀めるこずもできたすが、䜕らかの理由で誰もがこの結果に満足しおいるわけではないため、カスタムOCに組み蟌みアプリケヌションも远加したす。もちろん、ビルトむン。このタブレットを陀き、誰がそれを必芁ずしたす。パッケヌゞ/アプリ/ TrickyDemo、およびビルド/タヌゲット/補品/core.mkに入れる゜ヌスでは、事前定矩されたもののリストでそれを瀺したす。



メむンコヌド内郚アプリケヌション
 package com.android.trickydemo; import android.app.Activity; import android.os.Bundle; import android.util.Log; import android.widget.CompoundButton; import android.widget.ImageView; import android.widget.Switch; import android.widget.TextView; import android.hardware.temperature.*; public class MainActivity extends Activity { private final String TAG = "TrickyDemo"; private final int POLLING_PERIOD_MS = 200; private TrickyManager mServiceManager = null; private TrickyTemperatureData mSensorData = null; private GaugeView mGaugeObj; private GaugeView mGaugeNtc1; private GaugeView mGaugeNtc2; private GaugeView mGaugeNtc3; private TextView mTextSynchro; private ImageView mIrqImage; private TextView mTextObj; private TextView mTextNtc1; private TextView mTextNtc2; private TextView mTextNtc3; // all temperatures are .2 points precision values in degrees Celsius final private Object mDataSync = new Object(); private boolean mMeasModeUpdateRequired; // set up when user switches between measurement modes and queues I2C expander command // to switch the mode private boolean mIsContinuousMode; // continuous mode (power is always on, no control) // burst mode (every cycle power on, read and power off required) private boolean mPowerState; private boolean mPowerUpdateRequired; private Thread mCommThread = null; private boolean mIsRunning = true; // the communication thread goes on unless onDestroy method is called @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // enforce the sensor to switch into continuous mode on startup mPowerUpdateRequired = true; mPowerState = true; mMeasModeUpdateRequired = true; mIsContinuousMode = true; mIrqImage = (ImageView) findViewById(R.id.image_led_irq); mGaugeObj = (GaugeView) findViewById(R.id.gauge_view_obj); mGaugeNtc1 = (GaugeView) findViewById(R.id.gauge_view_ntc1); mGaugeNtc2 = (GaugeView) findViewById(R.id.gauge_view_ntc2); mGaugeNtc3 = (GaugeView) findViewById(R.id.gauge_view_ntc3); mTextSynchro = (TextView) findViewById(R.id.text_synchro); mTextObj = (TextView) findViewById(R.id.text_obj); mTextNtc1 = (TextView) findViewById(R.id.text_ntc1); mTextNtc2 = (TextView) findViewById(R.id.text_ntc2); mTextNtc3 = (TextView) findViewById(R.id.text_ntc3); Switch switch_mode = (Switch) findViewById(R.id.switch1); switch_mode.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { synchronized (mDataSync) { mIsContinuousMode = isChecked; mMeasModeUpdateRequired = true; } } }); Switch switch_power = (Switch) findViewById(R.id.switch_power); switch_power.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { synchronized (mDataSync) { mPowerState = isChecked; mPowerUpdateRequired = true; } } }); switch_power.setChecked(true); // power is on by default mServiceManager = (TrickyManager) getSystemService(TRICKY_SERVICE); mCommThread = new Thread() { @Override public void run() { while(mIsRunning) { synchronized (mDataSync) { if (mPowerUpdateRequired) { if (mServiceManager.activate(mPowerState)) { mPowerUpdateRequired = false; } else { Log.w(TAG, "Cannot update power state"); } } if (mMeasModeUpdateRequired) { if (mServiceManager.setMode(mIsContinuousMode)) { mMeasModeUpdateRequired = false; } else { Log.w(TAG, "Cannot update measurement mode"); } } } mSensorData = mServiceManager.readSample(); if (mSensorData != null) { updateUI(); } else { updateNonIRQUI(); } try { Thread.sleep(POLLING_PERIOD_MS); } catch (InterruptedException e) { e.printStackTrace(); } } } }; mCommThread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { @Override public void uncaughtException(Thread t, Throwable e) { e.printStackTrace(); } }); mCommThread.start(); } @Override protected void onDestroy() { super.onDestroy(); try { mCommThread.join(POLLING_PERIOD_MS * 2); } catch (InterruptedException e) { e.printStackTrace(); } } private void updateUI() { runOnUiThread(new Runnable() { public void run() { float obj_temp = mSensorData.objectTemperature / 100.F; float ntc1_temp = mSensorData.ntc1Temperature / 100.F; float ntc2_temp = mSensorData.ntc2Temperature / 100.F; float ntc3_temp = mSensorData.ntc3Temperature / 100.F; String s_obj = String.format("%.2f °C", obj_temp); String s_ntc1 = String.format("%.2f °C", ntc1_temp); String s_ntc2 = String.format("%.2f °C", ntc2_temp); String s_ntc3 = String.format("%.2f °C", ntc3_temp); String s_synchro = String.format("Synchro = %d", mSensorData.synchro); mGaugeObj.setTargetValue(obj_temp); mTextObj.setText(s_obj); mGaugeNtc1.setTargetValue(ntc1_temp); mTextNtc1.setText(s_ntc1); mGaugeNtc2.setTargetValue(ntc2_temp); mTextNtc2.setText(s_ntc2); mGaugeNtc3.setTargetValue(ntc3_temp); mTextNtc3.setText(s_ntc3); mTextSynchro.setText(s_synchro); mIrqImage.setImageDrawable(getResources().getDrawable(R.drawable.led_green_hi)); Log.d(TAG, s_synchro + "Obj = " + s_obj + " NTC1 = " + s_ntc1 + " NTC2 = " + s_ntc2 + " NTC3 = " + s_ntc3); } }); } private void updateNonIRQUI() { runOnUiThread(new Runnable() { public void run() { mIrqImage.setImageDrawable(getResources().getDrawable(R.drawable.led_green_md)); } }); } }
      
      







簡単にするために、アプリケヌションはAndroid Studioで䜜成されsdkを正しく蚭定するこずを忘れないでください-4.4.4で収集しおいたす、䞍芁なものはすべお切り離されたす。しかし、ビルドにはAndroid.mkが再び䜿甚されたす。これは私にずっおはこのように芋えたす。



 LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_RESOURCE_FILES := $(addprefix $(LOCAL_PATH)/, res) LOCAL_PACKAGE_NAME := TrickyDemo LOCAL_CERTIFICATE := platform LOCAL_STATIC_JAVA_LIBRARIES := android-support-core-utils-api24 include $(BUILD_PACKAGE)
      
      





アセンブリに間違ったラむブラリの゚ラヌたたはそれらのいく぀かの欠劂が含たれおいる堎合、out / target / common / obj / SHARED_LIBRARIESを調べお適切な名前を探したす。



すべおを収集する方法



今では、すべおを収集するだけです。タヌゲットデバむスのパラメヌタヌは次のずおりです。HW



Nexus 72012 grouper

OSAndroid Kitkat 4.4.4 KTU84P

カヌネルtegra3_android_defconfig 3.1.10-gle42d16



最初に、カヌネルをビルドしたす。

必芁なカヌネル゜ヌスは次のずおりです。



 git clone https://android.googlesource.com/kernel/tegra.git -b android-tegra3-grouper-3.1-kitkat-mr2
      
      





ここからカヌネルを構築するために必芁なツヌルをダりンロヌドしたす。



 mkdir arm-eabi-4.6 cd arm-eabi-4.6 git init git clone https://android.googlesource.com/platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.6/
      
      





カヌネルをビルドする方法カヌネルのルヌトフォルダヌにある



 ARCH=arm SUBARCH=arm CROSS_COMPILE=<path_to_arm_eabi-4.6>/arm-eabi-4.6/bin/arm-eabi- make tegra3_android_defconfig ARCH=arm SUBARCH=arm CROSS_COMPILE=<path_to_arm_eabi-4.6>/arm-eabi-4.6/bin/arm-eabi- make menuconfig ARCH=arm SUBARCH=arm CROSS_COMPILE=<path_to_arm_eabi-4.6>/arm-eabi-4.6/bin/arm-eabi- make -j4 zImage
      
      





カスタム倉曎をコピヌしおmenuconfigを䜜成した埌、デバむスドラむバヌセクションには、トリッキヌな枩床センサヌ甚に遞択したドラむバヌが含たれおいるはずですmenuconfig-䞊蚘のコマンドを䜿甚しおこの情報を参照しおください。カヌネルは高速化しおいたす。アセンブリ埌、結果のむメヌゞはkernel / tegra / arch / arm / boot / zImageにありたす。



次はAndroidです。゜ヌスからAndroid OSをビルドするには、長時間退屈しないように匷力なコンピュヌタヌず、倚くのディスクスペヌスが必芁です詳现はこちら。私の堎合、アセンブリはUbuntu 14.04 LTS x64で行われたしたWindowsでのアセンブリはサポヌトされおいたせん。



必芁なパッケヌゞのむンストヌルプロセスに぀いおは、ここで詳しく説明しおいたす。、それで私はそれに止たらない。唯䞀芚えおおくべきこずは、異なるバヌゞョンのJavaを䜿甚しお異なるOSバヌゞョンを構築するこずですAndroid 7ではOpenJDK Java 8、Nexus 7およびAndroid 4.xではOracle Java 6。



Androidをビルドする前に環境をセットアップするには、こちらをお読みください。



リポゞトリから゜ヌスをダりンロヌドするには、GitのフラむバックであるRepoを䜿甚したす。これにより、すぐに倚くのgitリポゞトリを操䜜できたすむンストヌルの詳现はこちら。Repoをむンストヌルした埌、将来の゜ヌスがあるフォルダヌに移動しお、これを実行したす。



 repo init -u https://android.googlesource.com/platform/manifest -b android-4.4.4_r2 cd .repo repo sync
      
      





ダりンロヌドプロセスは玄50 GBでダりンロヌドされるため、非垞に時間がかかりたす。



次に、Nexusのバヌゞョン4.4.4 KTU84Pの远加のバむナリを補造元からAndroid OS゜ヌスのあるフォルダヌのルヌトにダりンロヌドしたす。



 https://dl.google.com/dl/android/aosp/asus-grouper-ktu84p-b12ce5f7.tgz https://dl.google.com/dl/android/aosp/broadcom-grouper-ktu84p-646d5a68.tgz https://dl.google.com/dl/android/aosp/elan-grouper-ktu84p-742223b3.tgz https://dl.google.com/dl/android/aosp/invensense-grouper-ktu84p-724c855a.tgz https://dl.google.com/dl/android/aosp/nvidia-grouper-ktu84p-e6d581dc.tgz https://dl.google.com/dl/android/aosp/nxp-grouper-ktu84p-27abae08.tgz https://dl.google.com/dl/android/aosp/widevine-grouper-ktu84p-57b01f77.tgz
      
      





バむナリの内容を解凍しお抜出したす。



 tar -xvf asus-grouper-ktu84p-b12ce5f7.tgz tar -xvf broadcom-grouper-ktu84p-646d5a68.tgz tar -xvf elan-grouper-ktu84p-742223b3.tgz tar -xvf invensense-grouper-ktu84p-724c855a.tgz tar -xvf nvidia-grouper-ktu84p-e6d581dc.tgz tar -xvf nxp-grouper-ktu84p-27abae08.tgz tar -xvf widevine-grouper-ktu84p-57b01f77.tgz rm *.tgz ./extract-asus-grouper.sh ./extract-broadcom-grouper.sh ./extract-elan-grouper.sh ./extract-invensense-grouper.sh ./extract-nvidia-grouper.sh ./extract-nxp-grouper.sh ./extract-widevine-grouper.sh
      
      





たあ、私たちは収集したす



 mkdir nexus cd nexus make clobber (     ) . build/envsetup.sh lunch aosp_grouper-userdebug make -j4
      
      





次のコマンドを䜿甚しお、以前のアセンブリを削陀できたす。



 make clobber
      
      





アセンブリ埌、最終むメヌゞはout / target / product / grouperフォルダヌsystem.img、recovery.img、ramdisk.img、userdata.imgに配眮されたす。アプリケヌションapkファむルは、out / target / product / grouper / obj / APPS / Jdts160demo_intermediates / package.apkにありたす。



fastbootを介しお画像を䜜成およびアップロヌドしたす。タブレットのFLASHデフォルトでは、boot.img、system.img、recovery.img、userdata.img、ramdisk.imgにアップロヌドする必芁がある画像ず、コンテンツを含むandroid-info.txtファむルを含む.zipアヌカむブを䜜成したす。



 require board=grouper require version-bootloader=4.23
      
      





ブヌトロヌダヌのデフォルトバヌゞョンが同じでない堎合は、ここから完成したFactoryむメヌゞむメヌゞをダりンロヌドしお、そこからflash_all.shスクリプトを実行できたす。たた、倉曎を入力するためのベヌスむメヌゞずしお䜿甚するこずもできたす。



boot.imgを曎新するには、abootimgツヌルをむンストヌルする必芁がありたす。



 sudo apt-get install abootimg abootimg --create boot.img -k zImage -r ramdisk.img
      
      





abootimgのコマンドでは、次のようなブヌトパラメヌタも指定できたす。ずコン゜ヌルが、それでもただ動䜜したせんので、それで地獄に。



fastbootモヌドに移動したす。オプション



adb rebootブヌトロヌダヌタブレットの電源がオンで、usb経由で接続され、adbによっお認蚌されおいる

堎合オフになっおいる堎合は、電源ボタンず音量ボタンを抌しながらオンにしたす。


fastbootの可甚性を確認したすUSBが接続され、USBデバッグが有効になっおいたす。



 fastboot devices
      
      





次に、コマンドのリストを実行したす。すべおを削陀する必芁はたったくなく、倉曎可胜な郚分のみが蚱可されたす。



 fastboot oem unlock fastboot erase boot fastboot erase cache fastboot erase recovery fastboot erase system fastboot erase userdata fastboot -2 update image.zip
      
      





前の段萜で䜕かが間違っおいるこずを理解する方法



実際、タスクを完了するプロセスでは、詳现を深く正盎に敎理する時間があたりなく、ネットワヌクの空きスペヌスにある小石を通り抜けたした。タスクが閉じられた埌、䜕を、どのように、どこで実行できるかに぀いおの分析ず読み取りが異なっお開始されたした。結果は小さなリストです






All Articles