张墨轩的技术宅

不忘初心,方得始终

Win7-32位平台下用Cygwin+NDK编译android版FFmpeg+x264全过程

这里我将详细记录我在Win7-32位平台下用Cygwin+NDK编译出跑在android系统上的FFmpeg+x264全过程。FFmpeg默认情况下只支持h264的解码,并不支持h264的编码,为了让FFmpeg支持对h264的编码功能,需要编译的时候加入x264这个扩展库的支持。本文的目的就是最终编译出一个能在android下运行,同时支持h264编码和解码的的FFmpeg。

Mirrorlink类型车联网项目阶段性成果(二)

前段时间弄的是CE平台的车机。但是因为android发展迅猛,现在android车机已经相当普遍,所以最近一直在弄android系统的车机平台,这次主要的目标是实现android车机平台与iPhone手机之间的连接。对于苹果在车联网领域,已经有了它自己的方案CarPlay,但是正如苹果一贯的封闭,对我来说完全没有帮助。我只得采用airplay协议进行屏幕的投射。至于说反控,就是通过车机屏幕去控制iPhone手机的屏幕,这个因为iPhone手机严格的权限控制,是不可能实现的。不过人总是聪明的,这里有一种很取巧的办法,虽然我们没有权限控制整个iPhone手机,但是我们却可以实现应用内的控制,简单来说我们可以开发一个自己的苹果APP,然后可以通过车机端控制我们自己APP在运行时所展现出来的那个屏幕内容。这也不失是一种折中的好办法。 整的来说难度还是挺大的,而且对于airplay协议来说也是封闭的,没有太多公开的资料,很多时候需要自己抓包去分析,另外也不知道什么时候苹果一升级,协议又变了。

程序员的数学

数学对程序员来讲还是很重要的,特别是对我这种数学不好的人来讲更加重要。随着时代的发展,AR/VR,人工智能,自然人机交互,机器视觉,机器人技术等等将成为主流和重点。音频视频处理,3D技术,机器学习等等无不将成为必须要掌握的技术,而这些技术背后都蕴含着各种高深的数学知识。 所以适当的补充数学知识还是必须的。下面推荐一些看过的适合程序员看的好书:

Mirrorlink类型车联网项目阶段性成果

最近做的一个类似mirrorlink的车联网项目取得阶段性的成果,车机和手机之间已经连通并且已经可以实现远程控制,目前实现的车机平台是CE系统,手机是android类手机。其实这样的项目从原理上来讲并不复杂,主要是包括2大功能:


第一:实现一个类似手机助手功能,可以简单把车机理解成一台PC主机,当有android手机通过USB插入到车机上的时候,车机发现手机,并且推送类似VNC的远控程序到手机端,并且通过ADB的端口转发功能在USB链路上实现socket连通,这样车机控制端程序就可以和手机上的被控端程序进行socket网络通讯了。难点主要是需要在CE平台上实现一个ADB驱动程序, 并且将ADB移植到CE平台上来。

ADB与普通APP权限简单对比

