Android系统功耗优化之Alarm - 从AlarmManager到Linux kernel

Android 进阶——性能优化之电量优化全攻略及实战小结(一) 性能优化之电量优化之低电耗模式和应用待机模式概述 阅读详情

1 Overview

对于系统功耗优化,时常可以看到alarm唤醒频繁,或者alarm timer持锁时间过长的问题,对于这样的情况Android的各个版本也都有持续性的优化,对于alarm来说,简而言之都是加强管控,尽可能减少唤醒,集中批量处理。

2 AlarmManager

AlarmManager提供接口供应用根据自己的需求,来设置alarm以及对应的处理方法

frameworks/base/core/java/android/app/AlarmManager.java

alarm目前有几种类型
  • RTC_WAKEUP
    /**
     * Alarm time in {@link System#currentTimeMillis System.currentTimeMillis()}
     * (wall clock time in UTC), which will wake up the device when
     * it goes off.
     */
    public static final int RTC_WAKEUP = 0;
  • RTC
    /**
     * Alarm time in {@link System#currentTimeMillis System.currentTimeMillis()}
     * (wall clock time in UTC).  This alarm does not wake the
     * device up; if it goes off while the device is asleep, it will not be
     * delivered until the next time the device wakes up.
     */
    public static final int RTC = 1;
  • ELAPSED_REALTIME_WAKEUP
    /**
     * Alarm time in {@link android.os.SystemClock#elapsedRealtime
     * SystemClock.elapsedRealtime()} (time since boot, including sleep),
     * which will wake up the device when it goes off.
     */
    public static final int ELAPSED_REALTIME_WAKEUP = 2;
  • ELAPSED_REALTIME
    /**
     * Alarm time in {@link android.os.SystemClock#elapsedRealtime
     * SystemClock.elapsedRealtime()} (time since boot, including sleep).
     * This alarm does not wake the device up; if it goes off while the device
     * is asleep, it will not be delivered until the next time the device
     * wakes up.
     */
    public static final int ELAPSED_REALTIME = 3;
  • RTC_POWEROFF_WAKEUP
    /**
     * Alarm time in {@link System#currentTimeMillis System.currentTimeMillis()}
     * (wall clock time in UTC), which will wake up the device when
     * it goes off. And it will power on the devices when it shuts down.
     * Set as 5 to make it be compatible with android_alarm_type.
     * @hide
     */
    public static final int RTC_POWEROFF_WAKEUP = 5;
其特点用途如下
  • RTC和ELAPSED_REALTIME 的差异在于前者使用绝对时间,后者使用相对时间来设置

  • WAKEUP类型的alarm在超时时如果系统处于待机休眠状态,则会唤醒系统,非WAKEUP类型的只能等到下一次系统唤醒的时候再被处理

  • RTC_POWEROFF_WAKEUP 基本就是用来给关机闹钟,或者定时开机用

提供的设置接口有
  • set(int type, long triggerAtMillis, PendingIntent operation)
    设置一次性的
  • setRepeating(int type, long triggerAtMillis, long intervalMillis, PendingIntent operation)
    设置可重复执行的
  • setInexactRepeating(int type, long triggerAtMillis, long intervalMillis, PendingIntent operation)
    设置可重复执行的,并且没有精确的时间要求

第三个参数就是Alarm对应的超时处理方法,

除了PendingIntent还有OnAlarmListener类型

public void set(@AlarmType int type, long triggerAtMillis, String tag, OnAlarmListener listener,

        Handler targetHandler)

以上的API在小于19的情况下,可以正常工作,因为从Android 4.4开始,set 或者 setRepeating创建的alarm将会变得不准确,原因是做了唤醒对齐, 时间不敏感的放一起触发。

这时候可以用setWindow(), 这个api设置的是一个时间范围,可以确保alarm在这个时间范围内触发
如果需要非常精确的时间,可以使用setExact()

在Android 6.0 API 23 开始,DOZE 又会导致上述方法设置的alarm无法生效

