From 0cf2cc1607a0844e906042173815451cd9c2ff58 Mon Sep 17 00:00:00 2001 From: Thomas Martitz Date: Fri, 12 Nov 2010 21:04:13 +0000 Subject: Android: Change how detecting call state (introduced in r27746) works, from polling to event based. * For some reason, the polling methid is much more inefficient than I thought. According to htop it caused up to 15% CPU load on some phones (e.g. Galaxy S). The event based causes no CPU load. Rockbox' idle CPU load is now back to 0%, while it was previously dominated by polling the call state. * Also stop on outgoing calls (no need to explicitely pause for making a call anymore). * Factor out the detection mechanism to separate files. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@28564 a1c6a512-1295-4272-9138-f99709370657 --- android/AndroidManifest.xml | 3 +- android/src/org/rockbox/RockboxTelephony.java | 97 ++++++++++++++++++++++ android/src/org/rockbox/RockboxTimer.java | 35 +------- firmware/SOURCES | 1 + firmware/target/hosted/android/kernel-android.c | 18 +--- firmware/target/hosted/android/system-android.c | 22 +++-- firmware/target/hosted/android/telephony-android.c | 54 ++++++++++++ 7 files changed, 174 insertions(+), 56 deletions(-) create mode 100644 android/src/org/rockbox/RockboxTelephony.java create mode 100644 firmware/target/hosted/android/telephony-android.c diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml index e0fc106ca7..0eab90ff81 100644 --- a/android/AndroidManifest.xml +++ b/android/AndroidManifest.xml @@ -29,9 +29,10 @@ + - + diff --git a/android/src/org/rockbox/RockboxTelephony.java b/android/src/org/rockbox/RockboxTelephony.java new file mode 100644 index 0000000000..faaf0c36b7 --- /dev/null +++ b/android/src/org/rockbox/RockboxTelephony.java @@ -0,0 +1,97 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2010 Thomas Martitz + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +package org.rockbox; + +import android.content.Context; +import android.os.Handler; +import android.telephony.PhoneStateListener; +import android.telephony.TelephonyManager; + +public class RockboxTelephony +{ + public RockboxTelephony(Context c) + { + final Handler handler = new Handler(c.getMainLooper()); + final TelephonyManager tm = (TelephonyManager) + c.getSystemService(Context.TELEPHONY_SERVICE); + handler.post(new Runnable() + { + @Override + public void run() + { /* need to instantiate from a thread that has a Looper */ + tm.listen(new RockboxCallStateListener(), PhoneStateListener.LISTEN_CALL_STATE); + } + }); + } + + private class RockboxCallStateListener extends PhoneStateListener + { + private int last_state; + + public RockboxCallStateListener() + { + super(); + /* set artificial initial state, + * we will get an initial event shortly after this, + * so to handle it correctly we need an invalid state set */ + last_state = TelephonyManager.CALL_STATE_IDLE - 10; + } + + private void handleState(int state) + { + if (state == last_state) + return; + switch (state) + { + case TelephonyManager.CALL_STATE_IDLE: + postCallHungUp(); + break; + case TelephonyManager.CALL_STATE_RINGING: + postCallIncoming(); + break; + case TelephonyManager.CALL_STATE_OFFHOOK: + /* for incoming calls we handled at RINGING already, + * if the previous state was IDLE then + * this is an outgoing call + */ + if (last_state == TelephonyManager.CALL_STATE_IDLE) + { /* currently handled the same as incoming calls */ + postCallIncoming(); + } + break; + default: + return; + } + last_state = state; + + } + + @Override + public void onCallStateChanged(int state, String number) + { + super.onCallStateChanged(state, number); + handleState(state); + } + } + private native void postCallIncoming(); + private native void postCallHungUp(); +} diff --git a/android/src/org/rockbox/RockboxTimer.java b/android/src/org/rockbox/RockboxTimer.java index 776902e45e..ff48b3f53a 100644 --- a/android/src/org/rockbox/RockboxTimer.java +++ b/android/src/org/rockbox/RockboxTimer.java @@ -25,57 +25,32 @@ import java.util.Timer; import java.util.TimerTask; import android.content.Context; -import android.telephony.TelephonyManager; import android.util.Log; public class RockboxTimer extends Timer -{ - RockboxTimerTask task; - long interval; - +{ private class RockboxTimerTask extends TimerTask { private RockboxTimer timer; - private TelephonyManager tm; - private int last_state; - public RockboxTimerTask(RockboxService s, RockboxTimer parent) + public RockboxTimerTask(RockboxTimer parent) { super(); timer = parent; - tm = (TelephonyManager)s.getSystemService(Context.TELEPHONY_SERVICE); - last_state = tm.getCallState(); } @Override public void run() { timerTask(); - int state = tm.getCallState(); - if (state != last_state) - { - switch (state) - { - case TelephonyManager.CALL_STATE_IDLE: - postCallHungUp(); - break; - case TelephonyManager.CALL_STATE_RINGING: - postCallIncoming(); - default: - break; - } - last_state = state; - } synchronized(timer) { timer.notify(); } } } - public RockboxTimer(RockboxService instance, long period_inverval_in_ms) + public RockboxTimer(Context c, long period_inverval_in_ms) { super("tick timer"); - task = new RockboxTimerTask(instance, this); - schedule(task, 0, period_inverval_in_ms); - interval = period_inverval_in_ms; + schedule(new RockboxTimerTask(this), 0, period_inverval_in_ms); } @SuppressWarnings("unused") @@ -98,6 +73,4 @@ public class RockboxTimer extends Timer } } public native void timerTask(); - private native void postCallIncoming(); - private native void postCallHungUp(); } diff --git a/firmware/SOURCES b/firmware/SOURCES index c2df946394..29dc8644ee 100644 --- a/firmware/SOURCES +++ b/firmware/SOURCES @@ -1714,6 +1714,7 @@ target/hosted/android/kernel-android.c target/hosted/android/pcm-android.c target/hosted/android/powermgmt-android.c target/hosted/android/system-android.c +target/hosted/android/telephony-android.c #ifdef APPLICATION target/hosted/android/app/button-application.c #endif diff --git a/firmware/target/hosted/android/kernel-android.c b/firmware/target/hosted/android/kernel-android.c index 636c849c24..c0d927d026 100644 --- a/firmware/target/hosted/android/kernel-android.c +++ b/firmware/target/hosted/android/kernel-android.c @@ -52,22 +52,6 @@ Java_org_rockbox_RockboxTimer_timerTask(JNIEnv *env, jobject this) call_tick_tasks(); } -JNIEXPORT void JNICALL -Java_org_rockbox_RockboxTimer_postCallIncoming(JNIEnv *env, jobject this) -{ - (void)env; - (void)this; - queue_broadcast(SYS_CALL_INCOMING, 0); -} - -JNIEXPORT void JNICALL -Java_org_rockbox_RockboxTimer_postCallHungUp(JNIEnv *env, jobject this) -{ - (void)env; - (void)this; - queue_broadcast(SYS_CALL_HUNG_UP, 0); -} - void tick_start(unsigned int interval_in_ms) { JNIEnv e = *env_ptr; @@ -76,7 +60,7 @@ void tick_start(unsigned int interval_in_ms) jmethodID constructor = e->GetMethodID(env_ptr, RockboxTimer_class, "", - "(Lorg/rockbox/RockboxService;J)V"); + "(Landroid/content/Context;J)V"); /* the constructor will do the tick_start */ RockboxTimer_instance = e->NewObject(env_ptr, RockboxTimer_class, diff --git a/firmware/target/hosted/android/system-android.c b/firmware/target/hosted/android/system-android.c index 7d1fe9d458..009630eeaa 100644 --- a/firmware/target/hosted/android/system-android.c +++ b/firmware/target/hosted/android/system-android.c @@ -24,10 +24,6 @@ #include "config.h" #include "system.h" -void system_exception_wait(void) { } -void system_reboot(void) { } -void power_off(void) { } -void system_init(void) { } /* global fields for use with various JNI calls */ @@ -40,6 +36,21 @@ uintptr_t *stackend; extern int main(void); extern void powermgmt_init_target(void); +extern void telephony_init_device(void); + +void system_exception_wait(void) { } +void system_reboot(void) { } +void power_off(void) { } + +void system_init(void) +{ + /* no better place yet, most of powermgmt.c is #ifdef'd out for non-native + * builds */ + powermgmt_init_target(); + /* also no better place yet */ + telephony_init_device(); +} + /* this is the entry point of the android app initially called by jni */ JNIEXPORT void JNICALL Java_org_rockbox_RockboxService_main(JNIEnv *env, jobject this) @@ -57,8 +68,5 @@ Java_org_rockbox_RockboxService_main(JNIEnv *env, jobject this) RockboxService_instance = this; RockboxService_class = (*env)->GetObjectClass(env, this); - /* no better place yet, most of powermgmt.c is #ifdef'd out for non-native - * builds */ - powermgmt_init_target(); main(); } diff --git a/firmware/target/hosted/android/telephony-android.c b/firmware/target/hosted/android/telephony-android.c new file mode 100644 index 0000000000..771b7a973a --- /dev/null +++ b/firmware/target/hosted/android/telephony-android.c @@ -0,0 +1,54 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2010 by Thomas Martitz + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + + +#include +#include "kernel.h" + +extern JNIEnv *env_ptr; +extern RockboxService_instance; + + +void telephony_init_device(void) +{ + JNIEnv e = *env_ptr; + jclass class = e->FindClass(env_ptr, "org/rockbox/RockboxTelephony"); + jmethodID constructor = e->GetMethodID(env_ptr, class, "", "(Landroid/content/Context;)V"); + + e->NewObject(env_ptr, class, constructor, RockboxService_instance); +} + + +JNIEXPORT void JNICALL +Java_org_rockbox_RockboxTelephony_postCallIncoming(JNIEnv *env, jobject this) +{ + (void)env; + (void)this; + queue_broadcast(SYS_CALL_INCOMING, 0); +} + +JNIEXPORT void JNICALL +Java_org_rockbox_RockboxTelephony_postCallHungUp(JNIEnv *env, jobject this) +{ + (void)env; + (void)this; + queue_broadcast(SYS_CALL_HUNG_UP, 0); +} -- cgit v1.2.3