最近在做一个车联网的项目,其中一个基本需求是将一台android手机通过USB线缆接入到车机上后,手机屏幕远程映射到车机的屏幕上,我们可以通过操作车机的屏幕来远程控制手机。这个技术本质上就是通过类似VNC的方式在车机上远程控制手机。业内有名的车联网方案如apple的carplay还有google的androidauto本质上其实也都是远程映射,另外一个著名的规范MirrorLink就直接定义了利用VNC技术进行映射。
android平台上有很多VNC相关的程序和库,如开源的libvncserver,如有名的droidVncServer项目,它内部其实就是使用了libvncserver库。还有如Remoteroid等等。这些程序作为远程控制中的《被控端》运行到android上都必须要求root权限,原因也很简单就是需要权限。作为VNC技术中的《被控端》有两个基本工作要做:
第一就是读取本机的屏幕buffer传送给《控制端》,这样《控制端》就可以看到《被控端》的屏幕内容了。
第二就是《被控端》要接受来自《控制端》的操作请求,比如点击了屏幕上某个位置,进而控制android做出相应的反应。
这里获取屏幕buffer暂且不聊,主要说说输入控制相关的部分,android是基于linux的,所以输入控制的部分主要是操作/dev/input下面的设备文件。我们来看看android系统/dev/input下面的设备文件的权限。如图:
可见root用户有读写权限,input组下面的用户也有读写权限。而作为android下面的普通的APP是不具备这样的权限的。
下面我们来看看一个普通的APP的权限,如图:
可见这个普通的APP所属用户为u0_a57,所在组也不包括input组。所以对/dev/input下面的设备文件无权操作,那么输入控制功能将无法实现。所以必须要求root权限才行。
但是别家的车联网项目确实不要求android手机已经root,在没有root的android手机上也能实现类似VNC的远程操作。那么这又是为什么呢。答案就在adb上。adb在设备端所对应的的守护进程叫做adbd,在android启动过程中它会被init进程所加载,程序刚运行的时候是root权限,然后它会给自己降权,最终以shell用户权限运行。而shell属于input组,是可以读写/dev/input下面的设备文件的。如图:
所以当用户把android手机通过USB接入到车机上时(为了方便理解这里可以把车机就想象成一台PC电脑),车机通过adb命令通知android手机上的adbd运行起《被控端》程序,这个时候《被控端》运行在shell用户权限,可以正常读写/dev/input。
因为adb本身就是作为android调试桥的作用存在的。所以它实际上也是具备一定权限的,虽然没有root权限那么大,但是比一般普通的APP的权限还是要大一些。像/system/bin/下面提供的一些工具,比如getevent/sendevent,input,screencap,screenrecord等都只有用adb去调用才能正常工作,普通APP去调用是无法正常工作的,因为缺乏权限。 而像screenshot这样的工具通过adb去调用也无法正常工作,因为这个工具内部是直接操作/dev/graphics/fb0设备的,而这个设备连shell权限也无权操作。如图:
 
只有system用户和graphics组才有权操作。那为什么adb调用screencap又可以呢,通过读取源代码可以知道,它的源代码在frameworks/base/cmds/screencap/ ,它内部实际上是调用SurfaceFlinger提供的接口ScreenshotClient,本质上是通过binder机制与SurfaceFlinger进程间通讯罢了。android自带的调试工具DDMS有一个截图功能,其实也是通过adbd调用screencap完成截图的。


VR,AR之我见

近两年VR,AR等技术越来越火,像微软的Microsoft HoloLens眼镜这样的产品,依靠手势识别,语音识别等交互技术,加上真三维的视觉冲击,可以说把我们和未来一下子拉近了很多。那站在我们程序员的角度,如何看待这样的变革呢。我想估计以后至少会有两种类型的应用。
第一就是传统的二维应用:我们现在开发的PC程序,手机APP等,不管是阅读为主的新闻APP还是大型3D游戏程序,本质上还是看成一个二维程序,为什么这样说呢,因为它们最终需要一个二维的屏幕给显示出来,它们以后在类似Microsoft HoloLens这样的环境中如何表现出来呢?那就是在真三维环境中虚拟出一块屏幕,然后把APP的内容显示到这个虚拟的屏幕上,就像在真实的屏幕中显示一样。如下图:
这种模式下利用手势识别模拟点击和滑动等操作,这样可以将现在传统的APP,全部照搬到真三维环境中。对我们程序员来说可能不需要做太多工作。
第二种就是真三维应用,下面两张图一个是电影《普罗米修斯》,一个是游戏《星际争霸2》中的截图,表现的就是这种类型的应用,做这种应用估计得懂几何学,图形学,机器视觉,DirectX,OpenGL,向量,矩阵变换,顶点,纹理,多边形。哈哈哈,努力学习,天天向上。


微信公众号及其账号授权模式的一些发散思考

用户在使用app前碰到最大的二大问题:
1. APP需要从市场上下载到手机,需要占用流量。
2. 安装完毕后,一般需要注册,才能使用完整的功能。