标准 AlarmManager 闹铃(包括 setExact() 和 setWindow())推迟到下一维护时段。
    如果您需要设置在低电耗模式下触发的闹铃,请使用 setAndAllowWhileIdle() 或 setExactAndAllowWhileIdle()。
    一般情况下,使用 setAlarmClock() 设置的闹铃将继续触发 — 但系统会在这些闹铃触发之前不久退出低电耗模式。

这时候可以使用setAndAllowWhileIdle(int type, long triggerAtMillis, PendingIntent operation)

取消设置的接口

对应到设置的方法,cancel两种类型的超时处理方法

    /**
     * Remove any alarms with a matching {@link Intent}.
     * Any alarm, of any type, whose Intent matches this one (as defined by
     * {@link Intent#filterEquals}), will be canceled.
     *
     * @param operation IntentSender which matches a previously added
     * IntentSender. This parameter must not be {@code null}.
     *
     * @see #set
     */
    public void cancel(PendingIntent operation) {
        if (operation == null) {
            final String msg = "cancel() called with a null PendingIntent";
            if (mTargetSdkVersion >= Build.VERSION_CODES.N) {
                throw new NullPointerException(msg);
            } else {
                Log.e(TAG, msg);
                return;
            }
        }

        try {
            mService.remove(operation, null);
        } catch (RemoteException ex) {
            throw ex.rethrowFromSystemServer();
        }
    }

    /**
     * Remove any alarm scheduled to be delivered to the given {@link OnAlarmListener}.
     *
     * @param listener OnAlarmListener instance that is the target of a currently-set alarm.
     */
    public void cancel(OnAlarmListener listener) {
        if (listener == null) {
            throw new NullPointerException("cancel() called with a null OnAlarmListener");
        }

        ListenerWrapper wrapper = null;
        synchronized (AlarmManager.class) {
            if (sWrappers != null) {
                wrapper = sWrappers.get(listener);
            }
        }

        if (wrapper == null) {
            Log.w(TAG, "Unrecognized alarm listener " + listener);
            return;
        }

        wrapper.cancel();
    }

3 AlarmManagerService

AlarmManagerService提供接口给AlarmManager,实现上述接口,另外也实现了系统对于Alarm的处理逻辑,包括一些优化

从Android 4.4开始 Alarm默认是非精确的,也可以指定采用精确模式。在非精确模式下,Alarm是批量提醒的,每个Alarm会被根据其触发时间以及最大触发时间,加入到不同的batch中去,同一个batch中的alarm会同时触发,这也是low power的优化。对于

frameworks/base/services/core/java/com/android/server/AlarmManagerService.java

SET

setImpl 是最常用的方法
比如setAndAllowWhileIdle的实现

    public void setAndAllowWhileIdle(@AlarmType int type, long triggerAtMillis,
            PendingIntent operation) {
        setImpl(type, triggerAtMillis, WINDOW_HEURISTIC, 0, FLAG_ALLOW_WHILE_IDLE,
                operation, null, null, null, null, null);
    }

setImpl() 会把RTC类型的转换成ELAPSED_REALTIME类型,也就是说最终到底层的只有 ELAPSED_REALTIME_WAKEUP和ELAPSED_REALTIME, 也就是id 2和3

final long nominalTrigger = convertToElapsed(triggerAtTime, type);

其调用流程如下

setImpl()
    setImplLocked()
        setImplLocked()
            rescheduleKernelAlarmsLocked()
                setlocked()
                    set()
Service处理逻辑

在添加alarm的时候,比如先添加了一个15s的wakeup alarm(假设其就是下一个wakeup类型的alarm),再添加一个10s的wakeup alarm

在调用进行到 setImplLocked的时候, 15s的alarm所在的batch已在mAlarmBatches 数组中,这个时候来了10s的,那么10s的batch就会位于mAlarmBatches中15s的前面,之后调用rescheduleKernelAlarmsLocked(), 进而把位于第一个的10s设置下去

