Android+WM9714调试

Binder—ServiceManager 启动过程 Binder—ServiceManager 启动过程一、main:入口函数1.1 binder_open:打开和映射 Binder 设备文件1.2 binder_become_context_manager:注册为 Binder 进程间通信机制的上下文管理者1.3 binder_loop:循环等待 Client 进程请求二、ServiceManager 启动过程时序图 一、main:入口函数 [–>service_manager.c, main()] int main(int argc, char * 阅读详情

s3c6410平台,codec为WM9714(驱动可使用WM9713的),使用ALSA,android版本1.5. MID上移植android以来一直没有声音。

首先确认AC97的硬件连接,AC-LINK通讯是否正常,这里使用到wince中的init寄存器组,在

sound/soc/codecs/wm9713.c中替换static const u16 wm9713_reg[]相应的寄存器,以适配硬件

配置。

做完这部分工作后,应该启动时就会有噗噗声,如果能听到,说明硬件连接正常,软件读写CODEC正常.

在网上查了很多资料,很多说要配置/system/etc/asound.conf,可我也不知道怎么去配,找了一堆的资料学习,然后对照wm9713.c中

的参数和别人的asound.conf,终于弄了一份上去,不过似乎不起说明作用,用alsa_aplay z.wav还是提示错误"Unable to install

hw params:",以下函数出错:

err = snd_pcm_hw_params(handle, params);

也就是说真正要和硬件交互的时候错了。。 终端里用logcat命令查看log信息,发现还是一直打印消息:

I/ServiceManager( 1185): Waiting for sevice media.audio_flinger...

I/ServiceManager( 1185): Waiting for sevice media.audio_flinger...

W/AudioSystem( 1185): AudioFlinger not published, waiting...

I/ServiceManager( 1185): Waiting for sevice media.audio_flinger...

I/ServiceManager( 1185): Waiting for sevice media.audio_flinger...

I/ServiceManager( 1185): Waiting for sevice media.audio_flinger...

I/ServiceManager( 1185): Waiting for sevice media.audio_flinger...

I/ServiceManager( 1185): Waiting for sevice media.audio_flinger...

W/AudioSystem( 1185): AudioFlinger not published, waiting...

I/ServiceManager( 1185): Waiting for sevice media.audio_flinger...

I/ServiceManager( 1185): Waiting for sevice media.audio_flinger...

这说明audio服务还是没有正常启动起来! 于是查android源代码,在frameworks/base/libs/audioflinger/AudioFlinger.cpp中,

void AudioFlinger::instantiate() {

LOGD("*******++AudioFlinger::instantiate()/n");

    defaultServiceManager()->addService(

            String16("media.audio_flinger"), new AudioFlinger());

LOGD("*******--AudioFlinger::instantiate()/n");

}

有调用此函数将自己添加到服务管理器,但是不知道什么原因,系统的服务管理器并没有

得到media.audio_flinger的管理权,所以就会出现上面的一直等待的情况。

跟进new AudioFlinger()

先创建一个audio硬件对象 mAudioHardware = AudioHardwareInterface::create();

AudioHardwareInterface* AudioHardwareInterface::create()

{

    /*

     * FIXME: This code needs to instantiate the correct audio device

     * interface. For now - we use compile-time switches.

     */

    AudioHardwareInterface* hw = 0;

    char value[PROPERTY_VALUE_MAX];

#ifdef GENERIC_AUDIO

    hw = new AudioHardwareGeneric();

#else

    // if running in emulation - use the emulator driver

    if (property_get("ro.kernel.qemu", value, 0)) {

        LOGD("Running in emulation - using generic audio driver");

        hw = new AudioHardwareGeneric();

    }

    else {

        LOGV("Creating Vendor Specific AudioHardware");

        hw = createAudioHardware();

    }

#endif

    if (hw->initCheck() != NO_ERROR) {

        LOGW("Using stubbed audio hardware. No sound will be produced.");

        delete hw;

        hw = new AudioHardwareStub();

    }

#ifdef DUMP_FLINGER_OUT

    // This code adds a record of buffers in a file to write calls made by AudioFlinger.

    // It replaces the current AudioHardwareInterface object by an intermediate one which

    // will record buffers in a file (after sending them to hardware) for testing purpose.

    // This feature is enabled by defining symbol DUMP_FLINGER_OUT.

    // The output file is FLINGER_DUMP_NAME. Pause are not recorded in the file.

    hw = new AudioDumpInterface(hw);    // replace interface

#endif

    return hw;

}

这里hw = createAudioHardware();才是真正的初始化主体:

    android::AudioHardwareInterface *createAudioHardware(void) {

        return new android::AudioHardwareALSA();

    }

也就是AudioHardwareInterface::create()返回的是实际的硬件初始化对象AudioHardwareALSA的指针。

接着跟进:

AudioHardwareALSA::AudioHardwareALSA() :

    mOutput(0),

    mInput(0),

    mIPC(0) // sangsu fix : for IPC

{

    snd_lib_error_set_handler(&ALSAErrorHandler);

    mMixer = new ALSAMixer;  //创建混合器对象

    mIPC = new AudioHardwareIPC; // sangsu fix : IPC init

}

再看mIPC = new AudioHardwareIPC;

AudioHardwareIPC::AudioHardwareIPC() :

    mClient(NULL)

{

LOGD("### %s", __func__);

    int err = 0;

    mClient = OpenClient_RILD();

    if (mClient == NULL){

        LOGE("[*] OpenClient_RILD() error/n");

        err = 1;

    }

    if (RegisterRequestCompleteHandler(mClient, RIL_REQUEST_OEM_HOOK_RAW,

onRawReqComplete) != RIL_CLIENT_ERR_SUCCESS){

        LOGE("[*] RegisterRequestCompleteHandler() error/n");

        err = 1;

    }

    if (RegisterUnsolicitedHandler(mClient, 11004, onUnsol) !=

RIL_CLIENT_ERR_SUCCESS){

        LOGE("[*] RegisterUnsolicitedHandler() error/n");

        err = 1;

    }

    if (Connect_RILD(mClient) != RIL_CLIENT_ERR_SUCCESS){

        LOGE("[*] Connect_RILD() error/n");

        err = 1;

    }

    if (!err) LOGD("Success Initializing IPC");

    else LOGE("Failed Initializing IPC");

}

在logcat里也确实有打印出这些出错信息,说明RIL服务没有运行。

再次回到AudioFlinger::AudioFlinger(),创建音频接口对象后,接着打开OutputStream

AudioStreamOut *hwOutput = mAudioHardware->openOutputStream(AudioSystem::PCM_16_BIT, 0, 0, &status);

实际调用函数:

AudioStreamOut *

AudioHardwareALSA::openOutputStream(int format,

                                    int channelCount,

                                    uint32_t sampleRate,

                                    status_t *status)

{

AutoMutex lock(mLock);

LOGD("++AudioHardwareALSA::openOutputStream()/n");

    // only one output stream allowed

    if (mOutput) {

        *status = ALREADY_EXISTS;

        return 0;

    }

    AudioStreamOutALSA *out = new AudioStreamOutALSA(this);

    *status = out->set(format, channelCount, sampleRate);

    if (*status == NO_ERROR) {

        mOutput = out;

        // Some information is expected to be available immediately after

        // the device is open.

        uint32_t routes = mRoutes[mMode];

        mOutput->setDevice(mMode, routes);

    }

    else {

        delete out;

    }

LOGD("--AudioHardwareALSA::openOutputStream()/n");

    return mOutput;

}

进入new AudioStreamOutALSA(this)

AudioStreamOutALSA::AudioStreamOutALSA(AudioHardwareALSA *parent) :

    mParent(parent),

    mPowerLock(false)

{

    static StreamDefaults _defaults = {

        devicePrefix   : "AndroidPlayback",

        direction      : SND_PCM_STREAM_PLAYBACK,

        format         : SND_PCM_FORMAT_S16_LE,   // AudioSystem::PCM_16_BIT

        channels       : 2,

        sampleRate     : DEFAULT_SAMPLE_RATE,

        latency        : 250000,                  // Desired Delay in usec

        // sangsu fix : optimizing output buffer size

        bufferSize     : 2048,                   // Desired Number of samples

        };

    setStreamDefaults(&_defaults);

}

这里就是设置的默认OutStream参数了。。 再看out->set(format, channelCount, sampleRate);

            status_t                set(int format          = 0,

                                        int channelCount    = 0,

                                        uint32_t sampleRate = 0) {

                return ALSAStreamOps::set(format, channelCount, sampleRate);

            }

status_t ALSAStreamOps::set(int      format,

                            int      channels,

                            uint32_t rate)

{

    if (channels != 0)

        mDefaults->channels = channels;

    if (rate != 0)

        mDefaults->sampleRate = rate;

    switch(format) {

      // format == 0

        case AudioSystem::DEFAULT:

            break;

        case AudioSystem::PCM_16_BIT:

            mDefaults->format = SND_PCM_FORMAT_S16_LE;

            break;

        case AudioSystem::PCM_8_BIT:

            mDefaults->format = SND_PCM_FORMAT_S8;

            break;

        default:

            LOGE("Unknown PCM format %i. Forcing default", format);

            break;

    }

    return NO_ERROR;

}

也就是继续设置default参数。 然后调用mOutput->setDevice(mMode, routes);

status_t AudioStreamOutALSA::setDevice(int mode, uint32_t newDevice)

{

    AutoMutex lock(mLock);

    return ALSAStreamOps::setDevice(mode, newDevice);

}

status_t ALSAStreamOps::setDevice(int mode, uint32_t device)

{

    // Close off previously opened device.

    // It would be nice to determine if the underlying device actually

    // changes, but we might be manipulating mixer settings (see asound.conf).

    //

    close();

    const char *stream = streamName();

    status_t    status = open (mode, device);

    int     err;

    if (status != NO_ERROR)

        return status;

    err = snd_pcm_hw_params_any(mHandle, mHardwareParams);

    if (err < 0) {

        LOGE("Unable to configure hardware: %s", snd_strerror(err));

        return NO_INIT;

    }

    status = setPCMFormat(mDefaults->format);

    // Set the interleaved read and write format.

    err = snd_pcm_hw_params_set_access(mHandle, mHardwareParams,

                                       SND_PCM_ACCESS_RW_INTERLEAVED);

    if (err < 0) {

        LOGE("Unable to configure PCM read/write format: %s",

            snd_strerror(err));

        return NO_INIT;

    }

    //

    // Some devices do not have the default two channels.  Force an error to

    // prevent AudioMixer from crashing and taking the whole system down.

    //

    // Note that some devices will return an -EINVAL if the channel count

    // is queried before it has been set.  i.e. calling channelCount()

    // before channelCount(channels) may return -EINVAL.

    //

    status = channelCount(mDefaults->channels);

    if (status != NO_ERROR)

        return status;

    // Don't check for failure; some devices do not support the default

    // sample rate.

    sampleRate(mDefaults->sampleRate);

    // Disable hardware resampling.

    status = setHardwareResample(false);

    if (status != NO_ERROR)

        return status;

    snd_pcm_uframes_t bufferSize = mDefaults->bufferSize;

    unsigned int latency = mDefaults->latency;

    // Make sure we have at least the size we originally wanted

    err = snd_pcm_hw_params_set_buffer_size(mHandle, mHardwareParams, bufferSize);

    if (err < 0) {

        LOGE("Unable to set buffer size to %d:  %s",

             (int)bufferSize, snd_strerror(err));

        return NO_INIT;

    }

    // Setup buffers for latency

    err = snd_pcm_hw_params_set_buffer_time_near (mHandle, mHardwareParams,

                                                  &latency, NULL);

    if (err < 0) {

        /* That didn't work, set the period instead */

        unsigned int periodTime = latency / 4;

        err = snd_pcm_hw_params_set_period_time_near (mHandle, mHardwareParams,

                                                      &periodTime, NULL);

        if (err < 0) {

            LOGE("Unable to set the period time for latency: %s", snd_strerror(err));

            return NO_INIT;

        }

        snd_pcm_uframes_t periodSize;

        err = snd_pcm_hw_params_get_period_size (mHardwareParams, &periodSize, NULL);

        if (err < 0) {

            LOGE("Unable to get the period size for latency: %s", snd_strerror(err));

            return NO_INIT;

        }

        bufferSize = periodSize * 4;

        if (bufferSize < mDefaults->bufferSize)

            bufferSize = mDefaults->bufferSize;

        err = snd_pcm_hw_params_set_buffer_size_near (mHandle, mHardwareParams, &bufferSize);

        if (err < 0) {

            LOGE("Unable to set the buffer size for latency: %s", snd_strerror(err));

            return NO_INIT;

        }

    } else {

        // OK, we got buffer time near what we expect. See what that did for bufferSize.

        err = snd_pcm_hw_params_get_buffer_size (mHardwareParams, &bufferSize);

        if (err < 0) {

            LOGE("Unable to get the buffer size for latency: %s", snd_strerror(err));

            return NO_INIT;

        }

        // Does set_buffer_time_near change the passed value? It should.

        err = snd_pcm_hw_params_get_buffer_time (mHardwareParams, &latency, NULL);

        if (err < 0) {

            LOGE("Unable to get the buffer time for latency: %s", snd_strerror(err));

            return NO_INIT;

        }

        unsigned int periodTime = latency / 4;

        err = snd_pcm_hw_params_set_period_time_near (mHandle, mHardwareParams,

                                                      &periodTime, NULL);

        if (err < 0) {

            LOGE("Unable to set the period time for latency: %s", snd_strerror(err));

            return NO_INIT;

        }

    }

    LOGD("Buffer size: %d", (int)bufferSize);

    LOGD("Latency: %d", (int)latency);

    mDefaults->bufferSize = bufferSize;

    mDefaults->latency = latency;

    // Commit the hardware parameters back to the device.

    err = snd_pcm_hw_params(mHandle, mHardwareParams);

    if (err < 0) {

        LOGE("Unable to set hardware parameters: %s", snd_strerror(err));

        return NO_INIT;

    }

    status = setSoftwareParams();

    return status;

}

在调用了一系列设置参数的函数后,最后调用err = snd_pcm_hw_params(mHandle, mHardwareParams);

将参数写入到硬件。

完成这个过程后,接着创建 MixerThread ,AudioRecordThread ,至此media.audio_flinger服务初始化完毕。

在我们的MID上,wince6.0下有调试WM9714通过,可正常发声和录音。可android下使用alsa_aplay测试总是出现问题。

一气之下重新解压android包,编译,烧写ramdisk-uboot.img,system.img,userdata.img,偶然在android界面点开music player,找

到SD卡上的音乐,竟然能发出不连续的声音,欣喜若狂!  赶紧在kernel中关掉打印信息,再次进入播放,悠扬的声音出来了!

晕~~~  竟然不用动什么东西! 也不需要配asound.conf,所需要注意的是测试在android界面里用music player播放就好,

alsa_aplay还是在这种场合不合适,因为android加载,占用了音频设备。每次烧写也应该带上ramdisk-uboot.img,这个很重要。

我的alsa_aplay版本:

# alsa_aplay --version

aplay: version 1.0.19 by Jaroslav Kysela <perex@perex.cz>

 

linux_sound_alsa_Android+alsa音频系统中的几个问题 1.Android+alsa音频体系大体结构:    从alsa的角度由下往上看:linux中有alsa驱动层,其中,/sound/core/pcm_native.c文件中的snd_pcm_f_ops是alsa驱动层对alsa_lib层的接口;Android中有alsa_lib层(在donut/external/alsa_lib目录下)和alsa应用层;    从Android的角度由下往 阅读详情

相关推荐

比较几款国际主流的电子元器件及物料清单管理软件 – 工具汇总

Arenasolution 老牌的基于云计算物料清单管理软件,bom.com就是他们家的,10天免费试用,功能被分成4个不同的产品, 和传统ERP功能上有重叠,偏向于物流生产规划,一定程度可以取代ERP的生产规划模块,平均价格70美元/月/席位。网页客户端,不支持离线   SiliconExpert 曾经的老牌物料清单管理软件,后被Arrow 收购,14天免费试用,功能被分成4个不同的产品

u012062784的专栏 7236

android+WM9714(AC97)调试

s3c6410平台,codec为WM9714(驱动可使用WM9713的),使用ALSA,android版本1.5. MID上移植android以来一直没有声音。 首先确认AC97的硬件连接,AC-LINK通讯是否正常,这里使用到wince中的init寄存器组,在sound/soc/codecs/wm9713.c中替换static const u16 wm9713_reg[]相应的寄

knock的专栏 1万+

Facebook登录协议逆向实战:从加密参数到完整流程解析(附Python代码)

本文深入解析Facebook登录协议的逆向工程,重点拆解`lgndim`和`encpass`等加密参数的生成逻辑,并提供完整的Python实现代码。通过Base64解码和RSA加密技术,帮助开发者理解并实现Facebook登录流程,同时涵盖工程优化与安全实践。

weixin_30687051的博客 477

Linux下常见命令

=============安装和登陆命令======================================== Mount:挂载命令。把存储介质指定成系统中的某个目录,比如挂载光驱mount /dev/cdrom把CDROM挂载,可在目录/mnt/cdrom下查看内容。 umount:卸载命令,比如umount /dev/cdrom exit:退出终端命令。 shutdown:关闭...

weixin_30493401的博客 137

【寄存器模型】一、一个简单的寄存器模型

在描述寄存器模型之前,首先来了解一下实际寄存器的组成结构:如下图所示的DUT内部真实的寄存器寄存器中最小的一个单位是域(field),域是由一个或多个bit拼接而成的。一个或多个域就构成了一个寄存器(reg)。一个或多个寄存器就构成了一个块(block)。将DUT中的寄存器抽象出来,建立寄存器模型,如下图所示:uvm library已经定义好了field、reg、block等相关的概念,构建寄存器模型时,只需要继承这些类即可。:构建寄存器模型中的域段。uvm_reg。...

carrotbanana的博客 5368

SquareLine Studio汉化版安装激活全攻略:LVGL嵌入式UI设计从入门到出代码

嵌入式GUI开发中,LVGL作为轻量级开源图形库,广泛应用于STM32、ESP32等MCU平台。可视化设计器通过拖拽生成LVGL代码,大幅提升UI开发效率。SquareLine Studio正是这类工具的代表,支持界面设计、事件绑定与代码导出。其安装、汉化与激活是初学者常见门槛,尤其涉及LVGL版本匹配、字体配置及FreeRTOS移植等关键环节。本文围绕汉化版安装、一个月免费激活码使用及最小可用流程展开,帮助开发者快速上手LVGL界面设计,规避常见环境与集成问题。

weixin_29189987的博客 421

龙芯1B核心板中为什么有的wav格式无法播放(Unable to install hw params)

原因很简单,就是一个采样率的问题,龙芯1B中的采样率必须是48000HZ 录音也是一个道理,录音的时候需要设置采样率位48000HZ #arecord -Dhw:0,0 -d 10 -f cd -r 48000 -c 2 -t wav test.wav //-r,这个参数指的就是采样率 如果在aplay某文件时候,出现 aplay:set_params:1361:Unable to instal......

baidu_31788709的博客 2978

Zemax操作33--5倍激光扩束器

5倍扩束

lzy750750的博客 2932

8.声卡驱动03-自己实现alsa驱动-虚拟声卡-缓存

平台:ubuntu 16.04,kernel版本是4.15.0, 理论任何平台都可以,甚至是android,只要能编译通过。 需要完成的功能:传说中的回采,做过语音方案的童鞋应该能懂,就是播放的音频,录音录回去。因为是虚拟的声卡,不涉及硬件操作,也只能这样看点效果。 目的:当然是为了能更直观的理解alsa驱动框架。虚拟出一个声卡,不涉及复杂的硬件操作,不涉及复杂的硬件调试,只关心数据流怎么一步一步传给应用的。 1.数据是怎么交互的 以playback为例 驱动程序分配一个buffer APP不断写

u014056414的博客 7054

基于深度学习DNN LSTM网络的光伏发电量预测 完整代码数据 可直接运行

基于深度学习DNN LSTM网络的光伏发电量预测 完整代码数据 可直接运行

2079

灰色预测GM(1,n)模型_python

灰色系统理论及其应用系列博文: 一、灰色关联度分析法(GRA)_python 二、灰色预测模型GM(1,1) 文章目录一、GM(1,n)算法二、示例2.1 数据:2.2 代码_使用GM(1,n)城市用水总量2.3 结果分析 一、GM(1,n)算法 二、示例 注:数据均来自论文《基于灰色系统理论的贵阳市城市用水总量预测》 2.1 数据: data.csv 年份,城区人口,建成区面积,供水总量,用水人口,人口综合用水指标,城市用水总量 2002, 191.85, 98.00, 26396.00,

qq_34229228的博客 1万+

解决android录音失真BUG && Android上的alsa

在6410+WM9714的ANDROID平台上测试MIC IN录音功能,出现一个BUG。在该平台声音播放是完全正常的,但是录音后再播放刚录的声音,会有失真,同样的录音文件在电脑上播放也一样,说明是录音问题。后来通过打印9714的寄存器,发现录音频率是8000HZ,放音频率是44100HZ,这时基本上可以确定是由这个不匹配引起的。 我在android代码里:AudioHardwareAL...

zhandoushi的专栏 4544

【YOLOv8全方位学习手册】第四章 数据增强:从扩充数据到塑造模型的认知边界

"""使用 Albumentations 做自定义增强,兼容 YOLO 格式"""])# 转成 numpy# boxes 必须是 [[x_min,y_min,x_max,y_max], ...]# 在数据加载时调用你可以把集成到 PyTorch 的 Dataset 类里,或使用 Ultralytics 自带的DataLoader。

