【安卓Android】VibratorService分析

【安卓Android】VibratorService分析,第1张

前言

本文所有源码均是基于安卓8.0进行分析的,安卓12对振动服务做了比较多的变动。

本文适合阅读的人群为:3-5年开发经验,有一定系统源码阅读经历的人。

安卓开发做久了,经常觉得一切都理所当然。这导致我们遇到问题时,不能很理解本质,所以我们很有必要分析系统的源码。
本文侧重调用流程,不侧重具体的实现。
如果读者对硬件实现和粗略流程感兴趣,可以分别读以下两个文章:
粗略流程
硬件实现

分析 我们先来看看安卓设备上振动的基本使用方式
Vibrator vibrator = (Vibrator)this.getSystemService(this.VIBRATOR_SERVICE);
vibrator.vibrate(1000);//振动一下

long[] patter = {1000, 1000, 2000, 50};
vibrator.vibrate(patter, 0);//有不同幅度的振动

vibrator.cancel();//取消振动

首先 getSystemService(this.VIBRATOR_SERVICE) 相信各位做了这么久的安卓开发,肯定知道他的内部实实现,所以我就不再赘述。

通过getSystemService,我们把拿到的Object类型强转成了Vibrator。所以接下来我们的目光就放到这个类上面。

Vibrator的包名是android.os.Vibrator,所以它在安卓源码中的位置是\frameworks\base\core\java\android\os

vibrate方法的源码如下:

    public void vibrate(long milliseconds) {
        vibrate(milliseconds, null);
    }
    public void vibrate(long[] pattern, int repeat) {
        vibrate(pattern, repeat, null);
    }

如果参数只传入long,或者long[],int 实际上会调用另一个方法(不再展示),将他们封装为VibrationEffect,AudioAttributes

并调用此方法:

    public void vibrate(VibrationEffect vibe, AudioAttributes attributes) {
        vibrate(Process.myUid(), mPackageName, vibe, attributes);
    }

mPackageName在Vibrator类创建的时候会初始化,获得当前程序的包名

当你尝试跳转四个参数的vibrate时,你会发现它居然是abstract修饰的 !

当年在回头看Vibrator这个类的时候,会发现它居然也是abstract修饰的 !

当你使用Ctrl+Alt+B查看Vibrator的实现时,居然是红色的No Implement Found !

纳尼 难道振动的具体实现是ROM厂商写的吗?

并不是这样

我们之所以产生这样的想法,是因为我们习惯了只是使用AndroidStudio查看开放的源码。但实际上,AOSP中还有很多被@hide修饰的类。

Vibrator根本不是振动的实现,只是一个基类,在其内部只实现了对振动参数的封装。

想要知道它的具体实现,我们可以写如下代码:

Object vibrator = getSystemService(this.VIBRATOR_SERVICE);
Toast.makeText(this, vibrator.getClass().getName(), Toast.LENGTH_SHORT).show();

运行后,发现vibrator 的真身是android.os.SystemVibrator。

这个SystemVibrator是一个被@hide修饰的类,我们无法通过AndroidStudio阅读它。

它的路径为\frameworks\base\core\java\android\os

观察源码,发现这个SystemVibrator也是一个空壳,所有的函数都是通过Aidl和Binder与系统进行交互的。

合情合理,毕竟用户的进程不允许直接与硬件交互,必须通过系统的中转,不然可能会出现恶意的 *** 控。

重新开始

安卓的系统服务都是通过SystemServer(\frameworks\base\services\java\com\android\server)创建的,然后保存到ServiceManager(\frameworks\base\core\java\android\os)中

在创建服务时,会把服务分为三类Bootstrap,Core,Other。而VibratorService正是属于最后一种。

我们可以在SystemServer中找到如下代码:

private Context mSystemContext;
private void createSystemContext() {
        ActivityThread activityThread = ActivityThread.systemMain();
        mSystemContext = activityThread.getSystemContext();
    }
 private void startOtherServices(){
        final Context context = mSystemContext;
        VibratorService vibrator = null;
        vibrator = new VibratorService(context);
        ServiceManager.addService("vibrator", vibrator);
        try {
            vibrator.systemReady();
        } catch (Throwable e) {
            reportWtf("making Vibrator Service ready", e);
        }
    }