如果是先设15s的后面来了一个20s的,实际上20s的在这一次是不会被设置下去的,需要等到其前面的超时之后,alarm thread遍历20s的这个已经排在最前,才会被设置下去


private void setImplLocked(int type, long when, long whenElapsed, long maxWhen, long interval,  
        PendingIntent operation, boolean isStandalone, boolean doValidate,  
        WorkSource workSource) {  
    /**创建一个alarm,其中各参数的含义如下: 
     * type 闹钟类型 ELAPSED_REALTIME、RTC、RTC_WAKEUP等 
     * when 触发时间 UTC类型,绝对时间,通过System.currentTimeMillis()得到 
     * whenElapsed 相对触发时间,自开机算起,含休眠,通过SystemClock.elapsedRealtime()得到 
     * maxWhen 最大触发时间 
     * interval 触发间隔,针对循环闹钟有效 
     * operation 闹钟触发时的行为,PendingIntent类型 
     */  
    Alarm a = new Alarm(type, when, whenElapsed, maxWhen, interval, operation, workSource);  
    //根据PendingIntent删除之前已有的同一个闹钟  
    removeLocked(operation);  
  
    boolean reschedule;  
    //尝试将alarm加入到合适的batch中,如果alarm是独立的或者无法找到合适的batch去容纳此alarm,返回-1  
    int whichBatch = (isStandalone) ? -1 : attemptCoalesceLocked(whenElapsed, maxWhen);  
    if (whichBatch < 0) {  
        //没有合适的batch去容纳alarm,则新建一个batch  
        Batch batch = new Batch(a);  
        batch.standalone = isStandalone;  
        //将batch加入mAlarmBatches中,并对mAlarmBatches进行排序:按开始时间升序排列  
        reschedule = addBatchLocked(mAlarmBatches, batch);  
    } else {  
        //如果找到合适了batch去容纳此alarm,则将其加入到batch中  
        Batch batch = mAlarmBatches.get(whichBatch);  
        //如果当前alarm的加入引起了batch开始时间和结束时间的改变,则reschedule为true  
        reschedule = batch.add(a);  
        if (reschedule) {  
            //由于batch的起始时间发生了改变,所以需要从列表中删除此batch并重新加入、重新对batch列表进行排序  
            mAlarmBatches.remove(whichBatch);  
            addBatchLocked(mAlarmBatches, batch);  
        }  
    }  
  
    if (DEBUG_VALIDATE) {  
        if (doValidate && !validateConsistencyLocked()) {  
            Slog.v(TAG, "Tipping-point operation: type=" + type + " when=" + when  
                    + " when(hex)=" + Long.toHexString(when)  
                    + " whenElapsed=" + whenElapsed + " maxWhen=" + maxWhen  
                    + " interval=" + interval + " op=" + operation  
                    + " standalone=" + isStandalone);  
            rebatchAllAlarmsLocked(false);  
            reschedule = true;  
        }  
    }  
  
    if (reschedule) {  
        rescheduleKernelAlarmsLocked();  
    }  
}  
    void rescheduleKernelAlarmsLocked() {
        // Schedule the next upcoming wakeup alarm.  If there is a deliverable batch
        // prior to that which contains no wakeups, we schedule that as well.
        long nextNonWakeup = 0;
        if (mAlarmBatches.size() > 0) {
            final Batch firstWakeup = findFirstWakeupBatchLocked();
            final Batch firstBatch = mAlarmBatches.get(0);
            final Batch firstRtcWakeup = findFirstRtcWakeupBatchLocked();
            if (firstWakeup != null && mNextWakeup != firstWakeup.start) {
                mNextWakeup = firstWakeup.start;
                mLastWakeupSet = SystemClock.elapsedRealtime();
                setLocked(ELAPSED_REALTIME_WAKEUP, firstWakeup.start);
            }
CANCEL

cancel方法都会调用到AlarmManagerService中的 remove

boolean remove(final PendingIntent operation, final IAlarmListener listener)

相比与set,cancel并没有直接调用到底层的所谓cancel的api,kernel也没有提供cancel的接口

假设设置了一个10s的wakeup alarm, 在超时之前cancel,实际上是从超时的执行列表中移除10s alarm对应的处理方法,那这个alarm是怎么处理的呢?

  • 首先会从batch中移除这个alarm

  • alarm thread 会调用到rescheduleKernelAlarmsLocked()把移除的这个alarm的下一个作为next,重新写到底层

4 JNI 层

frameworks/base/services/core/jni/com_android_server_AlarmManagerService.cpp

在JNI层,可以看到id 2和3对应的分别是 CLOCK_BOOTTIME_ALARM 和 CLOCK_BOOTTIME

static const clockid_t android_alarm_to_clockid[N_ANDROID_TIMERFDS] = {
    CLOCK_REALTIME_ALARM,
    CLOCK_REALTIME,
    CLOCK_BOOTTIME_ALARM,
    CLOCK_BOOTTIME,
    CLOCK_MONOTONIC,
    CLOCK_REALTIME,
};

调用timerfd的接口设置下去

int AlarmImpl::set(int type, struct timespec *ts)
{
    if (static_cast<size_t>(type) > ANDROID_ALARM_TYPE_COUNT) {
        errno = EINVAL;
        return -1;
    }

    if (!ts->tv_nsec && !ts->tv_sec) {
        ts->tv_nsec = 1;
    }
    /* timerfd interprets 0 = disarm, so replace with a practically
       equivalent deadline of 1 ns */

    struct itimerspec spec;
    memset(&spec, 0, sizeof(spec));
    memcpy(&spec.it_value, ts, sizeof(spec.it_value));

    return timerfd_settime(fds[type], TFD_TIMER_ABSTIME, &spec, NULL);
}

5 Linux Kernel 层

很核心的概念就是对于alarm timer 或者是hrtimer,用户空间只能设置设置一个下来,新的会把旧的覆盖掉, 比如你通过AlarmManager设置了一个15s以后的wakeup 类型的alrm事件,再设置一个10s以后的,那么timerfd会把先前设置的15s的cancel掉,再设置10s的

timerfd

~/fs/timerfd.c

timerfd_settime 这个系统调用内核的调用路径如下, 根据类型的不同,分为alarm和hrtimer

do_timerfd_settime()
    timerfd_setup()
        alarm_init()        ~/kernel/time/alarmtimer.c
        alarm_start()
        hrtimer_init()        ~/kernel/time/hrtimer.c
        hrtimer_start()
static int do_timerfd_settime(int ufd, int flags, 
		const struct itimerspec *new,
		struct itimerspec *old)
{
	struct fd f;
	struct timerfd_ctx *ctx;
	int ret;

	if ((flags & ~TFD_SETTIME_FLAGS) ||
	    !timespec_valid(&new->it_value) ||
	    !timespec_valid(&new->it_interval))
		return -EINVAL;

	ret = timerfd_fget(ufd, &f);
	if (ret)
		return ret;
	ctx = f.file->private_data;

	if (!capable(CAP_WAKE_ALARM) && isalarm(ctx)) {
		fdput(f);
		return -EPERM;
	}

	timerfd_setup_cancel(ctx, flags);

	/*
	 * We need to stop the existing timer before reprogramming
	 * it to the new values.
	 */
	for (;;) {
		spin_lock_irq(&ctx->wqh.lock);

		if (isalarm(ctx)) {
			if (alarm_try_to_cancel(&ctx->t.alarm) >= 0)
				break;
		} else {
			if (hrtimer_try_to_cancel(&ctx->t.tmr) >= 0)
				break;
		}
		spin_unlock_irq(&ctx->wqh.lock);
		cpu_relax();
	}

	/*
	 * If the timer is expired and it's periodic, we need to advance it
	 * because the caller may want to know the previous expiration time.
	 * We do not update "ticks" and "expired" since the timer will be
	 * re-programmed again in the following timerfd_setup() call.
	 */
	if (ctx->expired && ctx->tintv.tv64) {
		if (isalarm(ctx))
			alarm_forward_now(&ctx->t.alarm, ctx->tintv); //如果是Alarm timer类型,先cancel前一个alarm类型的
		else
			hrtimer_forward_now(&ctx->t.tmr, ctx->tintv);
	}

	old->it_value = ktime_to_timespec(timerfd_get_remaining(ctx));
	old->it_interval = ktime_to_timespec(ctx->tintv);

	/*
	 * Re-program the timer to the new value ...
	 */
	ret = timerfd_setup(ctx, flags, new); //开始设置新的timer

	spin_unlock_irq(&ctx->wqh.lock);
	fdput(f);
	return ret;
}
alarm timer

AlarmTimer 参考https://www.cnblogs.com/arnoldlu/p/7145879.html 这一篇就好

值得注意的是 alarmtimer_suspend方法,在进入睡眠之前,遍历alarm_bases->timerqueue,取最近一次timer的expires;将此expires写入RTC定时器,RTC超时后会唤醒系统。



static int alarmtimer_suspend(struct device *dev)
{
...
    rtc = alarmtimer_get_rtcdev();-------------------------------------获取RTC设备
    /* If we have no rtcdev, just return */
    if (!rtc)
        return 0;

    /* Find the soonest timer to expire*/
    for (i = 0; i < ALARM_NUMTYPE; i++) {------------------------------遍历ALARM_REALTIME和ALARM_BOOTTIME两个alarm_base,取各自最近expires
        struct alarm_base *base = &alarm_bases[i];
        struct timerqueue_node *next;
        ktime_t delta;

        spin_lock_irqsave(&base->lock, flags);
        next = timerqueue_getnext(&base->timerqueue);
        spin_unlock_irqrestore(&base->lock, flags);
        if (!next)
            continue;
        delta = ktime_sub(next->expires, base->gettime());
        if (!min.tv64 || (delta.tv64 < min.tv64))---------------------比较两次expires,取最小者
            min = delta;
    }
    if (min.tv64 == 0)
        return 0;

    if (ktime_to_ns(min) < 2 * NSEC_PER_SEC) {-----------------------如果expires小于2秒,保持系统唤醒2秒,并中断suspend流程。
        __pm_wakeup_event(ws, 2 * MSEC_PER_SEC);
        return -EBUSY;
    }

    /* Setup an rtc timer to fire that far in the future */
    rtc_timer_cancel(rtc, &rtctimer);-------------------------------取消当前rtctimer
    rtc_read_time(rtc, &tm);
    now = rtc_tm_to_ktime(tm);
    now = ktime_add(now, min);--------------------------------------获取RTC时间,将rtc_timer转换成ktimer_t,将RTC时间加上AlarmTimer超时。

    /* Set alarm, if in the past reject suspend briefly to handle */
    ret = rtc_timer_start(rtc, &rtctimer, now, ktime_set(0, 0));---设置rtctimer
    if (ret < 0)
        __pm_wakeup_event(ws, 1 * MSEC_PER_SEC);
    return ret;
}




参考文章

https://www.cnblogs.com/leipDao/p/8203684.html
https://www.cnblogs.com/arnoldlu/p/7145879.html
https://blog.youkuaiyun.com/wh_19910525/article/details/44303039

AlarmManager 定时任务详解 android 是怎么通过AlarmManager调度定时任务;AlarmManager 与 Timer ,Hander的区别;以及在不同android版本,怎么解决AlarmManager 不准问题 阅读详情

相关推荐

Android Alarm框架层分析

Alarm框架层分析

xierong1的博客 303

Wi-Fi Scan

Wi-Fi Scan

kv110的专栏 5717

【实战学习(五)】开源项目学习之uWSGI的部署以及配合nginx

文章目录1)uWSGI是什么?1.1 WSGI1.1.1 Application端1.1.2 Server端1.1.3 WSGI中间件1.2 uwgi1.3 uWSGI、WSGI、uwsgi之间的关系*为什么有了uWSGI为什么还需要nginx?2)连接uwsgi和Django*避坑之Windows10安装uWSGI非常极其艰难,最好勿浪费时间,直接转战Linux吧:2.1 uWGI部署2.1.1 在虚拟环境下安装uwsgi:2.1.2 测试uWSGI的运行2.1.3 使用uWSGI运行Django项目2.

