2015-10-16 00:54:37 wtianok 阅读数 3295
  • 快速入门Android开发 视频 教程 android studio

    这是一门快速入门Android开发课程,顾名思义是让大家能快速入门Android开发。 学完能让你学会如下知识点: Android的发展历程 搭建Java开发环境 搭建Android开发环境 Android Studio基础使用方法 Android Studio创建项目 项目运行到模拟器 项目运行到真实手机 Android中常用控件 排查开发中的错误 Android中请求网络 常用Android开发命令 快速入门Gradle构建系统 项目实战:看美图 常用Android Studio使用技巧 项目签名打包 如何上架市场

    19464 人正在学习 去看看 任苹蜻

何为定制Android系统?就是在特定的硬件上,移植上Android操作系统,并修改原生Android系统以提供给定制的APP操作定制硬件的方法。

所以,定制Android的主要工作有以下三部分:

  1. 适配硬件;
  2. 制作接口;
  3. 定制APP;

一般而言,定制的硬件会采用方案商提供的稳定方案,例如全至的a20方案、a31s方案、r16方案、飞思卡尔的i.MX6方案等等。这些方案拿过来,是一个类似于平板的开发板,在其上Android系统是能够跑起来的。然后就要根据自身的需求,把一些外围硬件适配上去,例如你要做一个音箱类的产品,你可能需要适配上牛掰的DSP,PA等等,如果你要做一个车机类的产品,你可能要适配上一个MCU,适配上倒车摄像头,如果是要做一个电视盒子,红外或者2.4g是必须的。这就是适配硬件所要做的工作。

定制的硬件产品一般都会应用于一些特殊的场景下,那么肯定会需要定制一个APP来和用户进行交互,完成用户所需要的功能。因为硬件是定制的,很多功能原生的Android系统并没有提供接口来操作,这就需要开发人员对Android进行修改,把操作硬件的方法暴露给APP。这就是我所做的工作。这部分的工作处于应用开发和驱动开发之间,我姑且称之为Android中间件的开发。

开发驱动的同事一般会提供给我一些设备节点,通过读写这些设备节点就可以操作外设。一般来说,操作设备节点的操作会用C/C++来实现。但是对于制作APP的同事,他们会习惯于使用Java这类高级语言,所以对于Android中间件的开发者,就要借助于JNI这一工具,构建连接C/C++和Java的桥梁。

在我的开发过程中,我使用过以下几种方法来提供操作硬件的接口:

  1. 提供JNI源代码;

提供JNI源代码是最裸的一种方式。一般在调试一个硬件功能的时候,我会编写一个简单的Demo APP。调试成功之后,我曾直接把Demo APP的源代码提供给APP开发者。这样,我的工作是最少的,只要调试完,就算是大功告成了。但是对于开发APP的同事来说,这种提供接口的方式需要他们具备一定的JNI开发知识,这就无形中增加了他们的工作量。在我看来,APP开发应该讲经历集中于与用户的交互上,而不是具体的功能的实现细节上。所以这种方法并不好。

另外一方面,因为接口的源代码文件肯定不止一个,那么源代码的版本控制也是一个问题。

  1. 提供JNI编译的库文件;

具体来说,提供库文件有两种方式。一种是给APP提供JNI编译之后的库文件,由他们集成到APP中。这种方式只是简化了版本控制的问题(因为只有一个库文件),对APP开发者的要求没有减少。另一种是把JNI在源代码的环境中编译,编译完之后库文件就在/system/lib/下面了。APP只需运行在特定固件中就行了。这种方式的版本控制问题更严重。因为采用这种方式,在库函数载入的时候会检查APP中声明的接口函数是否和当前库中的函数一一对应,不对应会直接崩掉。所以,如果在某个版本之后,APP新增了一个接口,那么这个新的APP就不能运行在老的固件中了。

  1. 编写后台运行的服务;