流程很简单,拿到系统的Context,然后创建VibratorService ,并存入ServiceManager中,最后调用systemRead完成创建。

我们再去VibratorService (\frameworks\base\services\core\java\com\android\server)

    native static boolean vibratorExists();//是否存在嵌入式的振动设备
    native static void vibratorInit();//初始化硬件
    native static void vibratorOn(long milliseconds);//开始振动,并设置持续时长
    native static void vibratorOff();//关闭振动
    native static boolean vibratorSupportsAmplitudeControl();//是否支持振动强度控制
    native static void vibratorSetAmplitude(int amplitude);//设置振动强度
    native static long vibratorPerformEffect(long effect, long strength);//effect是系统预设的振动模式,strength是振动模式


    VibratorService(Context context) {
        vibratorInit();
        vibratorOff();
        mSupportsAmplitudeControl = vibratorSupportsAmplitudeControl();
        mContext = context;//经过分析,这里传入的Context是SystemContext
        PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
        mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*vibrator*");
        mWakeLock.setReferenceCounted(true);//通过PM拿到休眠锁,让振动的时候可以在后台运行
                mAppOpsService=IAppOpsService.Stub.asInterface(ServiceManager.getService(Context.APP_OPS_SERVICE));//权限检查作用

        mFallbackEffects = new VibrationEffect[] { clickEffect, doubleClickEffect };
    }
    public void systemReady() {//向ServiceManager添加后会调用此方法
       //本质就是监听系统的设置或者振动设备是否有变化,如果有变化就调用updateVibrators
        mContext.registerReceiver(new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                updateVibrators();
            }
        }, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mH);
        updateVibrators();
    }
   private void updateVibrators() {//更改锁的状态
        synchronized (mLock) {
            boolean devicesUpdated = updateInputDeviceVibratorsLocked();
            boolean lowPowerModeUpdated = updateLowPowerModeLocked();

            if (devicesUpdated || lowPowerModeUpdated) {
                doCancelVibrateLocked();
            }
        }
    }
    private void doCancelVibrateLocked() {
        mH.removeCallbacks(mVibrationEndRunnable);
        if (mThread != null) {
            mThread.cancel();
            mThread = null;
        }
        doVibratorOff();
        reportFinishVibrationLocked();
        //解除当前的振动
    }

走了这么远,我们再回头看看vibrate方法的具体实现

    @Override // 实现了IVibratorService.Stub,所以是Override
    public void vibrate(int uid, String opPkg, VibrationEffect effect, int usageHint,
            IBinder token) {
        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;
        }//记录每次振动的token,实质上是一个IBinder对象
        verifyIncomingUid(uid);//认证id
        if (!verifyVibrationEffect(effect)) {//判断振动是否合法
        //这个判断实际上是调用effect本身的validate方法
            return;
        }
        //和上一次振动比较
        if (effect instanceof VibrationEffect.OneShot
                && mCurrentVibration != null
                && mCurrentVibration.mEffect instanceof VibrationEffect.OneShot) {
            VibrationEffect.OneShot newOneShot = (VibrationEffect.OneShot) effect;
            VibrationEffect.OneShot currentOneShot =
                    (VibrationEffect.OneShot) mCurrentVibration.mEffect;
            if (mCurrentVibration.hasLongerTimeout(newOneShot.getTiming())
                    && newOneShot.getAmplitude() == currentOneShot.getAmplitude()) {
                if (DEBUG) {
                    Slog.e(TAG, "Ignoring incoming vibration in favor of current vibration");
                }
                return;
            }
        }

        Vibration vib = new Vibration(token, effect, usageHint, uid, opPkg);
        //Vibration是VibratiorService的一个内部类,对vibrate方法的参数进行封装

        if (effect instanceof VibrationEffect.Waveform) {
            try {
                token.linkToDeath(vib, 0);//将token和本次振动的生命周期绑定到一起
                //这里实际上会调用binderDied
            } catch (RemoteException e) {
                return;
            }
        }


        long ident = Binder.clearCallingIdentity();//开始锁,并执行振动
        try {
            synchronized (mLock) {
                doCancelVibrateLocked();
                startVibrationLocked(vib);//真正执行振动的函数
                addToPreviousVibrationsLocked(vib);//把当前的振动数据储存起来
            }
        } finally {
            Binder.restoreCallingIdentity(ident);
        }
    }
    private void verifyIncomingUid(int uid) {//认证id
        if (uid == Binder.getCallingUid()) {
            return;
        }
        if (Binder.getCallingPid() == Process.myPid()) {
            return;
        }
        mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,
                Binder.getCallingPid(), Binder.getCallingUid(), null);
    }

