Android学习笔记

通用概念

Android框架图

2016071201.png

Android应用程序框架

UI基本开发

Fragment

安全策略

在Android中,安全涵盖了应用程序的部署和执行.对于部署来 说,Android应用程序必须被赋予一个数字证书才允许被安装到某个设备中.对 于运行来说,每个应用程序都在一个独立的应用程序中执行,每个进程都有一 个唯一的永久的用户ID(在安装的时候分配的).

注册应用程序需要三样东西:

  1. 一个数字证书,
  2. 一个.apk文件
  3. 以及用于将数字签名应用到.apk文件的工具(jarsigner).

注册一个应用程序步骤如下:

  • 使用Keytool创建一个自注册的证书.

   步骤1 Create a folder to hold the keystore, for example

c:\android\release\.

  步骤2 在命名行中执行如下命令:

       keytool -genkey -v -keystore "FULL PATH OF release.keystore FILE FROM STEP 1"
       -alias androidbook -storepass paxxword -keypass paxxword -keyalg RSA
       -validity 14000

keytool的参数说明如下: 2016070502.png

  • 使用Jarsigner注册.apk文件
    jarsigner -keystore "PATH TO YOUR release.keystore FILE" -storepass paxxword
    -keypass paxxword "PATH TO YOUR APK FILE" androidbook(别名)
    
  • 用zipalign作字节对齐 命令如下:
    zipalign –v 4 infile.apk outfile.apk
    

    验证一个.apk文件是否是4字节对齐,用如下命令

    zipalign –c –v 4 filename.apk
    
  • 安装应用程序
    adb install "PATH TO APK FILE GOES HERE"(安装)
    adb uninstall packagename(卸载)
    adb install –r "PATH TO APK FILE GOES HERE"(重装)
    

Framework

Audio System

Audio System 介绍

2016053001.png

AudioTrack 介绍

2016053002.png

基本说明:

  1. 用于管理来自一个Source的Audio 播放将播放的Audio 数据送给 AudioFlinger
  2. 提供播放的控制接口 API:start(), stop(), …
  3. 提供Volume 控制接口, 用于控制L/R声道各自的Volume
    • API: setVolume
    • Android 体系中有3个Audio Volume控制, 最终的输出Volume是下面3 者的乘积
      1. Master Volume
      2. Stream Type Volume
      3. Track Volume
  4. AudioTrack可以配置为下面三种Mode:
    1. PUSH MODE
    2. PULL MODE
    3. STATIC MODE
  5. AudioTrack测试程序
    /**
     * 利用AudioTrack播放一个wav文件
     */
    
    //#define LOG_NDEBUG 0
    #define LOG_TAG "AudioTrackTest"
    //#include <utils/Log.h>
    #include <media/AudioTrack.h>
    #include <system/audio.h>
    using namespace android;
    #define ALOGD printf
    int main(int argc, char *argv[])
    {
      int readNum;
      unsigned short channel;
      unsigned int sampleRate;
      FILE *fp = fopen("bzk_chic.wav", "ab+");
      if (fp == NULL) {
        ALOGD("Cannot open .wav file");
        return -1;
      }
      ALOGD("Open wav file successfully!\n");
      fseek(fp, 0x16, 0); 
      readNum= fread(&channel, 1, 2, fp);
      if (readNum < 1) {
        ALOGD("Can not read channel number: %d\n", readNum);
        fclose(fp);
        return 0;
      }
      ALOGD("channel number is %d\n", channel);
      fseek(fp, 0x18, 0); 
      readNum = fread(&sampleRate, 1, 4, fp);
      if (readNum < 1) {
        ALOGD("Cannot read sample rate: %d\n", readNum);
        fclose(fp);
        return 0;
      }
      ALOGD("Sample Rate is %d\n", sampleRate);
    
      // playing to an AudioTrack, set up mask if necessary
      audio_channel_mask_t audioMask = AUDIO_CHANNEL_OUT_STEREO;
      if (0 == audioMask) {
        return -1;
      }
      sp<AudioTrack> audioTrack = new AudioTrack(
                                                 AUDIO_STREAM_MUSIC, sampleRate, AUDIO_FORMAT_PCM_16_BIT, audioMask,
                                                 0, AUDIO_OUTPUT_FLAG_NONE);
      status_t status = audioTrack->initCheck();
      if(status != NO_ERROR) {
        audioTrack.clear();
        ALOGD("Failed for initCheck()");
        return -1;
      }
      audioTrack->start();
    
      unsigned char *buffer = new unsigned char[channel * 64 * 2];
      while (1) {
        readNum = fread(buffer, 1, channel * 64 * 2, fp);
        if (readNum <= 0)
          break;
        ALOGD("Write data : %d to AudioTrack", readNum);
        audioTrack->write(buffer, readNum);
      }
    
      fclose(fp);
      delete []buffer;
      audioTrack->stop();
    
    }
    