为了解决上面的问题,可以编写一个Service。由这个Service来和APP进行交互。因为Service是内置在固件内部的,所以这个Service和JNI不会有版本匹配的问题。而且交互的过程全部都是通过Java实现的(APP开发者最开心了)。APP和Service是运行与不同进程中的,Android的IPC一般有两种方式,一种是通过系统广播,一种是通过AIDL。前者的优点是使用简单,调用不同的接口只需发送不同的广播就行了,返回值则通过接收广播来获取。它的缺点通过广播调接口的实时性不能保证。后者则编写难度较大。各位可以找一下远程服务的代码看看,为了调一个接口,需要编写很多行的代码,这个也是APP的开发人员不想看到的。

其实IPC还有另外一种方式,就是通过socket。这种方式我没有用过,因为其代码编写的量也不少。

  1. 增加系统服务;

这种方式在我目前看来,是最好的方法。为什么好呢?下次再说。已经快一点了,明天还要上班。

2015-10-16 14:04:16 wtianok 阅读数 3367
  • 快速入门Android开发 视频 教程 android studio

    这是一门快速入门Android开发课程,顾名思义是让大家能快速入门Android开发。 学完能让你学会如下知识点: Android的发展历程 搭建Java开发环境 搭建Android开发环境 Android Studio基础使用方法 Android Studio创建项目 项目运行到模拟器 项目运行到真实手机 Android中常用控件 排查开发中的错误 Android中请求网络 常用Android开发命令 快速入门Gradle构建系统 项目实战:看美图 常用Android Studio使用技巧 项目签名打包 如何上架市场

    19464 人正在学习 去看看 任苹蜻

在这篇博文中,我将一步一步建立一个SystemService。

这个系统服务是用于控制收音机的,名字就叫做RadioManagerService。

新建IRadioManager.aidl;

framework/base/core/java/amdroid/os/中新建IRadioManager.aidl文件。文件的内容如下:

package android.os;

interface IRadioManager{
    void test();
}

aidl文件的语法规则可以网上查一下,这里就不做解释了。

将.adil文件名添加到Android.mk脚本中;

上面虽然新建了aidl文件,但是在编译的过程中并不会编译,只有在Android.mk中添加相关说明之后才会编译。

这个Android.mk文件的位置是:frameworks/base/Android.mk

LOCAL_SRC_FILES += \ 
    core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl \
    core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl \
    #…… 此处省略很多行
    com/java/android/os/IRadioManager.aidl

编写Service,实现xxx.stub;

frameworks/base/services/java/com/android/server/目录下新建RadioManagerService.java。其内容如下:

public class RadioManagerService extends IRadioManager.Stub implements IOnUartMsgListener {
    private static final String TAG = "TimothyRadioManagerService";
    private Context mContext;

    public RadioManagerService(Context context) {
        this.mContext = context;
    }

    @Override
    public void test() throws RemoteException {
        Log.d(TAG, "test() is called");
    }
}

实现Manager,调用Service;

framework/base/core/java/android/os/目录下新建RadioManager.java,内容如下:

public class RadioManager {
    private static final String TAG = "TimothyRadioManager";
    private Context mContext;
    private IRadioManager mService; // 要调用服务器的接口,首先就要保存服务器的对象。就好比只有知道了找人办事,首先得知道要找的人叫什么。

    public RadioManager(Context context, IRadioManager service) {
        mContext = context;
        mService = service;
    }
    public void test() {
        Log.d(TAG, "test() is called");
        mService.test(); // 调用客户端的test()函数,实际上调用的是服务器的test()函数。
    }
}

将自定义的服务注册到SystemServer;

framework/base/services/java/com/android/server/SystemServer.java的initAndLoop()函数里增加声明,并注册Service。