黑黑白白君的博客 1506

使用AlarmManager实现定时提醒,解决锁屏后无法正常唤醒CPU和屏幕的问题

之前写过一个demo来实现定时操作,最近帮别人写项目的时候又用到了这个需求,于是coding起来。 首先来说一下我的实现思路:用户选择好闹钟提醒时间后我要启动一个Service,在这个Service里面设置闹钟,通过闹钟直接打开一个Activity来显示提醒信息。我想要创建一个不在通知栏中显示notification的前台Service,这样就可以让Service一直运行了,除非你在手机的“最近任...

泥巴城 的博客 8596

【WILEY】从Revision到Online:逐层拆解投稿状态更新与关键文件提交实战

本文详细解析了学术论文从返修到在线发表的全过程,重点拆解了投稿系统状态更新背后的含义与应对策略。文章提供了返修稿与回复信的准备技巧、关键补充文件(如图文摘要)的提交要点,并分享了校对校样与处理出版协议的实战经验,帮助作者高效、专业地完成发表流程。

weixin_29209805的博客 712

保姆级避坑指南:在openEuler 22.03 LTS上用kubeadm 1.32.2部署K8s集群(含阿里云镜像加速)

本文提供在openEuler 22.03 LTS上使用kubeadm 1.32.2部署Kubernetes集群的详细指南,涵盖系统准备、容器运行时适配、kubeadm配置及集群初始化等关键步骤。特别针对openEuler系统的特殊性,解决软件源配置、cri-dockerd编译安装、阿里云镜像加速等常见问题,帮助用户高效完成K8s集群部署。