下载安装这个就不需要多讲了,那为什么要注册呢?注册的目的主要是有2点:

第一:最基础的一点就是用于唯一的标识一个客户,厂家可以知道是有不同的人在进行操作,虽然不知道具体是谁,不知道他的具体情况,但是确实是有这么一个人。
第二:可以在第一点的基础上,记录这个人的各种详细信息,以便于对他进行服务,比如电商系统,可以记录某个人手机是多少,叫什么,住哪里,这样可以为他送货,也可以记录他的购买历史等等。

现在微信公众号的推出,作为一种轻量级app,其实就是解决了一开始说的2个大问题,下载和注册。用户只需要进行关注,这样比下载成本低很多,也不需要刻意去做登录这一步,因为微信本身就已经是登录状态了,只需要把这个登录的账号做网页授权就可以了,获得的openid对这个公众号是唯一的,可以作为一个用户的唯一凭证。当然仅仅只知道一个openid是不够的,它只解决了用户识别问题,至于其他的用户详细信息部分就在软件的使用过程中逐步引导客户去填写,比如我是电商系统我可以在用户下单的时候,要求用户填入手机和姓名和地址等,因为这是理所当然的,不然怎么送货呢。

在需要登录的时候,一般可以如下方式:

1.微信授权登录 获取openid和一些其他信息 算是登录了。
2.自定义登录,又可以分出以下几种方式:
一:邮箱或者手机号码 发验证码登录 不需要固定密码
二:用邮箱或者手机绑定固定密码,以后登录直接用固定密码登录。

当获得手机或者邮箱或者一个openid的时候 就都算登录了。 因为这三者每一个都能唯一表示一个用户,用户的其他的信息,可以在随后的使用中逐步引导客户去输入。

比如京东PC站点有一种不需要登录一次性购买的行为,就是你可以不用登录,看完商品 然后在最后下单的时候 京东会要求你输入手机和送货地址 并且验证你的手机,然后就下单了。这样看上去好像是不需要登录直接购买,实际上是变相的方式引导客户进行了注册而已。所以方式很重要。

账号体系是如此之重要,所以BAT等都在争抢。所以我们也可以看到各种授权登录模式,比如微信授权登录,QQ授权登录,支付宝授权登录等等。

微信开放平台的核心思想就是账号授权给其他app免去注册这个坎。


小蚁直递

小蚁直递是我2015年做的一个社区电商领域的项目,虽然一直没什么起色,不过还是记录下来,自勉之。


Xdebug调试PHP原理浅析

用很多工具写过PHP,最后还是发现PhpStorm最好用,同时用PhpStorm搭配Xdebug调试PHP也很舒服。至于如何配置Xdebug网上已经有了太多文章可以参考,这里不再说明,本文只是简单的记录一下Xdebug调试PHP的原理和过程。

要进行调试有三个必要组件:

组件一:实现了DBGP调试协议的调试插件,这个PhpStorm默认就已经包含了,设置里面也可以看到相关设置,如图:
通过点击导航栏上电话一样的按钮(如下图),PhpStorm会开启9000端口进行监听。
通过进程信息可以清楚的看到PhpStorm已经在监听9000端口。如下图:
DBGP协议介绍地址:

组件二:PHP的Xdebug扩展。下载地址为:
Xdebug作为PHP扩展模块将会被PHP所加载,加载成功后可以通过 php -m 命令 或者 phpinfo() 函数查看。如下图:
php.ini文件中的配置示例:

[Xdebug]
zend_extension=E:\php-5.4.8-Win32-VC9-x86\ext\php_xdebug-2.4.0rc3-5.4-vc9.dll
xdebug.profiler_enable=on
xdebug.trace_output_dir="../xdebug"
xdebug.profiler_output_dir="../xdebug"
xdebug.idekey=PhpStorm
xdebug.remote_handler=dbgp
xdebug.remote_enable=on

组件三:Chrome浏览器的xdebug helper扩展。安装地址(记得翻墙):

