Android在标准linux基础上对休眠唤醒的实现(三)

2024-04-22 17:48

本文主要是介绍Android在标准linux基础上对休眠唤醒的实现(三),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

四、android层源码解析

在linux之上经过android的软件堆层层封装,最终在上层的java应用程序中使用。休眠唤醒也是从最上层发出的命令,然后一层一层地将参数解析,往最底层传,最后走上标准linux的休眠唤醒之路。

       这一部分将会初略分析休眠唤醒机制上linux之上所走的路线。

      

       在linux之上,存在一个hal层,专门做和linux内核设备打交道的事情,这里也不例外。休眠唤醒机制的hal层源码位于:@hardware/libhardware_legacy/power/power.c

该文件源码比较简单,下面列举重点片段:

       enum {

    ACQUIRE_PARTIAL_WAKE_LOCK = 0,

    RELEASE_WAKE_LOCK,

    REQUEST_STATE,

    OUR_FD_COUNT

};

const char * const NEW_PATHS[] = {

    "/sys/power/wake_lock",

    "/sys/power/wake_unlock",

    "/sys/power/state"

};

static int g_initialized = 0;

static int g_fds[OUR_FD_COUNT];

static const char *off_state = "mem";

static const char *on_state = "on";

 

static int  open_file_descriptors(const char * const paths[])

{

    int i;

    for (i=0; i<OUR_FD_COUNT; i++) {

        int fd = open(paths[i], O_RDWR);

        if (fd < 0) {

            fprintf(stderr, "fatal error opening /"%s/"/n", paths[i]);

            g_error = errno;

            return -1;

        }

        g_fds[i] = fd;

    }

 

    g_error = 0;

    return 0;

}

 

static inline void  initialize_fds(void)

{

    if (g_initialized == 0) {

        if(open_file_descriptors(NEW_PATHS) < 0) {

            open_file_descriptors(OLD_PATHS);

            on_state = "wake";

            off_state = "standby";

        }

        g_initialized = 1;

    }

}

 

int  acquire_wake_lock(int lock, const char* id)

{

    initialize_fds();

    if (g_error) return g_error;

    int fd;

 

    if (lock == PARTIAL_WAKE_LOCK) {   // 上层传下来的lock type

        fd = g_fds[ACQUIRE_PARTIAL_WAKE_LOCK];

    }

    else {

        return EINVAL;

    }

 

    return write(fd, id, strlen(id));

}

 

int  release_wake_lock(const char* id)

{

    initialize_fds();

 

//    LOGI("release_wake_lock id='%s'/n", id);

 

    if (g_error) return g_error;

 

    ssize_t len = write(g_fds[RELEASE_WAKE_LOCK], id, strlen(id));

    return len >= 0;

}

 

int set_screen_state(int on)

{

    QEMU_FALLBACK(set_screen_state(on));

    LOGI("*** set_screen_state %d", on);

 

    initialize_fds();

    if (g_error) return g_error;

 

    char buf[32];

    int len;

    if(on)

        len = sprintf(buf, on_state);

    else

        len = sprintf(buf, off_state);

    len = write(g_fds[REQUEST_STATE], buf, len);

    if(len < 0) {

        LOGE("Failed setting last user activity: g_error=%d/n", g_error);

    }

    return 0;

}

 

Hal层的代码在jni层中被使用,源码位于:frameworks/base/core/jni/android_os_Power.cpp,代码片段如下:

static void  acquireWakeLock(JNIEnv *env, jobject clazz, jint lock, jstring idObj)

{

    if (idObj == NULL) {

        throw_NullPointerException(env, "id is null");

        return ;

    }

 

    const char *id = env->GetStringUTFChars(idObj, NULL);

 

    acquire_wake_lock(lock, id);

 

    env->ReleaseStringUTFChars(idObj, id);

}// 对wakelock加锁函数

static void releaseWakeLock(JNIEnv *env, jobject clazz, jstring idObj)

{

    if (idObj == NULL) {

        throw_NullPointerException(env, "id is null");

        return ;

    }

 

    const char *id = env->GetStringUTFChars(idObj, NULL);

 

    release_wake_lock(id);

 

    env->ReleaseStringUTFChars(idObj, id);

 

}// 对wakelock解锁函数

static int setScreenState(JNIEnv *env, jobject clazz, jboolean on)

{

    return set_screen_state(on);

}// 休眠唤醒的函数

 

Jni的方法需要注册到上层才可以使用,同时也需要在上层的对应java类中声明了native才可以使用。那么这里的方法在java中对应的声明在哪里呢?frameworks/base/core/java/android/os/Power.java,该文件定义一个java类,如下:

public class Power

{

    // can't instantiate this class

    private Power()

    {

    }

      

    /**

     * Wake lock that ensures that the CPU is running.  The screen might

     * not be on.

     */

    public static final int PARTIAL_WAKE_LOCK = 1;

      

    /**

     * Wake lock that ensures that the screen is on.

     */

    public static final int FULL_WAKE_LOCK = 2;

      

    public static native void acquireWakeLock(int lock, String id);

    public static native void releaseWakeLock(String id);

       …