weixin_28312391的博客 273

你是否了解APP耗电问题?深入探索 Android 电量优化,flutter插件推荐

3)、最后,把电量输送给电池,而整个降压的过程中会产生热能。 分类 1)、高压低电流快充方案:在充电过程中提升充电电压(7-20V)来提升充电功率。 2)、低压大电流快充方案:在电压一定情况下,增加电流,通常使用并联电路的方式进行分流。 3)、铝-石墨烯超级电池 超高耐用性和安全性,快充充电1.1秒就能充满电。 实验阶段。 3、寿命 通常使用充电循环次数衡量。 4、安全性 严格控制电池容量,例如 VOOC 就使用了各种安全检测技术。 5、电量和硬件 手机耗电是通过使用相.

m0_65146275的博客 2596

手把手教你学simulink(83.2)--分布式能源场景实例:使用Simulink构建一个典型的光伏发电分布式能源系统模型

*分布式能源系统(Distributed Energy System, DES)**是指由多个小型发电单元、储能装置和负载组成的电力系统,这些组件通常分布在不同的地理位置。DES包括太阳能光伏(PV)、风力发电、微型燃气轮机、储能电池等。这种系统能够提高能源利用效率、减少传输损耗,并增强电网的稳定性和可靠性。在DES中,各组件之间的协调与控制至关重要。通过使用Simulink,我们可以模拟和优化这些系统的运行情况,研究其动态行为,并设计有效的控制策略。