上述代码中,真正使得设备振动的代码在startVibrationLocked中,我们来一窥天机

    private void startVibrationLocked(final Vibration vib) {
        if (!isAllowedToVibrate(vib)) 
            return;
        if (vib.mUsageHint == AudioAttributes.USAGE_NOTIFICATION_RINGTONE &&
                !shouldVibrateForRingtone()) {
            return;
        }

        final int mode = getAppOpMode(vib);
        if (mode != AppOpsManager.MODE_ALLOWED) {
            if (mode == AppOpsManager.MODE_ERRORED) {
                // We might be getting calls from within system_server, so we don't actually want
                // to throw a SecurityException here.
                Slog.w(TAG, "Would be an error: vibrate from uid " + vib.mUid);
            }
            return;
        }
        startVibrationInnerLocked(vib);
    }

检查是否可以振动,然后检查权限,再通过startVibrationInnerLocked执行振动再上锁

private void startVibrationInnerLocked(Vibration vib) {
        mCurrentVibration = vib;
        if (vib.mEffect instanceof VibrationEffect.OneShot) {
            VibrationEffect.OneShot oneShot = (VibrationEffect.OneShot) vib.mEffect;
            doVibratorOn(oneShot.getTiming(), oneShot.getAmplitude(), vib.mUid, vib.mUsageHint);
            mH.postDelayed(mVibrationEndRunnable, oneShot.getTiming());//1
        } else if (vib.mEffect instanceof VibrationEffect.Waveform) {
            VibrationEffect.Waveform waveform = (VibrationEffect.Waveform) vib.mEffect;
            mThread = new VibrateThread(waveform, vib.mUid, vib.mUsageHint);
            mThread.start();
        } else if (vib.mEffect instanceof VibrationEffect.Prebaked) {
            long timeout = doVibratorPrebakedEffectLocked(vib);
            if (timeout > 0) {
                mH.postDelayed(mVibrationEndRunnable, timeout);//2
            }
        }
    //因为Waveform 是一种长时间,强度多次变化的,所以使用线程振动
    }

留意一下注释1,2.我们在分析doVibratorOn后会分析

我们先来看一下doVibratorOn,他是核心振动方法

private void doVibratorOn(long millis, int amplitude, int uid, int usageHint) {
        synchronized (mInputDeviceVibrators) {//对当前振动设备加锁
            if (amplitude == VibrationEffect.DEFAULT_AMPLITUDE) {
                amplitude = mDefaultVibrationAmplitude;
            }
            final int vibratorCount = mInputDeviceVibrators.size();
            if (vibratorCount != 0) {
                final AudioAttributes attributes =
                        new AudioAttributes.Builder().setUsage(usageHint).build();
                for (int i = 0; i < vibratorCount; i++) {//让所有振动设备都振动
                    mInputDeviceVibrators.get(i).vibrate(millis, attributes);
                    //mInputDeviceVibrators存放的是Vibrator,最终仍然会走这个doVibratorOn方法,并且所有振动设备都持有锁
                }
            } else {//调用native方法设置振动并设置强度。
                //安卓源码在这里有一个贴心提示,让先开启振动,再设置强度,这个排序很重要
                vibratorOn(millis);
                doVibratorSetAmplitude(amplitude);
            }
        }
    }
    private void doVibratorSetAmplitude(int amplitude) {
        if (mSupportsAmplitudeControl) {
            vibratorSetAmplitude(amplitude);
        }
    }

在回头看注释1,2。其中的mVibrationEndRunnable,会在振动结束后(通过postDaly实现)异步调用onVibrationFinished

    public void onVibrationFinished() {
        synchronized (mLock) {
            doCancelVibrateLocked();//这个方法我们已经在前面介绍过,不再赘述
        }
    }