当把上面三大必要组件都配置好后(具体配置网上很多文章都有详细介绍),就可以开始调试了。具体的调试原理如下:
1. 运行WEB服务器(如Apache),Apache会加载PHP,PHP会加载Xdebug扩展模块。
2. WEB浏览器(如Chrome)会通过80端口访问 WEB服务器中的某个PHP文件
3. WEB服务器会调用PHP解释器解析PHP文件,如果开启调试的话,PHP会通过Xdebug(根据php.ini中的Xdebug配置)主动连接调试客户端,默认是localhost:9000,如图:
也就是说 PHP会通过Xdebug扩展模块主动连接上PhpStorm正在监听的9000端口,从而PHP会与PhpStorm建立起调试会话通讯,这样程序员就可以通过PhpStorm对PHP程序进行各种调试交互动作了,比如查看变量值,比如下断点等等。
4. 当PHP的代码执行完毕以后,Xdebug会断开与PhpStorm的连接,从而结束本次调试会话过程。

交互流程如下:

browser <==> Port 80 <==> Apache+PHP+Xdebug <==> Port 9000 <==> PhpStorm(DBGP Plugin)

文章写到这里,可能细心的朋友就发现了。Chrome浏览器的xdebug helper扩展 这个部分一直没有提起。不是说它是三大必要组件之一吗!确实,从操作体验上来看用Chrome浏览器配合xdebug helper扩展确实会体验好很多,但是从纯技术角度来讲,它确实不是必须的,因为你想啊,PHP是一门服务端语言,调试也是服务端调试,怎么需要某个特定的浏览器呢?难道只能用Chrome浏览器,其他的浏览器不行吗,这个从技术角度来讲说不过去啊。事实上确实与特定浏览器没有关系,Chrome浏览器的xdebug helper扩展实际作用其实只是设置了一个标志在cookie中,当浏览器访问服务端时,这个cookie值会被传到服务端,这样Xdebug读取到这个值后就知道本次请求用户是想要开启调试功能,它才会连接调试客户端建立调试会话。
上图就是浏览器传给服务端的cookie值,意味着要开启调试。

所以简单来讲,不管用的是什么浏览器,其实只要设置对了相应的cookie值,就可以开启调试。在我这个示例当中还可以直接利用下面的代码来开启调试:
<div id="xdebug_bookmarklets" class="hide" style=" displayblock" >
    <h3>Bookmark these links for future use </h3>
    <h4>Debug: </h4>
    <ul class= "starlist" >
        <li>< a id="xdebugStartSession" href="javascript:(/** @version 0.5.2 */function() {document .cookie='XDEBUG_SESSION='+'PHPSTORM'+';path=/;';})()"> Start debugger</a></li>
        <li>< a id="xdebugStopSession" href="javascript:(/** @version 0.5.2 */function() {document .cookie='XDEBUG_SESSION='+''+';expires=Mon, 05 Jul 2000 00:00:00 GMT;path=/;';})()"> Stop debugger</a></ li>
        <li>< a id="xdebugThisPage" href="javascript:(/** @version 0.5.2 */function() {document .cookie='XDEBUG_SESSION='+'PHPSTORM'+';path=/;';document. location.reload(); document.cookie='XDEBUG_SESSION='+''+';expires=Mon, 05 Jul 2000 00:00:00 GMT;path=/;';})()" >Debug this page </a></li>
    </ul>
    <h4>Profile: </h4>
    <ul class= "starlist" >
        <li>< a id="xdebugStartProfiler" href="javascript:(/** @version 0.5.2 */function() {document .cookie='XDEBUG_PROFILE='+'1'+';path=/;';})()"> Start profiler</a></li>
        <li>< a id="xdebugStopProfiler" href="javascript:(/** @version 0.5.2 */function() {document .cookie='XDEBUG_PROFILE='+''+';expires=Mon, 05 Jul 2000 00:00:00 GMT;path=/;';})()"> Stop profiler</a></ li>
    </ul>
    <h4>Function Trace: </h4>
    <ul class= "starlist" >
        <li>< a id="xdebugStartTracer" href="javascript:(/** @version 0.5.2 */function() {document .cookie='XDEBUG_TRACE='+'1'+';path=/;';})()"> Start tracer</a></li>
        <li>< a id="xdebugStopTracer" href="javascript:(/** @version 0.5.2 */function() {document .cookie='XDEBUG_TRACE='+''+';expires=Mon, 05 Jul 2000 00:00:00 GMT;path=/;';})()"> Stop tracer</a></ li>
    </ul>