AudioRecord介绍

2016053003.png

基本说明:

  1. 用于管理从底层获取录音数据,并提供给上层
  2. 提供录音的控制接口 API:start(), stop()
  3. 获取声音资料的方式
    • 由上层主动调用AudioRecord::read() 来获取数据 (PULL MODE)
    • 上层提供Callback function, 通过AudioRecord主动将资料通过 Callback 给上层(PUSH MODE)

AudioPolicyService介绍

2016053004.png

AudioPolicyService在Audio system中的位置和作用

  • 仅是一个行为决策者,而不是行为的实施者
  • 真正的实施者为AudioFlinger
  • 它是一个在后台进程中的服务实体,提供的服务就是告诉实施者要怎么去 做

2016053005.png

AudioPolicyService几大功能:

  • 设备状态管理
  • 输入输出策略管理
  • 音量控制管理
  • Effect 控制管理

AudioFlinger

2016053006.png

AudioFlinger的线程循环逻辑如下所示:

2016053007.png

Media Framework

基础知识

AMessage代表一个消息,对应一个target, 根据这个target可以知道对 应的消息应该归哪个AHandler去处理。

AHandler是处理消息的基类,它有一个id,处理与这个id相关联的AMessage, 在 onMessageReceived 函数中处理各种消息。 从AHandler派生的类,都会重写该方法,以处理各种消息。

有一个全局的 ALooperRoster 对象,它维护了系统中存在的 AHandler对 象。

ALooper对象,通过 registerHandler 接口将AHandler对象注册给 ALooperRoster 对象维护的AHandler列表中。

主要代码路径

  • MediaPlayer.java
    • Java 层的 MediaPlayer 接口,APK 主要通过 call 它的接口实现播放功能
    • code path: framework/base/media/java/android/media/MediaPlayer.java
  • Media JNI
    • MediaPlayer java 层与 native 层的接口
    • code path: framework/base/media/jni/androidmediaMediaPlayer.cpp
    • output:libmediajni.so
  • MediaPlayer
    • MediaPlayer Native 层 client 端接口
    • code path: framework/av/media/libmedia/
    • output:libmedia.so
  • Media Service
    • Native 层真正实现播放功能的 Service 进程
    • code path: framework/av/media/mediaserver framework/av/media/libmediaplayerservice
    • output: mediaserver libmediaplayerservice.so

Stagefright

  • StagefrightPlayer
    • 负责提供 player 的接口
    • code path: framework/av/media/libmediaplayerservice/StagefrightPlayer.cpp
  • AwesomePlayer
    • 真正实现 playback 功能的模块
    • code path: : framework/av/media/libstagefright
  • DataSource
    • 提供 Source 数据,可以是本地文件,也可以是网络数据
    • code path: : framework/av/media/libstagefright
  • MediaSource
    • MediaSource使用到了DataSoure和OMX,可以提供解码后的供显示的数据
    • code path: framework/av/media/libstagefright/
  • OMXClient
    • 使用 OMX 的 client 端
    • code path: framework/av/media/libstagefright/
  • OMX
    • 提供一套接口接到底层的 decoder 进行解码
    • code path: framework/av/media/libstagefright/omx