VectorShift的博客 211

Android录音失真具体解决方案

在6410+WM9714的Android平台上测试MIC IN录音功能,出现一个BUG。在该平台声音播放是完全正常的,但是录音后再播放刚录的声音,会有失真,同样的录音文件在电脑上播放也一样,说明是Android录音失真的问题。后来通过打印9714的寄存器,发现录音频率是8000HZ,放音频率是44100HZ,这时基本上可以确定是由这个不匹配引起的。  我在Android代码里:AudioHard

曹浩洋的专栏 2530

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

Android数据流详解

Android数据流详解

码夫的专栏 5979

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

android 录音失真

我们曾经在一篇文章中为大家详细介绍过有关Android多媒体录制功能的一些实现方法。其中就包括对录音的实现方法。今天我们可以通过这篇文章介绍的内容详细了解Android录音失真的具体解决方法,以帮助大家解决实际应用中出现的问题。 在6410+WM9714的Android平台上测试MIC IN录音功能,出现一个BUG。在该平台声音播放是完全正常的,但是录音后再播放刚录的声音,会有失真,同样的录...

yunshangbuhe1的博客 337

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

S5PV210 ANDROID2.2 BSP

WY-S5PV210 V3 ANDROID2.2BSP软件资源 类别 功能特性 描述 Bootloader u-boot.bin 版本:u-boot-1.3.4主要功能:1、支持Nand Flash擦除、读、写2、支持USB 下载镜像3、支持打印、设置、保存环境变量4、支持SD卡读写5...