</div>
本质就是设置一个cookie值而已。
当然其实还有个更简单的办法 就是直接在请求的url后面连上一个&XDEBUG_SESSION_START=1,这样也开启了调试。

其实不单单是PhpStorm,其他编辑器如 vim,notepad++等编辑器装上DBGP调试插件后也都能进行PHP调试,原理流程也和上文介绍的一样,只是调试客户端不同而已。
下面是notepad++的DBGP调试插件的下载地址:
下面是vim插件下载地址:


APK【Volume Power】逆向全过程

之前对音量键点亮屏幕比较感兴趣就分析了一个这样功能的APP,现在又分析了另一个名叫Volume Power的APP,感觉比较坑爹,权且当学习吧。我们开始,先看看包结构,如图:
文件很少,非常简单,唯一一个可疑的是empty.mp3文件,这个文件稍后分析中会提到。运行后主界面如下:
就是一个设置界面,有三个设置选项:
一:启用还是禁用音量键点亮屏幕
二:是否启动运行
三:通过通知栏的按钮关闭屏幕
接下来正式开始分析,这里只会讲重点部分,其他可以自己看代码。按惯例先看AndroidManifest.xml文件内容:
这里注册了几个广播接收器,还有一个服务。其中:
android.media.VOLUME_CHANGED_ACTION 会在调节音量的时候被触发。
android.intent.action.SCREEN_OFF 在关闭屏幕的时候触发
android.intent.action.SCREEN_ON   在点亮屏幕的时候触发
android.app.action.DEVICE_ADMIN_ENABLED 将程序设置成Android设备管理器或者取消的时候被触发
android.intent.action.BOOT_COMPLETED 系统启动后自动运行
其他都先不关注,按程序执行流程先看com.example.stayawake.BootReceiver,它主要是创建一个线程并且执行,如图:
那么线程具体做了什么,接着看 BootReceiver$1类,这个是个匿名类,如图:
这里注解的很清楚,这是一个内部类,没有名字,它存在于BootReceiver.onReceive中,线程主要就是运行起了SoundService服务:
然后我们来看看这个服务,这个服务最主要的作用就是做了一件坑爹的事,如图:
就是不停的循环播放empty.mp3文件,而empty.mp3实际上是一个空的没有声音的文件,所以用户并不知道在播放声音,但是后台确实一直在播放,那就意味着运行了这个程序后,电量将飞快的被消耗掉,真是坑爹啊。那为什么要这样做呢,主要目的就是保持这个APP一直存在于内存中不被kill掉,如果被kill了功能就丧失了,因为在Android系统内存低时系统会根据一些策略kill掉一些进程来腾出内存,所以作者这里用了这样一种坑爹的方式来保证APP能一直运行。
接下来当用户点击音量键的时候,android.media.VOLUME_CHANGED_ACTION所对应的广播接收器VolumeReceiver.onReceive会被执行,然后事情就简单了:
直接调用系统的电源管理器点亮屏幕。另外程序为了能有关闭屏幕的权限会在设置界面将自己提升为Android设备管理器:
好了,基本就是这样,这个APP非常简单也没什么太多要说的,具体的可以自行查看源代码。
全部代码已经上传到github上,源代码的github地址:
https://github.com/phonegapX/com.teliapp.powervolume


«123456»

Powered By Z-Blog 2.2 Prism Build 140101

Copyright phonegap.me Rights Reserved.