public void initAndLoop() {
    EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_SYSTEM_RUN,
        SystemClock.uptimeMillis());

    Looper.prepareMainLooper();

    // 此处省略很多行

    Installer installer = null;
    AccountManagerService accountManager = null;
    ContentService contentService = null;
    LightsService lights = null;
    PowerManagerService power = null;

    // 此处省略很多行

    com.android.server.RadioManagerService audioManagerService = null;

    // 此处省略很多行

    // 找个系统添加其他Service的地方加上下面这些
    try {
        Slog.i(TAG, "radio service");
        radioManagerService = new com.android.server.RadioManagerService(context);
        ServiceManager.addService(Context.RADIO_MANAGER_SERVICE, radioManagerService);
    } catch (Throwable e) {
        reportWtf("starting iflytek radio service", e);
    }
}

千万别忘了,在Context中增加RADIO_MANAGER_SERVICE这个常量的定义。

在ContextImpl.java中注册服务;

framework/base/core/java/android/app/ContextImpl.java中注册其他服务的地方加上下面的代码:

registerService(RADIO_MANAGER_SERVICE, new ServiceFetcher() {
    public Object createService(ContextImpl ctx) {
        IBinder b = ServiceManager.getService(RADIO_MANAGER_SERVICE);
        return new android.os.iflytek.RadioManager(ctx, IRadioManager.Stub.asInterface(b));
    }});

当你在使用Context.getSystemService()的时候,代码会走到这里。

结论

到这里,在Android APP中就能通过使用下面的代码调用系统服务:

RadioManager mRadioManager = (RadioManager)getSystemService(Context.RADIO_MANAGER_SERVICE);
mRadioManager.test();

因为改了framework中的代码,增加了接口,在编译的时候,需要先执行

make update-api

之后再make。

2013-12-10 16:12:11 lyccsu 阅读数 892
  • 快速入门Android开发 视频 教程 android studio

    这是一门快速入门Android开发课程,顾名思义是让大家能快速入门Android开发。 学完能让你学会如下知识点: Android的发展历程 搭建Java开发环境 搭建Android开发环境 Android Studio基础使用方法 Android Studio创建项目 项目运行到模拟器 项目运行到真实手机 Android中常用控件 排查开发中的错误 Android中请求网络 常用Android开发命令 快速入门Gradle构建系统 项目实战:看美图 常用Android Studio使用技巧 项目签名打包 如何上架市场

    19464 人正在学习 去看看 任苹蜻

1、环境搭建:进入www.android.com

2、找到developer Resource->open source

3、http://source.android.com/source/initializing.html当前历史时间的连接,根据下面的Downloading and Building->Initializing the Build Environment

然后按照左边的环境搭建就可以了

4、呵呵,还在学习中,后面可能就可以自己定制自己的Android的操作系统,就当玩玩

5、上面也说了,当前不支持Window系统的,不过可以在Window下面安装可以编辑的Ubuntu系统

 

 

2015-10-16 11:09:16 wtianok 阅读数 1253
  • 快速入门Android开发 视频 教程 android studio

    这是一门快速入门Android开发课程,顾名思义是让大家能快速入门Android开发。 学完能让你学会如下知识点: Android的发展历程 搭建Java开发环境 搭建Android开发环境 Android Studio基础使用方法 Android Studio创建项目 项目运行到模拟器 项目运行到真实手机 Android中常用控件 排查开发中的错误 Android中请求网络 常用Android开发命令 快速入门Gradle构建系统 项目实战:看美图 常用Android Studio使用技巧 项目签名打包 如何上架市场

    19464 人正在学习 去看看 任苹蜻

何为系统服务

做Android APP开发的过程中,会经常需要调用类似于下面这样的函数:

WifiManager mWifiManager = (WifiManager)getSystemService(Context.WIFI_MANAGER_SERVICE);

这个WifiManagerService就是运行在Android系统后台,为应用提供接口支持的系统服务。这些系统服务在开机的过程中启动,运行于系统进程中。

系统服务的优点

使用系统服务提供接口的三大优点就是:好用!好用!好用!(重要的事情说三遍)。APP开发者需要做的事情就是通过上面的库函数获取一个系统服务的代理,然后就可以通过代理来控制硬件。所有的扩进程调用都不需要考虑了。就算系统服务崩掉,系统服务也能自动重启。