MHD0815的博客 1104

程序性能优化之耗电优化(四)下篇

阿里P7移动互联网架构师进阶视频(每日更新中)免费学习请点击:https://space.bilibili.com/474380680 本篇文章将最后从以下两个方面来介绍耗电优化: 【JobScheduler】 【WorkManager】 一、JobScheduler API的使用详细 1.1 简介 JobScheduler API是在Android5.0开始有的,使用场景:在...

AndroidAlvin的博客 632

Android 13.0 开机启动优化之PMS扫描apk耗时相关功能优化

在android13.0的系统rom定制化开发中,在系统中开发产品时,会根据客户要求内置第三方app,这时如果内置app过多,或者安装的app过多,在系统开机的过程中 在pms扫描安装app的时候,就会比较耗时,这时候就需要优化下pms扫描安装app这块的功能代码,用多线程来实现pms扫描安装app,来加快开机时间,接下来 来实现这个功能

安卓兼职framework和app工程师的博客 1333

Flow Matching05:概率路径与插值【概率路径:线性插值路径(最简单)、高斯插值路径】【先尝试线性插值,看效果如何;若不够好,尝试高斯插值】

好的,我将从数学角度详细解释Flow Matching,从高中生能理解的基础知识开始,逐步深入到高级概念。

u013250861的博客 173