     /**

     * Turn the screen on or off

     *

     * @param on Whether you want the screen on or off

     */

    public static native int setScreenState(boolean on);

      

    …

}

             

       声明的jni接口应该是被java server在使用,这里就是专门的电源管理服务:PowerManagerService使用,具体源码位置在:frameworks/base/services/java/com/android/server/PowerManagerService.java。android在最上层还提供了现场的android.os.PowerManager类

(frameworks/base/core/java/android/os/PowerManager.java)来供app使用,PowerManager类会调用java服务PowerManagerService的方法来完成与wakelock相关的工作。

      

       @ frameworks/base/core/java/android/os/PowerManager.java

       类PowerManager中内嵌了一个WakeLock类,另外还定义了wakelock的类型,下面是代码片段:

       public class PowerManager

{

           private static final String TAG = "PowerManager";

       …

        /**

     * Wake lock that ensures that the CPU is running.  The screen might

     * not be on.

     */

    public static final int PARTIAL_WAKE_LOCK = WAKE_BIT_CPU_STRONG;

 

    /**

     * Wake lock that ensures that the screen and keyboard are on at

     * full brightness.

     */

    public static final int FULL_WAKE_LOCK = WAKE_BIT_CPU_WEAK | WAKE_BIT_SCREEN_BRIGHT | WAKE_BIT_KEYBOARD_BRIGHT;

      

    /**

     * Wake lock that ensures that the screen is on at full brightness;

     * the keyboard backlight will be allowed to go off.

     */

    public static final int SCREEN_BRIGHT_WAKE_LOCK = WAKE_BIT_CPU_WEAK | WAKE_BIT_SCREEN_BRIGHT;

 

    /**

     * Wake lock that ensures that the screen is on (but may be dimmed);

     * the keyboard backlight will be allowed to go off.

     */

    public static final int SCREEN_DIM_WAKE_LOCK = WAKE_BIT_CPU_WEAK | WAKE_BIT_SCREEN_DIM;

 

    /**

     * Wake lock that turns the screen off when the proximity sensor activates.

     * Since not all devices have proximity sensors, use

     * {@link #getSupportedWakeLockFlags() getSupportedWakeLockFlags()} to determine if

     * this wake lock mode is supported.

     *

     * {@hide}

     */

public static final int PROXIMITY_SCREEN_OFF_WAKE_LOCK

= WAKE_BIT_PROXIMITY_SCREEN_OFF;

       …

       public class WakeLock

{

       …

       WakeLock(int flags, String tag)

        {

            switch (flags & LOCK_MASK) {

            case PARTIAL_WAKE_LOCK:

            case SCREEN_DIM_WAKE_LOCK:

            case SCREEN_BRIGHT_WAKE_LOCK:

            case FULL_WAKE_LOCK:

            case PROXIMITY_SCREEN_OFF_WAKE_LOCK:

                break;

            default:

                throw new IllegalArgumentException();

            }

 

            mFlags = flags;

            mTag = tag;

            mToken = new Binder();

        }

       public void acquire()

        {

            synchronized (mToken) {

                if (!mRefCounted || mCount++ == 0) {

                    try {

                        mService.acquireWakeLock(mFlags, mToken, mTag);

                    } catch (RemoteException e) {

                    }

                    mHeld = true;

                }

            }

        }

              public void release(int flags)

        {

            synchronized (mToken) {

                if (!mRefCounted || --mCount == 0) {

                    try {

                        mService.releaseWakeLock(mToken, flags);

                    } catch (RemoteException e) {

                    }

                    mHeld = false;

                }

                if (mCount < 0) {

                    throw new RuntimeException("WakeLock under-locked " + mTag);

                }

            }

        }

}

public WakeLock newWakeLock(int flags, String tag)

    {

        if (tag == null) {

            throw new NullPointerException("tag is

null in PowerManager.newWakeLock");

        }

        return new WakeLock(flags, tag);

    }

       public void goToSleep(long time)

    {

        try {

            mService.goToSleep(time);

        } catch (RemoteException e) {

        }

}

public PowerManager(IPowerManager service, Handler handler)

    {

        mService = service;

        mHandler = handler;

    }

 

    IPowerManager mService;

    Handler mHandler;

}

应用实例:

PowerManager pm = (PowerManager)getSystemService(Context.POWER_SERVICE);

PowerManager.WakeLock wl =

pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, “Tag”);

wl.acquire();  //申请锁这个里面会调用PowerManagerService里面acquireWakeLock()

wl.release(); //释放锁,显示的释放,如果申请的锁不在此释放系统就不会进入休眠。

 

接下来就会调用到java服务PowerManagerService中:

public void acquireWakeLock(int flags, IBinder lock, String tag) {

        int uid = Binder.getCallingUid();

        if (uid != Process.myUid()) {

          mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);

        }

        long ident = Binder.clearCallingIdentity();

        try {

            synchronized (mLocks) {

                acquireWakeLockLocked(flags, lock, uid, tag);       // 内部方法

            }

        } finally {

            Binder.restoreCallingIdentity(ident);

        }

}

 

acquireWakeLockLocked(flags, lock, uid, tag)会调用函数power类的方法:

Power.acquireWakeLock(Power.PARTIAL_WAKE_LOCK,PARTIAL_NAME)。

 

public void releaseWakeLock(IBinder lock, int flags) {

        int uid = Binder.getCallingUid();

        if (uid != Process.myUid()) {

            mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);

        }

 

        synchronized (mLocks) {

            releaseWakeLockLocked(lock, flags, false);

        }

}

releaseWakeLockLocked(lock, flags, false)函数会调用power类的方法:

       Power.releaseWakeLock(PARTIAL_NAME);

 

上层休眠唤醒都是调用PowerManagerService类的方法:

goToSleep()

       à goToSleepWithReason()

              à goToSleepLocked()

                     à setPowerState()

                            à setScreenStateLocked()

                                   à Power.setScreenState()

                                          à jni方法

Android层的代码分析得不是很详细,这里只关注框架和流程。下图是网上的一个框架,可以参考一下:


这篇关于Android在标准linux基础上对休眠唤醒的实现(三)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/926449

相关文章

C++中unordered_set哈希集合的实现

《C++中unordered_set哈希集合的实现》std::unordered_set是C++标准库中的无序关联容器,基于哈希表实现,具有元素唯一性和无序性特点,本文就来详细的介绍一下unorder... 目录一、概述二、头文件与命名空间三、常用方法与示例1. 构造与析构2. 迭代器与遍历3. 容量相关4

Linux join命令的使用及说明

《Linuxjoin命令的使用及说明》`join`命令用于在Linux中按字段将两个文件进行连接,类似于SQL的JOIN,它需要两个文件按用于匹配的字段排序,并且第一个文件的换行符必须是LF,`jo... 目录一. 基本语法二. 数据准备三. 指定文件的连接key四.-a输出指定文件的所有行五.-o指定输出

Linux jq命令的使用解读

《Linuxjq命令的使用解读》jq是一个强大的命令行工具,用于处理JSON数据,它可以用来查看、过滤、修改、格式化JSON数据,通过使用各种选项和过滤器,可以实现复杂的JSON处理任务... 目录一. 简介二. 选项2.1.2.2-c2.3-r2.4-R三. 字段提取3.1 普通字段3.2 数组字段四.

C++中悬垂引用(Dangling Reference) 的实现

《C++中悬垂引用(DanglingReference)的实现》C++中的悬垂引用指引用绑定的对象被销毁后引用仍存在的情况,会导致访问无效内存,下面就来详细的介绍一下产生的原因以及如何避免,感兴趣... 目录悬垂引用的产生原因1. 引用绑定到局部变量,变量超出作用域后销毁2. 引用绑定到动态分配的对象,对象

Linux kill正在执行的后台任务 kill进程组使用详解

《Linuxkill正在执行的后台任务kill进程组使用详解》文章介绍了两个脚本的功能和区别,以及执行这些脚本时遇到的进程管理问题,通过查看进程树、使用`kill`命令和`lsof`命令,分析了子... 目录零. 用到的命令一. 待执行的脚本二. 执行含子进程的脚本,并kill2.1 进程查看2.2 遇到的

SpringBoot基于注解实现数据库字段回填的完整方案

《SpringBoot基于注解实现数据库字段回填的完整方案》这篇文章主要为大家详细介绍了SpringBoot如何基于注解实现数据库字段回填的相关方法,文中的示例代码讲解详细,感兴趣的小伙伴可以了解... 目录数据库表pom.XMLRelationFieldRelationFieldMapping基础的一些代

Java HashMap的底层实现原理深度解析

《JavaHashMap的底层实现原理深度解析》HashMap基于数组+链表+红黑树结构,通过哈希算法和扩容机制优化性能,负载因子与树化阈值平衡效率,是Java开发必备的高效数据结构,本文给大家介绍... 目录一、概述:HashMap的宏观结构二、核心数据结构解析1. 数组(桶数组)2. 链表节点(Node

Java AOP面向切面编程的概念和实现方式

《JavaAOP面向切面编程的概念和实现方式》AOP是面向切面编程,通过动态代理将横切关注点(如日志、事务)与核心业务逻辑分离,提升代码复用性和可维护性,本文给大家介绍JavaAOP面向切面编程的概... 目录一、AOP 是什么?二、AOP 的核心概念与实现方式核心概念实现方式三、Spring AOP 的关

从基础到高级详解Go语言中错误处理的实践指南

《从基础到高级详解Go语言中错误处理的实践指南》Go语言采用了一种独特而明确的错误处理哲学,与其他主流编程语言形成鲜明对比,本文将为大家详细介绍Go语言中错误处理详细方法,希望对大家有所帮助... 目录1 Go 错误处理哲学与核心机制1.1 错误接口设计1.2 错误与异常的区别2 错误创建与检查2.1 基础

Python实现字典转字符串的五种方法

《Python实现字典转字符串的五种方法》本文介绍了在Python中如何将字典数据结构转换为字符串格式的多种方法,首先可以通过内置的str()函数进行简单转换;其次利用ison.dumps()函数能够... 目录1、使用json模块的dumps方法:2、使用str方法:3、使用循环和字符串拼接:4、使用字符