使用系统服务的第四大优点是易于版本控制。所有的版本控制都是由Android中间件的开发者完成的,Android中间件开发者只需提供一个可用的固件即可。就算是APP和固件的版本不匹配,系统也只会报一个RemoteException,APP在捕获这个Exception之后,就能做到版本的兼容。

用这种方式提供接口的缺点也是很明显的,就是工作量都交给Android中间件的开发者了。虽然编写系统服务的代码开上去很复杂,但是跟着我下一篇博博文的步骤来做,也是能很容易的实现的。

系统服务的模型分析

Android的系统服务是一个典型的客户端/服务器模型(见下图)。

Android系统服务模型

每一个用户(APP)都拥有一个XXXManager对象的实例(客户端)。APP通过XXXManager的一个实例与XXXManagerService(服务器)进行交互。APP与XXXManager运行于用户进程,而XXXManagerService运行于系统该进程中。这种跨进程的交互完全由XXXManager来完成,用户是不需要知道其实现的细节。

在Android系统中,这样的系统服务有很多。各种Manager的代码在frameworks\base\core\java\android\os目录下,各种ManagerService的代码在frameworks\base\services\java\com\android\server。这些代码将是我们编写自己的服务的重要参考资料。当你不知道怎么实现一个功能的时候,都能从中找到参考的代码。

系统服务的实现方式

运行于用户进程的各种Manager是如何与各种ManagerService进行交互的呢?这就用到了Android里大名鼎鼎、随处可见的Binder。Binder是什么,各位自己去查一下,这里不做讨论。

总的来说,Binder的实现也有以下两种方式:

  • C/C++实现
  • Java实现

ManagerService可以完全由C++来实现,然后通过Binder这种机制与用Java实现的Manager进行交互。这样的系统服务比较典型的是MediaService。使用C++来实现的优点很明显,效率高。但是对于Java和.Net程序员的我来说,阅读面向对象的C++代码是非常痛苦的,处理各种指针是很容易出错的。所以在对效率没有那么高的要求的情况下,我推荐使用Java实现。

Java实现的ManagerService与Manager之间的交互是通过AIDL来实现的。AIDL的全称是Android Interface Describe Language。这个东西在上一篇博文里面也提到过。那个时候的用法是把AIDL文件直接交给APP,由APP来处理IPC,APP开发者就需要具备AIDL的知识。而这里,我们在系统服务于与APP之间增加了一个Manager,AIDL的代码完全由Manager来实现,这样用户就不需要知道AIDL的实现细节了(像我这样的为APP开发者考虑的系统开发者已经很少见了)。

在下一篇博文中,我将给出一个实现系统服务的步骤和例子。敬请期待!

2013-07-29 13:42:52 farsightliuht 阅读数 822
  • 快速入门Android开发 视频 教程 android studio

    这是一门快速入门Android开发课程,顾名思义是让大家能快速入门Android开发。 学完能让你学会如下知识点: Android的发展历程 搭建Java开发环境 搭建Android开发环境 Android Studio基础使用方法 Android Studio创建项目 项目运行到模拟器 项目运行到真实手机 Android中常用控件 排查开发中的错误 Android中请求网络 常用Android开发命令 快速入门Gradle构建系统 项目实战:看美图 常用Android Studio使用技巧 项目签名打包 如何上架市场

    19464 人正在学习 去看看 任苹蜻

作者:唐老师,华清远见嵌入式学院讲师。

一、 修改化定制Android4.0系统

Android系统启动时,先加载Linux内核,在Linux的framebuffer驱动里可以定制开机界面,Linux内核启动成功后,挂载根文件系统,启动Android系统,这个时候设备屏幕上开始出现滚动的Android动画,等全部的Android服务启动完毕之后,开始启动Android的HOME界面,也就是桌面。

而在这个过程中,我们可以将开机界面和Android动画全部定制为自己需要的效果。