weixin_33691700的博客 150

linux dev controlC0,关于Linux的alsa音频问题解决

到今日,在android平台上调试声音的方面终于有了进展,原来是需要改一个配置文件,目前只是解决了问题,具体原因以后再分析。硬件平台是6410+WM9714,软件平台是ANDROID。现在由于android系统启动时,加载音频服务不成功,处于一个死循环中,老停在登陆界面。此时打印的Logcat信息如下:.........AudioFlinger not published, waiting...W...

weixin_35458961的博客 1017

关于Linux的alsa音频问题解决

到今日,在android平台上调试声音的方面终于有了进展,原来是需要改一个配置文件,目前只是解决了问题,具体原因以后再分析。硬件平台是6410+WM9714,软件平台是ANDROID。现在由于android系统启动时,加载音频服务不成功,处于一个死循环中,老停在登陆界面。此时打印的Logcat信息如下:  .........  AudioFlinger not published, waiti

GameLife_lch的专栏 3434

看看培训中心培训Android系统开发培训都讲些啥

华清远见 step1 学习目标     掌握Andriod开发环境的搭建方法,熟悉Android在硬件平台上的移植方法。 1 Andriod 开发环境搭建     1.1 andriod sdk介绍     1.2 eclipse中装载Android插件     1.3 编写、调试、运行Hello, Android!程序

wgembed的专栏 1014
上一篇: Android2.0 Eclair在S3C6410上运行成功
下一篇: android的文件系统结构及其引导过程的初步理解
willand1981
博客等级 码龄18年 136粉丝 31原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值