日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

安卓9.0马达框架分析

發布時間:2023/12/20 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 安卓9.0马达框架分析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前言

最近需要將之前的一些驅動接口轉為安卓標準接口,方便上層應用或者第三方應用去適配。這篇文章先從簡單的馬達框架入手進行講解。

正文

整個馬達框架比較簡單,安卓官方已經幫我們實現了framework到HAL層,我們需要實現的就只有驅動層。這篇文章我們梳理一下從上層到底層怎么流程。

1、APP層

import android.os.Vibrator; import android.widget.ToggleButton;public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main);private Vibrator vibrator=null; vibrator=(Vibrator)this.getSystemService(VIBRATOR_SERVICE); toggleButton1=(ToggleButton)findViewById(R.id.toggleButton1); /*短震動*/ toggleButton1.setOnCheckedChangeListener(new ToggleButton.OnCheckedChangeListener() {@Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { if(isChecked){Log.i(TAG,"toggleButton1 enter vibrator.vibrate"); //設置震動周期,第二個參數為 -1表示只震動一次 vibrator.vibrate(new long[]{1000, 10, 100, 1000},-1); }else{ //取消震動Log.i(TAG,"toggleButton1 enter vibrator.cancel()"); vibrator.cancel(); } } }); } }

上面展示了一個最簡單的馬達震動應用代碼,獲得服務后即可調用接口進行驅動。

2、framework層

代碼路徑:frameworks\base\services\core\java\com\android\server\VibratorService.java

? @Override // Binder callpublic void vibrate(int uid, String opPkg, VibrationEffect effect, int usageHint,IBinder token) {Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "vibrate");try {if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.VIBRATE)!= PackageManager.PERMISSION_GRANTED) {throw new SecurityException("Requires VIBRATE permission");}if (token == null) {Slog.e(TAG, "token must not be null");return;}verifyIncomingUid(uid);if (!verifyVibrationEffect(effect)) {return;}// If our current vibration is longer than the new vibration and is the same amplitude,// then just let the current one finish.synchronized (mLock) {if (effect instanceof VibrationEffect.OneShot&& mCurrentVibration != null&& mCurrentVibration.effect instanceof VibrationEffect.OneShot) {VibrationEffect.OneShot newOneShot = (VibrationEffect.OneShot) effect;VibrationEffect.OneShot currentOneShot =(VibrationEffect.OneShot) mCurrentVibration.effect;if (mCurrentVibration.hasTimeoutLongerThan(newOneShot.getDuration())&& newOneShot.getAmplitude() == currentOneShot.getAmplitude()) {if (DEBUG) {Slog.d(TAG,"Ignoring incoming vibration in favor of current vibration");}return;}}// If the current vibration is repeating and the incoming one is non-repeating,// then ignore the non-repeating vibration. This is so that we don't cancel// vibrations that are meant to grab the attention of the user, like ringtones and// alarms, in favor of one-shot vibrations that are likely quite short.if (!isRepeatingVibration(effect)&& mCurrentVibration != null&& isRepeatingVibration(mCurrentVibration.effect)) {if (DEBUG) {Slog.d(TAG, "Ignoring incoming vibration in favor of alarm vibration");}return;}Vibration vib = new Vibration(token, effect, usageHint, uid, opPkg);linkVibration(vib);long ident = Binder.clearCallingIdentity();try {doCancelVibrateLocked();startVibrationLocked(vib);addToPreviousVibrationsLocked(vib);} finally {Binder.restoreCallingIdentity(ident);}}} finally {Trace.traceEnd(Trace.TRACE_TAG_VIBRATOR);}}

接口里面會判斷一下權限,根據應用層傳遞的不同effect值,有不同的震動效果。然后就調用到JNI層,調用順序大概如下:

startVibrationLocked startVibrationInnerLocked doVibratorOn vibratorOn

3、JNI層

代碼路徑:frameworks\base\services\core\jni\com_android_server_VibratorService.cpp

static void vibratorOn(JNIEnv* /* env */, jobject /* clazz */, jlong timeout_ms) {Status retStatus = halCall(&V1_0::IVibrator::on, timeout_ms).withDefault(Status::UNKNOWN_ERROR);if (retStatus != Status::OK) {ALOGE("vibratorOn command failed (%" PRIu32 ").", static_cast<uint32_t>(retStatus));} }static void vibratorOff(JNIEnv* /* env */, jobject /* clazz */) {Status retStatus = halCall(&V1_0::IVibrator::off).withDefault(Status::UNKNOWN_ERROR);if (retStatus != Status::OK) {ALOGE("vibratorOff command failed (%" PRIu32 ").", static_cast<uint32_t>(retStatus));} }static const JNINativeMethod method_table[] = {{ "vibratorExists", "()Z", (void*)vibratorExists },{ "vibratorInit", "()V", (void*)vibratorInit },{ "vibratorOn", "(J)V", (void*)vibratorOn },{ "vibratorOff", "()V", (void*)vibratorOff },{ "vibratorSupportsAmplitudeControl", "()Z", (void*)vibratorSupportsAmplitudeControl},{ "vibratorSetAmplitude", "(I)V", (void*)vibratorSetAmplitude},{ "vibratorPerformEffect", "(JJ)J", (void*)vibratorPerformEffect} };int register_android_server_VibratorService(JNIEnv *env) {return jniRegisterNativeMethods(env, "com/android/server/VibratorService",method_table, NELEM(method_table)); }

以馬達的On和off為例,會調用到HAL層的on和off方法。

4、HIDL層

代碼路徑:hardware\interfaces\vibrator\1.0\default\Vibrator.cpp

Return<Status> Vibrator::on(uint32_t timeout_ms) {int32_t ret = mDevice->vibrator_on(mDevice, timeout_ms);if (ret != 0) {ALOGE("on command failed : %s", strerror(-ret));return Status::UNKNOWN_ERROR;}return Status::OK; }Return<Status> Vibrator::off() {int32_t ret = mDevice->vibrator_off(mDevice);if (ret != 0) {ALOGE("off command failed : %s", strerror(-ret));return Status::UNKNOWN_ERROR;}return Status::OK; }

HIDL層是較新的安卓版本才引入的,是連接HAL層和JNI層的橋梁。

5、HAL層

代碼路徑:hardware\libhardware\modules\vibrator\vibrator.c

static const char THE_DEVICE[] = "/sys/class/timed_output/vibrator/enable";static int sendit(unsigned int timeout_ms) {char value[TIMEOUT_STR_LEN]; /* large enough for millions of years */snprintf(value, sizeof(value), "%u", timeout_ms);return write_value(THE_DEVICE, value); }static int vibra_on(vibrator_device_t* vibradev __unused, unsigned int timeout_ms) {/* constant on, up to maximum allowed time */return sendit(timeout_ms); }static int vibra_off(vibrator_device_t* vibradev __unused) {return sendit(0); }static int vibra_open(const hw_module_t* module, const char* id __unused,hw_device_t** device __unused) {bool use_led;if (vibra_exists()) {ALOGD("Vibrator using timed_output");use_led = false;} else if (vibra_led_exists()) {ALOGD("Vibrator using LED trigger");use_led = true;} else {ALOGE("Vibrator device does not exist. Cannot start vibrator");return -ENODEV;}vibrator_device_t *vibradev = calloc(1, sizeof(vibrator_device_t));if (!vibradev) {ALOGE("Can not allocate memory for the vibrator device");return -ENOMEM;}vibradev->common.tag = HARDWARE_DEVICE_TAG;vibradev->common.module = (hw_module_t *) module;vibradev->common.version = HARDWARE_DEVICE_API_VERSION(1,0);vibradev->common.close = vibra_close;if (use_led) {vibradev->vibrator_on = vibra_led_on;vibradev->vibrator_off = vibra_led_off;} else {vibradev->vibrator_on = vibra_on;vibradev->vibrator_off = vibra_off;}*device = (hw_device_t *) vibradev;return 0; }

其實開啟和關閉馬達的工作很簡單,就是往節點"/sys/class/timed_output/vibrator/enable"寫入震動時間,所以可以想得到驅動層只需要提供一個節點供上層操作就好。

6、驅動層

馬達的驅動是基于kernel提供的timed_output框架完成的:

代碼路徑:kernel-4.4\drivers\staging\android\timed_output.c

代碼比較簡單,提供接口給驅動在"/sys/class/timed_output/"路徑下面建立自己的節點,并提供節點的device attribute的操作接口,當我們寫節點的時候就會調用到enable_store函數,并調用注冊驅動的enable函數。

static struct class *timed_output_class;static ssize_t enable_store(struct device *dev, struct device_attribute *attr,const char *buf, size_t size) { struct timed_output_dev *tdev = dev_get_drvdata(dev); int value; int rc;rc = kstrtoint(buf, 0, &value); if (rc != 0) return -EINVAL;tdev->enable(tdev, value);return size; } static DEVICE_ATTR_RW(enable);static struct attribute *timed_output_attrs[] = { &dev_attr_enable.attr, NULL, }; ATTRIBUTE_GROUPS(timed_output);static int create_timed_output_class(void) { if (!timed_output_class) { timed_output_class = class_create(THIS_MODULE, "timed_output"); if (IS_ERR(timed_output_class)) return PTR_ERR(timed_output_class); atomic_set(&device_count, 0); timed_output_class->dev_groups = timed_output_groups; }return 0; }int timed_output_dev_register(struct timed_output_dev *tdev) { int ret;if (!tdev || !tdev->name || !tdev->enable || !tdev->get_time) return -EINVAL;ret = create_timed_output_class(); if (ret < 0) return ret;tdev->index = atomic_inc_return(&device_count); tdev->dev = device_create(timed_output_class, NULL, MKDEV(0, tdev->index), NULL, "%s", tdev->name); if (IS_ERR(tdev->dev)) return PTR_ERR(tdev->dev);dev_set_drvdata(tdev->dev, tdev); tdev->state = 0; return 0; }

現在我們看一下基于上面框架書寫的馬達驅動:

static void vibrator_off(void) { gpio_direction_output(gpio, !en_value); ? ? ? wake_unlock(&vibdata.wklock); //震動關閉就可以釋放 wake_lock鎖 ? ? ? ? }void motor_enable(struct timed_output_dev *sdev,int value) { mutex_lock(&vibdata.lock); //關鍵代碼段,同一時間只允許一個線程執行/* cancelprevious timer and set GPIO according to value */ hrtimer_cancel(&vibdata.timer); //當先前定時器完成后 關閉這個定時器 cancel_work_sync(&vibdata.work); //當上次震動完成后 關閉這次動作 if(value) { wake_lock(&vibdata.wklock); //開始震動打開wake lock鎖不允許休眠 gpio_direction_output(gpio, en_value);if(value > 0) { if(value > MAX_TIMEOUT) value= MAX_TIMEOUT; hrtimer_start(&vibdata.timer,ktime_set(value / 1000, (value % 1000) * 1000000),HRTIMER_MODE_REL); } } else vibrator_off();mutex_unlock(&vibdata.lock); }struct timed_output_dev motot_driver = { .name ="vibrator", //注意這個名字,由于HAL層里面的設備為//"/sys/class/timed_output/vibrator/enable"//因此這個名字必須為"vibrator" .enable= motor_enable, .get_time= get_time, };static enum hrtimer_restart vibrator_timer_func(struct hrtimer *timer) //定時器結束時候的回調函數 { schedule_work(&vibdata.work); //定時器完成了 執行work隊列回調函數來關閉電機 return HRTIMER_NORESTART; } static void vibrator_work(struct work_struct *work) { vibrator_off(); }static int motor_probe(struct platform_device *pdev) { struct device_node *node = pdev->dev.of_node; enum of_gpio_flags flags; int ret =0;hrtimer_init(&vibdata.timer,CLOCK_MONOTONIC, HRTIMER_MODE_REL); vibdata.timer.function= vibrator_timer_func; INIT_WORK(&vibdata.work,vibrator_work);...ret=timed_output_dev_register(&motot_driver); if (ret< 0) goto err_to_dev_reg; return 0;err_to_dev_reg: mutex_destroy(&vibdata.lock); wake_lock_destroy(&vibdata.wklock);printk("vibrator ? err!:%d\n",ret); return ret;}

1、 驅動接收上層傳遞過來的是震動時長,單位為毫秒。在驅動里注冊一個定時器,定時器倒計時到期后會喚醒注冊的工作隊列,最終會執行vibrator_work()函數去關閉馬達震動。

2、調用timed_output框架提供的timed_output_dev_register()接口將我們的馬達驅動注冊進系統,這里的關鍵就是我們需要自定義struct timed_output_dev結構體,填充enable和get_time函數。enable函數用來開啟馬達的震動:

void motor_enable(struct timed_output_dev *sdev,int value) { mutex_lock(&vibdata.lock); //關鍵代碼段,同一時間只允許一個線程執行/* cancelprevious timer and set GPIO according to value */ hrtimer_cancel(&vibdata.timer); //當先前定時器完成后 關閉這個定時器 cancel_work_sync(&vibdata.work); //當上次震動完成后 關閉這次動作 if(value) { wake_lock(&vibdata.wklock); //開始震動打開wake lock鎖不允許休眠 gpio_direction_output(gpio, en_value);if(value > 0) { if(value > MAX_TIMEOUT) value= MAX_TIMEOUT; hrtimer_start(&vibdata.timer,ktime_set(value / 1000, (value % 1000) * 1000000),HRTIMER_MODE_REL); } } else vibrator_off();mutex_unlock(&vibdata.lock); }

開啟震動的操作也很簡單,只是寫一下GPIO,然后重新開啟定時器,倒計時的時間就是寫入節點的值,到時間再把馬達關閉就好。

參考鏈接

https://blog.csdn.net/qq_34211365/article/details/105556842

嵌入式Linux

微信掃描二維碼,關注我的公眾號

總結

以上是生活随笔為你收集整理的安卓9.0马达框架分析的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 香蕉成人在线视频 | 操在线视频 | 国产二区自拍 | 亚洲天堂2016 | 天天操夜夜操夜夜操 | 在线观看中文字幕视频 | 国产麻豆剧传媒精品国产 | 国产精品伦理一区二区 | www.久久久久久 | 欧美一卡二卡在线 | 久久精品蜜桃 | 亚洲综合p | 免费看日批 | 婷婷久久精品 | 综合性色 | 天天操天| 黄色的网站免费看 | 老司机在线永久免费观看 | 国产精品视频网 | 在线观看va | 日韩欧美国产一区二区三区 | 日韩在线国产 | 日韩综合一区二区三区 | 国产美女引诱水电工 | 森林影视官网在线观看 | 国产男女裸体做爰爽爽 | 97人妻精品一区二区三区免 | 在线观看少妇 | 在线免费看av片 | 91亚洲精品久久久蜜桃网站 | 欧美一级片在线看 | 男女视频在线免费观看 | 天天看片天天操 | 国产夜夜操| 国产乱码一区二区 | 国产123| 亚洲av男人的天堂在线观看 | 91调教打屁股xxxx网站 | 国产精品1区2区 | 综合久久一区 | 国产黄色片在线观看 | 一区二视频 | 午夜国产福利在线观看 | 成年午夜视频 | 日本大尺度床戏揉捏胸 | 体内精69xxxxxx | 国产激情小视频 | 在线观看麻豆 | 500福利视频导航 | 97久久超碰| 五月婷婷激情小说 | 久久久久久成人精品 | 你懂的国产视频 | 国产毛片视频 | 在线免费观看福利 | se在线观看 | 欧美一级鲁丝片 | 91香蕉国产 | 欧美美女色图 | 麻豆传媒一区二区 | 欧美精品一级二级三级 | 国产精品刘玥久久一区 | 亚洲第一页乱 | 青青草原综合久久大伊人精品 | 19韩国主播青草vip | 国产乱淫a∨片免费观看 | 亚洲综合99 | 欧美系列一区二区 | 人人看av| 欧美精品一区二区在线观看 | 久久久久久免费视频 | 国产极品视频 | 成人黄色一级 | www.av在线免费观看 | 乱h伦h女h在线视频 99999视频 | 免费观看一区二区 | www免费黄色 | 欧美精品在线免费观看 | 夜夜操av| 丝袜 亚洲 另类 国产 制服 | av在线精品| 久草精品视频在线观看 | 国产成人短视频在线观看 | 亚洲一区中文 | 久久久久久国产精品免费免费 | 91中文 | 91污网站 | 欧美综合激情网 | 国产91在线免费观看 | 麻豆成人91精品二区三区 | 91桃色视频在线观看 | 久久久av一区二区三区 | 亚洲精品国产精品国自产观看浪潮 | av 日韩 人妻 黑人 综合 无码 | 91九色偷拍| 久久久国产免费 | 国产第113页 | 手机av在线免费 | 一二区在线观看 |