Android手机功耗,高通/MTK功耗

功耗优化- https://blog.youkuaiyun.com/zhangbijun1230/article/category/7541658 android 功耗优化- https://blog.youkuaiyun.com/zhangbijun1230/article/category/7618452 MTK 驱动- https://blog.youkuaiyun.com/zhangbijun1230/article/cat...

ShareUs的专栏 5977

2025年最新雷电模拟器9.22安装Magisk面具和LSPosed框架完整图文教程 文章末尾附所需软件下载

操作环境:雷电模拟器9.0.22 虚拟系统版本android 91、设置-其他设置-Root权限-开启2、设置-性能设置-System.vmdk可写入3、安装Magisk-18a0b94a-delta(25205).apk,运行并给予root权限4、选择右上角安装弹出“允许“magisk Delta”访问您设备上的照片、媒体内容和文件吗?“选择允许,然后结束magisk进程。5、从新运行magisk选择右上角安装-选择修补boot镜像中的vbmeta和安装到Recovery。

代码简单说 Vue、JAVA、PHP、Node.js 熟练运用,接口、架构、性能全搞定。 7091

ChatGPT解答:安卓APP耗电量测试方案和源码,用Android代码实现

ChatGPT解答:安卓APP耗电量测试方案和源码,用Android代码实现。

HRD的博客 5536

基于XGBoost的混凝土力学性能预测系统

本文介绍了一个基于XGBoost算法的混凝土力学性能预测系统。该系统通过模拟生成3000组混凝土配合比数据(包含水灰比、水泥用量和龄期三个关键特征),利用XGBoost强大的非线性建模能力预测混凝土抗压强度。研究背景源于传统混凝土性能测试方法耗时耗力的痛点,该系统可显著减少实验次数,优化配合比设计。系统实现包括:数据生成与特征工程(模拟真实工程数据并添加噪声和异常值)、XGBoost模型构建、以及预测性能评估。XGBoost算法因其处理非线性关系能力强、鲁棒性好等优势被选用,可为智能建造和数字化施工提供技术

huanghm88的专栏 128

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

Android定时器Alarm

要想使用Android中的定时任务,首先必须先获取AlarmManager的对象,然后调用AlarmManager的set(int type,long triggerAtMillis,PendingIntent operation)或者setExact(int type,long triggerAtMillis,PendingIntent operation)设置定时任务,第二种方法定时更准确些。

yangshuangyue的博客 569

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

Android之Alarm

Android之Alarm   1 简介         Alarm是在预定的时间上触发Intent的一种独立的方法。         Alarm超出了应用程序的作用域,所以它们可以用于触发应用程序事件或动作。在应用程序关闭之后,与Broadcast Receiver结合,它们可以变得尤其的强大,可以通过设置Alarm来启动应用程序或者执行动作,而应用程序不需要打开或者处

chenbeixin的专栏 980

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

Android知识点 120 —— AlarmManager

目录 1 概述 2 为什么要有AlarmManager 3 闹铃类型 4 AlarmManager的常用方法 4.1 设置时间 4.2 设置闹铃 4.2.1 set 4.2.2 setExact 4.3 取消闹铃 4.4 获得下一次闹铃事件 5 常用时间定义 6 1 概述 AlarmManager类提供对系统警报服务的访问。这些允许您安排应用程序在将来...