NuPlayer

2016053008.png

OpenMAX

OpenMAX is a royalty-free, cross-platform API. OpenMAX Working Group has been formed by the Khronos Group. The Standard for Media Library Portability. Reduce the cost and complexity of porting multimedia software to new processors and architectures. 分为 OpenMAX DL, IL, AL 三层,Android 上只用到 OpenMAX IL.

Graphics

Android Graphics Pipeline Overview

  • Android Graphics Pipeline

    2016052601.png

    如图,对于一些Buffer,有些通过GPU处理后,再送给HWComposer,有些则 直接送给HWComposer处理。

  • BufferQueue

    2016052602.png

    关于BufferQueue的说明如下:

    1. manages flow of buffers between producers and consumers
    2. two queues
    3. producers dequeue unused buffers, fill them, then queue them
    4. consumers acquire filled buffers, use them, then release them when done.
  • SurfaceFlinger

    它的主要使用是:

    1. Responsible for compositing all windows into the display(s)
    2. Just another GL client
  • HW Composer

    一开始是为了加速叠图而准备的一个HAL,目前作为所有显示的HAL。

    • Overlay
      • Overlay 是什么

        在android 上面,屏幕上输出的画面都是由多个图层(layer)合成 (compsing)得到的结果. 所以在android上面,图像的合成是非常普 通而且常见(频繁)的操作, 如果有一个简单而省电的hardware(hw)来负 责图像合成, 可以很有效的降低功耗,而且也可以降低GPU的loading.

        Overlay 就是一个专门负责图像合成的一个hw. 相比GPU 而言, overlay 是一个非常简单图像处理hw. 和GPU具有的庞大的图形功能不 同, overlay只能负责简单的图像合成动作.

        由于overlay 功能简单,所以hw的实现上相比GPU也要简单很多,工作起 来也会非常省电.

      • Overlay 有什么限制

        由于overlay hw很简单,所以它只能处理简单的图像合成工作,太复杂 的图像合成工作还是要GPU来协助完成.

        overlay 无法处理的case:

        1. 需要旋转的图像
        2. 需要缩放的图像
        3. 图层超过4层

        不过对于普通的android应用场景来说,很少会出现上述的那些cases.

      • 没有overlay HW,图像合成流程

        Surfaceflinger把需要合成的layers 交给GPU 做composing, 最终输出 到屏幕。

        2016071204.png

      • 有Overlay HW, 图像合成的流程

        Surfaceflinger把需要合成的layers 交给ovl做composing, 最终输出 到屏幕。

        2016071205.png

      • 有overlay HW,但需要GPU做图像合成流程

        Overlay不能处理的layers, 会交给GPU做图像合成,GPU把图像合成为 一个layer, 然后再通过overlay 输出.

        2016071206.png