在整个开机过程中,屏幕上会出现三次内容:
        Ø Linux启动时画面,通常是个黄嘴的小企鹅
        Ø Android系统本地启动阶段画面,是“ANDROID”文字字样
        ØAndroid系统显示系统启动阶段动画,是滚动的ANDROID动画

我们下面将三个过程中的屏幕内容都进行个性化设置。

1. 定制手机开机界面

根据前面文章介绍,我们要在Linux的framebuffer驱动里修改一些代码,让屏幕上出现我们自己的一个开机图片,如下图所示效果。

在Linux系统中,LCD显示设备的驱动都是基于framebuffer的,framebuffer我们可以看成是Android的显存,只要我们向该显存里写入数据,这些数据就可以显示在LCD上。

根据不同的LCD所支持的颜色可以分为:16位色,24位色,32位色。

学过初中物理都知道,色彩由三元色:红(R),绿(G),蓝(B)组成。

Ó16位色:一个像素点由16bit表示,占两个字节,RGB组成分为:565或555二种

Ó24位色:一个像素点由24bit表示,占三个字节,RGB每个颜色由8位组成。

Ó32位色:一个像素点由32bit表示,占四个字节,除了RGB每个颜色8位外,还有8位的Alpha的透明度,共组成32位。

很明显,位数越高,可显示的色彩越丰富,相同像素的LCD占用的显存越大,现在手机和平板基本上都使用32位色的LCD。

Android模拟器里使用16位565格式显示驱动。

既然如此,那么出现在framebuffer里的应该是16位的具体颜色值,我们从怎么知道一个图片的RGB的值呢?

还好,我们使用一款叫Image2Lcd的软件,可以将一个指定的bmp位图格式图片转换成指定的RGB格式数据的数组中。

如下图所示:

选择好图片,设置好宽度和高度及颜色位数,保存成一个头文件mylogo.h,打开里面内容如下:

[cpp] view plaincopyprint?
                            1. const unsigned char bmp[307200] = { /* 0X00,0X10,0X40,0X01,0XE0,0X01,0X01,0X1B, */
                            2. 0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
                            3. …
                            4. };

那么我们可以直接将这个头文件拷贝到内核目录中,包含到驱动里,然后直接通过bmp数组名访问图片内容。

Ó修改goldfish的fb驱动文件:

drivers/video/goldfishfb.c

在里面添加一个绘制Logo图片函数draw_logo,如下所示:

[cpp] view plaincopyprint?
                            1. 191 // MichaelTang add for bootlogo
                            2. 192 #include "mylogo.h"
                            3. 193 static int draw_logo(struct goldfish_fb *fb)
                            4. 194 {
                            5. 195          int height = fb->fb.var.yres;
                            6. 196          int width = fb->fb.var.xres;
                            7. 197
                            8. 198          printk("---------> h = %d, w = %d\n", height, width);
                            9. 199          memcpy(fb->fb.screen_base, bmp, height*width*2);
                            10. 200          return 0;
                            11. 201 }

Ó在goldfish_fb_probe函数里调用我们刚才添加的draw_logo函数:

[cpp] view plaincopyprint?
                            1. 204 static int goldfish_fb_probe(struct platform_device *pdev)
                            2. {
                            3.            …
                            4. 312          // MichaelTang add for bootlogo
                            5. 313          draw_logo(fb);
                            6.            ...
                            7. }

重新编译goldfish内核,然后将模拟器的内核指定为新编译的内核,启动后效果如下图所示:

当然,这儿的实验只是在Android的模拟器上实现的,如果在真实设备上,其步骤和上述一样,只不过驱动文件可能不一样,修改的位置不太一样,其原理是一样的。不过最后苹果和三星专利大战再次敲响,希望苹果有一天别来找我,否则,卖肾都赔不起,现在肾也不值钱了。

2.定制Android启动字样

当Linux启动完毕之后,开始挂载根文件系统ramdisk.img,通过命令行指定Linux运行Linux系统里的第一个用户进程init:

init程序由system/core/init/目录下的源码编译而成,其入口文件为:init.c,console_init_action函数就是用来打开console终端,然后在屏幕上打印“A N D R O I D”字样的,如果想修改这个值,则直接将其内容修改了,重新编译init程序,然后重新生成system.img即可,不过,一般是将其内容注释掉。

[cpp] view plaincopyprint?
                            1. 538 static int console_init_action(int nargs, char **args)
                            2. 539 {
                            3.              …
                            4. 548      fd = open(console_name, O_RDWR);
                            5. 549      if (fd>= 0)
                            6. 550          have_console = 1;
                            7. 551      close(fd);
                            8. 552
                            9. 553      if( load_565rle_image(INIT_IMAGE_FILE) ) {
                            10. 554          fd = open("/dev/tty0", O_WRONLY);
                            11. 555          if (fd>= 0) {
                            12. 556              const char *msg;
                            13. 557                  msg = "\n"
                            14. 558              "\n"
                            15. 559              "\n"
                            16. 560              "\n"
                            17. 561              "\n"
                            18. 562              "\n"
                            19. 563              "\n" // console is 40 cols x 30 lines
                            20. 564              "\n"
                            21. 565              "\n"
                            22. 566              "\n"
                            23. 567              "\n"
                            24. 568              "\n"
                            25. 569              "\n"
                            26. 570              "\n"
                            27. 571              "              A N D R O I D ";
                            28. 572              write(fd, msg, strlen(msg));
                            29. 573              close(fd);
                            30. 574          }
                            31. 575      }
                            32. 576      return 0;
                            33. 577 }

修改完之后,操作步骤如下:

[cpp] view plaincopyprint?
                            1. $ source build/envsetup.sh
                            2. $ mmm system/core/init
                            3. $ make snod

重新启动模拟器,可以发现ANDROID字样发生了相应的改变。

3. 定制Android动画

Android系统过程中会滚动Android字样的一个动画,我们可以根据自己的需要,定制这个开机动画,如下图所示:

Android的开机动画是由Linux本地程序bootanimation控制实现的,其代码在:

frameworks/base/cmds/bootanimation/,通过分析源码可知,修改Android开机动画有两种方式:

Ø 替换frameworks/base/core/res/assets/images/目录下的两个图片文件:android-logo-mask.png和android-logo-shine.png,android-logo-mask.png是镂空蒙板png图片,android-logo-shine.png是镂空蒙板后面的闪光png图片

Ø在/data/local/或/system/media/目录创建bootanimation.zip文件

bootanimation.zip文件打包前的结构为:

[cpp] view plaincopyprint?
                            1. desc.txt 动画属性描述文件
                            2. part0/ 第一阶段动画图片的目录(动画是由一帧帧图片组成的)
                            3. part1/ 第二阶段动画图片的目录

bootanimation.zip文件是直接由这几个文件打包的,打包的格式是ZIP,并且要指定用压缩打包方式(就是在打包时的压缩方式选择为存储)。

desc.txt文件的格式为

[cpp] view plaincopyprint?
                            1. 480 250 15
                            2. p 1 0 part0
                            3. p 0 10 part1

其中各个参数的意义为:

480 250 15  
图片的宽 图片的高 每秒显示帧数  
p 1 0 part0
标识符 循环的次数 阶段切换间隔时间 对应图片目录
p 0 10 part1
标识符 循环的次数 阶段切换间隔时间 对应图片目录

注:
        标识符:p 是必须的。
        循环次数:指该目录中图片循环显示的次数,0表示本阶段无限循环。
        每秒显示帧数:就是每秒显示的图片数量,决定每张图片显示的时间。
        阶段切换间隔时间:指的是该阶段结束后间隔多长时间显示下一阶段的图片,其单位是每张图片显示的时间。
        对应图片目录:就是该阶段动画的系列图片,以图片文件目录的顺序显示动画,而且图片的格式必须要为PNG。

原文来源:华清远见嵌入式学院讲师博文,原文地址:http://www.embedu.org/Column/Column678.htm

没有更多推荐了,返回首页