编程到管理、技术到产品 2142

一加8pro Android

--------- beginning of main 08-31 10:30:24.912 5619 5619 W AVMediaServiceUtils: symbol createExtendedMediaServiceUtils not found: undefined symbol: createExtendedMediaServiceUtils 08-31 10:30:24.913 5619 5619 D AndroidRuntime: >>>>>>

qq_41906870的博客 2019

android AlarmManager使用初探

引子:     可悲的5月29号,由于在android手机中安装的“正点闹钟”没有响,让我错过了欧冠联赛决赛。完美的巴萨用完美的进球赢了完美的比赛,可我只能在第二天,看看下载的比赛实况,聊以自慰。痛定思痛,我觉得做个简单的闹钟程序。但事情好像并不那么简单……   通过粗略查看SDK,初步决定使用service,在service中注册Intent.ACTION_TIME_TICK事件的Broad...

weixin_30600503的博客 160

BiometricPrompt.Builder.setDeviceCredentialAllowed(boolean)方法过时了,怎么破。

BiometricPrompt.Builder.setDeviceCredentialAllowed(boolean)方法过时了,怎么破。

u013398960的博客 2012

android 模块之桌面闹钟

在android中,定时alarm功能是很常用的,现在来分析下怎么实现的,这里将采用自下而上的方式讲解。  1. driver 首先了解下android下是如何driver一个RTC的。android RTC 的driver 位于kernel\drivers\rtc 目录下。 在该目录下,有一堆以rtc-为前缀的文件,这些文件都是各种板子上用的rtc底层驱动代码,我们要看的只有3

sir_zeng的专栏 1368

系统服务之定时服务(AlarmManager)

概述 AlarmManager提供了对系统定时服务的访问接口,使得开发者可以安排在未来的某个时间运行应用。当到达闹铃设定时间,系统就会广播闹铃之前注册的Intent。如果此时目标应用没有被启动,系统还会帮你自动启动目标应用。即使设备已经进入睡眠已注册的闹铃也会被保持,只有当设备关闭或是重启的时候会被清除。下面基于Android 8.0源码来一起学习一下。 闹铃类型 AlarmManage...

Peter的专栏 5168

App定时提醒(AlarmManager实现,适配不同版本)

本文主要介绍App定时提醒的实现方式及原理。篇幅较长,先提供demo地址。 项目Demo地址 AlarmSample App定时提醒方案探讨 方案一:利用 Handler 实现。Handler可以使用 sendEmptyMessageDelayed 来实现定时发送消息(提醒)的功能,但 sendEmptyMessageDelayed 方法是依赖于 Handler 所在的线程的,如果线程结束,就起...

狂健小夫的博客 4977

AlarmManagerService是如何工作的?

系统开发过程中,经常会遇到Android心跳机制,待机耗流问题,几乎都跟AlarmMangerService有关,本文从应用层到kernel记录下整个处理流程。 应用层 样例代码: AlarmManager mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE); ... mAlarmM...

weixin_42935803的博客 1363

多个循环的AlarmManager管理

本文涉及内容: 一,如何设置多个AlarmManager提醒 二,多个循环的AlarmManager逻辑管理 最近在捣鼓的一个小proj涉及到需要定时提醒的问题,每天的三个特定时间到点提醒。涉及到类似问题的,我觉得AlarmManager是最佳选择,简单粗暴。因为之前就用过AlarmManager,所以感觉轻车熟路,没想到一开始就碰壁了,首先是一打开程序,就会莫名其妙地提醒,其次,存

crxmai的专栏 1353
上一篇: Android系统功耗优化之CPU - CPU功耗和频率的关系
下一篇: Systrace分析游戏卡顿问题之王者荣耀CPU资源不足
DecJ
博客等级 码龄18年 537粉丝 25原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值