Android Sync Framework

  • 定义

    Synchronization between consumers and producers who are from different hardware components to use a buffer atomically

  • 应用背景

    在复杂的DMA管线如图形管线(多媒体,摄像头,GPU以及显示设备),一 个buffer的消费者需要知道生产者什么时候完成生产(即创建一个Buffer, 并往里面放置消费者所需要的数据)。同样地,生产者也需要知道消费者 什么时候使用它创建的Buffer,以便它可以重新使用这个Buffer。而且, 一个Buffer可能被多个不同的消费者使用不同的时间。另外,一个消费者 可能需要互斥地消费多个Buffer,等等,有一个问题应运而生,就是如何 保证多个消费者之间同步使用Buffer,以及生产者与消费者协调使用 Buffer。因为Buffer是一个共享资源,且任何消费者或生产者对Buffer的 使用都是排他性的(因为它们属于不同的硬件单元或模块),大体看来, 需要解决如下两个问题:

    1. 消费者与生产者之间对Buffer的同步访问。
    2. 消费者之间对Buffer的同步访问。
  • 目标
    1. Provide a simple API to let components signal when buffers are ready/released.
    2. Allow synchronization primitives to be passed between processes and between userspace and the kernel.
    3. Allow implementers to exploit hardware sync support
    4. Provide visibility into the graphics pipeline for debugging
  • Software Stacks

    2016052609.png

  • 实现
    1. synctimeline

      2016052603.png

      • Represents monotonically increasing counter
      • Generally one instance per driver context
      • allows hardware specific implementation
      • swsync implementation provided
    2. syncpt

      2016052604.png

      • Represents a specific values on a parent timeline
      • 3 states
        • active
        • signaled
        • error
      • starts active and transitions once to either signaled or error
    3. syncfence

      2016052605.png

      • A collection of syncpts
      • Backed by a file and can be passed to userspace.
      • Main primitive drivers and userspace use to describe sync events/dependencies.
      • Fences are a promise by the kernel
        • that work has been queued
        • and will complete in a "timely" manner
      • Starts active and transitions to signaled with all of its syncpts become signaled or one becomes errored
      • The list of syncpts is immutable after fence creation
      • A syncpt can only be in one fence.
      • Two fences can be merged to create a third fence containing copies of the sync points in both.
      • Sync Merge
        • Before Merge

          2016052606.png

        • After Merge

          2016052607.png

    4. 代码
      • supported in android-3.10 kernel + staged for quite some time
      • Core
        • drivers/staging/android/sync.c
        • drivers/staging/android/sync.h
      • swsync
        • drivers/staging/android/sw_sync.c
        • drivers/staging/android/sw_sync.h
      • 接口声明

        2016052608.png

    5. 实现synctimeline的建议

      在实现前,先考虑是否可以直接使用swsync, 以swsync为起点。

      • Don'ts
        • Don't base a timeline on any "real" time.
        • Don't allow userspace to explicitly
          • create a fence
          • signal a fence
        • Don't access synctimeline, syncpt, or syncfence elements explicitly.
      • Dos
        • Do provide useful names
        • Do implement timelinevalue str and ptvaluestr
        • Do implement fill driverdata

Input System

Input Event Process Flow

2016053009.png

Architecture (ICS)

2016053010.png

Architecture (JB)

2016053011.png

Wifi Framework

传统WiFi

Android Framework中的wifi代码分为两部分,一部分面向应用开发者,提供 公共接口给应用开发者,另一部分则是框架的实现灵魂,代码分别位于: Android 5.1

  • frameworks\base\wifi\java\android\net\wifi
  • frameworks\opt\net\wifi\service
  • WifiConfigStore

P2P/Miracast

  • 开启WifiSink的调用序列

    DisplayManager.requestEnableSink DisplayManager.enableSink DisplayManagerGlobal.enableSink DisplayManagerService.enableSink DisplayManagerService.enableSinkInternal WifiDisplayAdapter.requestEnableSinkLocked WifiDisplayController.requestEnableSink

    WifiDisplaySinkActivity WfdSinkSurfaceFragment WfdSinkExt.setupWfdSinkConnection WfdSinkExt.setWfdMode(true) WifiDisplayAdapter.requestEnableSinkLocked … WifiDisplayController.startWaitConnection WifiDisplayController.enterSinkState

Global Settings

设置和访问一个全局变量。

Settings.java

//frameworks/base/core/java/android/provider/Settings.java
public final class Settings {
    public static final String WIFI_AUTO_CONNECT = "wifi_auto_connect";
    ...
    MOVED_TO_GLOBAL.add(Settings.Global.WIFI_AUTO_CONNECT);
}

defaults.xml

<!-- /packages/SettingsProvider/res/values/defaults.xml -->
<integer name="def_wifi_auto_connect">0</integer>

DatabaseHelper.java

public class DatabaseHelper extends SQLiteOpenHelper {
    ...
    loadIntegerSetting(stmt, Settings.Global.WIFI_AUTO_CONNECT,
                       R.integer.def_wifi_auto_connect);

    ...
}

访问

//读取
Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.WIFI_AUTO_CONNECT);
//写入
Settings.Global.putInt(getContentResolver(), Settings.Global.WIFI_AUTO_CONNECT, 0);