注意一下,我们在vibrate方法中,对振动对象绑定了振动的生命周期,所以会在结束时调用Vibration对象(实现了IBinder.DeathRecipient接口)的binderDied

        public void binderDied() {
            synchronized (mLock) {
                if (this == mCurrentVibration) {
                    doCancelVibrateLocked();
                }
            }
        }//即使postDaly出现了问题,也能在振动超时的时候停止

以上我们已经分析了onShot振动的实现,现在我们来看看Wave的实现

Wave振动是开启了一个类型为VibrateThread的线程,代码如下:

private class VibrateThread extends Thread {
        private final VibrationEffect.Waveform mWaveform;
        private final int mUid;
        private final int mUsageHint;

        private boolean mForceStop;

        VibrateThread(VibrationEffect.Waveform waveform, int uid, int usageHint) {
            mWaveform = waveform;
            mUid = uid;
            mUsageHint = usageHint;
        }

        private long delayLocked(long duration) {//延时的实现
            long durationRemaining = duration;
            if (duration > 0) {
                final long bedtime = duration + SystemClock.uptimeMillis();
                do {
                    try {
                        this.wait(durationRemaining);
                    }
                    catch (InterruptedException e) { }
                    if (mForceStop) {
                        break;
                    }
                    durationRemaining = bedtime - SystemClock.uptimeMillis();
                } while (durationRemaining > 0);
                return duration - durationRemaining;
            }
            return 0;
        }

        public void run() {
            mWakeLock.acquire();//拿到唤醒锁
            try {
                boolean finished = playWaveform();//阻塞式实现振动
                if (finished) {
                    onVibrationFinished();
                }
            } finally {
                mWakeLock.release();
            }
        }

        public boolean playWaveform() {
            synchronized (this) {
                final long[] timings = mWaveform.getTimings();
                final int[] amplitudes = mWaveform.getAmplitudes();
                final int len = timings.length;
                final int repeat = mWaveform.getRepeatIndex();

                int index = 0;
                long onDuration = 0;
                while (!mForceStop) {
                    if (index < len) {
                        final int amplitude = amplitudes[index];
                        final long duration = timings[index++];
                        if (duration <= 0) {
                            continue;
                        }
                        if (amplitude != 0) {
                            if (onDuration <= 0) {
                                onDuration =
                                        getTotalOnDuration(timings, amplitudes, index - 1, repeat);
                                doVibratorOn(onDuration, amplitude, mUid, mUsageHint);
                            } else {
                                doVibratorSetAmplitude(amplitude);
                            }
                        }

                        long waitTime = delayLocked(duration);
                        if (amplitude != 0) {
                            onDuration -= waitTime;
                        }
                    } else if (repeat < 0) {
                        break;
                    } else {
                        index = repeat;
                    }
                }
                return !mForceStop;
            }
        }

        public void cancel() {//强制取消
        //doCancelVibrateLocked方法中会调用
            synchronized (this) {
                mThread.mForceStop = true;
                mThread.notify();
            }
        }

        private long getTotalOnDuration(//获得总时长
                long[] timings, int[] amplitudes, int startIndex, int repeatIndex) {
            int i = startIndex;
            long timing = 0;
            while(amplitudes[i] != 0) {
                timing += timings[i++];
                if (i >= timings.length) {
                    if (repeatIndex >= 0) {
                        i = repeatIndex;
                    } else {
                        break;
                    }
                }
                if (i == startIndex) {
                    return 1000;
                }
            }
            return timing;
        }
    }

实质上振动的实现还是native方法doVibratorOndoVibratorSetAmplitude

我们再简单分析一下硬件层

首先设备的载入在server.cpp(\device\google\marlin\vibrator)中

核心代码如下


static const char *ENABLE_PATH = "/sys/class/timed_output/vibrator/enable";
static const char *AMPLITUDE_PATH = "/sys/class/timed_output/vibrator/voltage_level";

status_t registerVibratorService() {
    std::ofstream enable{ENABLE_PATH};
    if (!enable) {
        int error = errno;
        ALOGE("Failed to open %s (%d): %s", ENABLE_PATH, error, strerror(error));
        return -error;
    }

    std::ofstream amplitude{AMPLITUDE_PATH};
    if (!amplitude) {
        int error = errno;
        ALOGE("Failed to open %s (%d): %s", AMPLITUDE_PATH, error, strerror(error));
        return -error;
    }

    sp<IVibrator> vibrator = new Vibrator(std::move(enable), std::move(amplitude));
    vibrator->registerAsService();
    return OK;
}

int main() {
    configureRpcThreadpool(1, true);
    status_t status = registerVibratorService();

    if (status != OK) {
        return status;
    }

    joinRpcThreadpool();
}

振动设备的配置信息在Vibrator.cpp(\device\google\marlin\vibrator)

代码如下

//振动器的强度通过电压控制
static constexpr int MAX_VOLTAGE = 3596;//最大电压
static constexpr int MIN_VOLTAGE = 116;//最小电压

static constexpr uint32_t CLICK_TIMING_MS = 20;//单位持续时长

Vibrator::Vibrator(std::ofstream&& enable, std::ofstream&& amplitude) :
        mEnable(std::move(enable)),
        mAmplitude(std::move(amplitude)) {}
Return<Status> Vibrator::on(uint32_t timeout_ms) {
    mEnable << timeout_ms << std::endl;
    if (!mEnable) {
        ALOGE("Failed to turn vibrator on (%d): %s", errno, strerror(errno));
        return Status::UNKNOWN_ERROR;
    }
    return Status::OK;
}

Return<Status> Vibrator::off()  {
    mEnable << 0 << std::endl;
    if (!mEnable) {
        ALOGE("Failed to turn vibrator off (%d): %s", errno, strerror(errno));
        return Status::UNKNOWN_ERROR;
    }
    return Status::OK;
}

Return<bool> Vibrator::supportsAmplitudeControl()  {
    return true;
}

Return<Status> Vibrator::setAmplitude(uint8_t amplitude) {
    if (amplitude == 0) {
        return Status::BAD_VALUE;
    }
    long voltage =
            std::lround((amplitude - 1) / 254.0 * (MAX_VOLTAGE - MIN_VOLTAGE) + MIN_VOLTAGE);
    ALOGE("Setting amplitude  to: %ld", voltage);
    mAmplitude << voltage << std::endl;
    if (!mAmplitude) {
        ALOGE("Failed to set amplitude (%d): %s", errno, strerror(errno));
        return Status::UNKNOWN_ERROR;
    }
    return Status::OK;
}

Return<void> Vibrator::perform(Effect effect, EffectStrength strength, perform_cb _hidl_cb) {//系统预设的振动
    if (effect == Effect::CLICK) {
        uint8_t amplitude;
        switch (strength) {
        case EffectStrength::LIGHT:
            amplitude = 36;
            break;
        case EffectStrength::MEDIUM:
            amplitude = 128;
            break;
        case EffectStrength::STRONG:
            amplitude = 255;
            break;
        default:
            _hidl_cb(Status::UNSUPPORTED_OPERATION, 0);
            return Void();
        }
        on(CLICK_TIMING_MS);
        setAmplitude(amplitude);
        _hidl_cb(Status::OK, CLICK_TIMING_MS);
    } else {
        _hidl_cb(Status::UNSUPPORTED_OPERATION, 0);
    }
    return Void();
}


振动的HAL层实现在Vibrator.cpp(\hardware\interfaces\vibrator\1.0\default)

就不贴代码了,因为厂商的实现都不一样的。

至此,振动服务的调用已经从Java API层到HAL层,我们来做一个总结。

总结

首先系统在启动时,通过ZygoteInit中handleSystemServerProcess函数的最后一步,调用SystemServer的静态函数main方法。

在SystemServer的main函数中,根据service的类型分三类进行服务加载,振动服务属于Other类。

创建了VibratorService对象后,将其加入到系统服务map中。

在VibratorService中调用native方法vibratorInit,初始化硬件振动器。至此系统振动服务加载完成。

开发者通过getSystemService拿到SystemVibrator ,SystemVibrator继承自Vibrator,内部实现了对振动参数的检验和封装。

开发者调用vibrate方法,SystemVibrator将参数封装,并通过Binder与系统振动服务进行通信。

系统振动服务最终调用native的doVibratorOn与doVibratorSetAmplitude *** 控硬件。通过加锁和Handler的postDaly实现结束时监听。

doVibratorOn与doVibratorSetAmplitude会调用厂商封装好的HAL层 *** 作硬件设备。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/992866.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-21
下一篇 2022-05-21

发表评论

登录后才能评论

评论列表(0条)

保存