android功耗优化(2)--对齐唤醒

android功耗优化(2)--对齐唤醒,第1张

概述概况Android手机上安装的很多应用都会频繁唤醒手机(唤醒系统、唤醒屏幕),造成手机耗电等现象。良好的对齐唤醒管理方案,就是对后台应用待机时不频繁唤醒,智能节省电量。实现原理:APK作为该功能的入口,勾选应用后,将勾选的应用写入黑名单,并通知framework黑名单内容变化;framework接收到通 概况

AndroID手机上安装的很多应用都会频繁唤醒手机(唤醒系统、唤醒屏幕),造成手机耗电等现象。良好的对齐唤醒管理方案,就是对后台应用待机时不频繁唤醒,智能节省电量。

实现原理:APK作为该功能的入口,勾选应用后,将勾选的应用写入黑名单,并通知framework黑名单内容变化;framework接收到通知后,自动获取黑名单中的应用,保存到列表中;在framework调用接口中检测应用是否在黑名单中,如果在黑名单中则检测闹钟类型,如果闹钟类型是0或2,对应修改为1或3。

应用层功能实现APK界面初始化

在ForbitAlarmlogic构造方法中初始化了数组列表ListPkgs、forbitPkgs、allowPkgs、showPkgs。

ListPkgs:表示需要设置对齐唤醒的应用,如果这些应用已经安装,就会显示在对齐唤醒设置的界面上。初始数据从/data/data/com.***.androID.security/app_bin/forbitappList.xml中获取,如果文件不存在,则从本地资源数组security_array_savepower_forbitalarms中获取。

forbitPkgs:表示对齐唤醒名单,即禁止唤醒的名单,界面勾选的应用。初始数据从SharedPreference数据库名ManagerUtil.PRE_name(com.***.androID.savepowermanager_preferences)中获取键值ManagerUtil.FORBIT_ALARM_APP_List_KEY中保存的数据,将获取的数据保存到forbitPkgs数组中,如果没有数据则返回null。

allowPkgs:表示允许唤醒的名单,界面没有勾选的应用。初始数据从SharedPreference数据库ManagerUtil.PRE_name(com.***.androID.savepowermanager_preferences)中获取键值为ManagerUtil.ALLOW_ALARM_APP_List_KEY中保存的数据,将获取的数据保存到allowPkgs数组列表中;如果没有数据则返回null。

showPkgs:表示要显示在对齐唤醒设置界面的数组应用列表,在数据初始化之前先将该数组清空。对齐唤醒方案优化之前,该数组保存的是ListPkgs列表与已安装应用的交集。优化之后,同时还保存了已安装的第三方应用。

public ForbitAlarmlogic(Context ctx) {    this.mCtx = ctx;    pm = ctx.getPackageManager();    xmlAppList = Util.getDefaultDataPath(ctx) + "/app_bin/appList.xml";    String xmlfile = Util.getDefaultDataPath(ctx)+"/app_bin/forbitappList.xml";    file f = new file(xmlfile);    if (!f.exists()) {        Log.e("forbitappList not exist!");        String[] strs = mCtx.getResources().getStringArray(R.array.security_array_savepower_forbitalarms);        for (String str : strs) {            ListPkgs.add(str);        }    } else {        readFromXmlWithfilename(xmlfile, ListPkgs);    }//      readFromXml();    Set<String> forbitset = (Set<String>)ManagerUtil.getPreferenceValue(mCtx, ManagerUtil.PRE_name,            ManagerUtil.FORBIT_ALARM_APP_List_KEY, null, 4);    if (forbitset != null) {        Iterator<String> forbitir = forbitset.iterator();        while(forbitir.hasNext()) {            String forbit = forbitir.next();            forbitPkgs.add(forbit);        }    }    Set<String> allowset = (Set<String>)ManagerUtil.getPreferenceValue(mCtx, ManagerUtil.PRE_name,            ManagerUtil.ALLOW_ALARM_APP_List_KEY, null, 4);    if (allowset != null) {        Iterator<String> allowir = allowset.iterator();        while(allowir.hasNext()) {            String allow = allowir.next();            allowPkgs.add(allow);        }    }}
    public ArrayList<DroIDApp> getListApps() {        if (forbitPkgs.size() == 0) {            Set<String> forbitset= (Set<String>)ManagerUtil.getPreferenceValue(mCtx, ManagerUtil.PRE_name,                    ManagerUtil.FORBIT_ALARM_APP_List_KEY, null, 4);            if (forbitset == null) {                readFromXml();                HashSet<String> forbitPkgsSet = new HashSet<String>();                for (String pkg : forbitPkgs) {                    forbitPkgsSet.add(pkg);                }                ManagerUtil.savePreferenceValue(mCtx, ManagerUtil.PRE_name,                    ManagerUtil.FORBIT_ALARM_APP_List_KEY, forbitPkgsSet, 4);            } else {                Iterator<String> forbitir = forbitset.iterator();                while(forbitir.hasNext()) {                    String forbit = forbitir.next();                    forbitPkgs.add(forbit);                }            }        }        showPkgs.clear();        ArrayList<DroIDApp> apps = new ArrayList<DroIDApp>();                final List<PackageInfo> installed = pm.getInstalledPackages(0);               String name = null;        for (final PackageInfo appInfo : installed){            String pkg = appInfo.packagename;            if (ListPkgs.contains(pkg)) {                DroIDApp app = new DroIDApp();                name = pm.getApplicationLabel(appInfo.applicationInfo).toString();                app.name = name;                app.icon = appInfo.applicationInfo.loadIcon(pm);                if (forbitPkgs.contains(pkg)) {                    app.online_switch = true;                } else if (allowPkgs.contains(pkg)) {                    app.online_switch = false;                } else {                    app.online_switch = true;                }                app.pkg = pkg;                apps.add(app);                showPkgs.add(pkg);                Log.d("in white List and installed package is : "+pkg);            } else {//              已经安装的第三方应用                if ((appInfo.applicationInfo.uID > 10000)                        && (appInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYstem) == 0                        && (appInfo.applicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYstem_APP) == 0) {                    String pkgname = appInfo.packagename;                    DroIDApp app = new DroIDApp();                    app.name = pm.getApplicationLabel(appInfo.applicationInfo).toString();                    app.icon = appInfo.applicationInfo.loadIcon(pm);//                    app.online_switch = true;                    if (forbitPkgs.contains(pkg)) {                        app.online_switch = true;                    } else if (allowPkgs.contains(pkg)) {                        app.online_switch = false;                    } else {                        app.online_switch = true;                    }                    app.pkg = pkgname;                    apps.add(app);                    showPkgs.add(pkgname);                    Log.d("not in white List and installed third package is : "+pkgname);                }            }        }        return apps;    }
private class GetListDataThread implements Runnable {    @OverrIDe    public voID run() {        // Todo auto-generated method stub        appList = mFbAmLogic.getListApps();        resultList.clear();        for (DroIDApp app : appList) {            Log.d("getListApps appname = " + app.pkg);            if (app.online_switch) {                if (app.pkg != null && app.pkg.length() > 0) {                    resultList.add(app.pkg);                    saveList.add(app.pkg);                }            }        }        Message msg = Message.obtain();        msg.what = MSG_SHOWList;        handler.sendMessage(msg);    }}

ForbitAlarmlogic类的getListApps()方法中重新为forbitPkgs数组赋值

如果forbitPkgs为空,即在构造方法中没有获取到数据,重新从上面数据库中获取数据;如果仍然是空,则从/data/data/com.***.androID.security/app_bin/appList.xml文件中获取,保存到forbitPkgs数组中。

手机管家中显示的对齐唤醒名单主要有:
(1)、forbitappList.xml文件与已安装应用的交集应用;

(2)、已安装的第三方应用。

APK响应机制

APK在启动之后,就已经设置好了黑白名单,初始化过程就是加载界面的过程。

响应点击事件

界面初始化完毕之后,将处于勾选状态的应用保存到两个数组列表:resultList、saveList。响应点击事件时,将应用移除resultList列表,或添加到resultList列表中。

界面退出机制

在onPause()方法中判断resultList与saveList是否相同,如果不相同则重新保存对齐唤醒名单,并通知AlarmManagerService。

    public voID onPause() {        // Todo auto-generated method stub        super.onPause();        new Thread(new Runnable() {             @OverrIDe            public voID run() {                // Todo auto-generated method stub                boolean isSameContent = true;                for (int i = 0; i < saveList.size(); i++) {                    Log.d("saveList "+ i + " = "+saveList.get(i));                }                for (int j = 0; j < resultList.size(); j++) {                    Log.d("resultList "+ j + " = "+resultList.get(j));                }                 if (saveList.size() == resultList.size()) {                    Log.i("saveList == resultList");                    for (String result : resultList) {                        String xmlAppList = "/data/data/com.***.androID.security/app_bin/appList.xml";                        ArrayList<String> forbitPkgs = new ArrayList<String>();                        ForbitAlarmlogic.readFromXmlWithfilename(xmlAppList, forbitPkgs);                        if (!forbitPkgs.contains(result)) {                            Log.i(result + "Not In appList.xml");                            isSameContent = false;                            break;                        }                         if (!saveList.contains(result)) {                            Log.i(result + "Not In SaveList");                            isSameContent = false;                            break;                        }                    }                } else {                    Log.i("saveList Changed");                    isSameContent = false;                }                 if (!isSameContent) {                    Log.i("ForbitAlarmSetting save Data");                    mFbAmLogic.saveAlarmAppMap(resultList);                }            }        }).start();    }

(1)、如何重新保存名单?

首先,清空allowPkgs和forbitPkgs,即先清空允许启动的应用列表和禁止启动的应用列表。

其次,将禁止唤醒的应用(即界面上处于勾选状态的应用)添加到forbitPkgs中,并写入/data/data/com.***.androID.security/app_bin/appList.xml文件中。同时写入对应键值为ManagerUtil.FORBIT_ALARM_APP_List_KEY数据库中。

再次,将允许唤醒的应用(界面上没有勾选的应用)添加到allowPkgs中,并写入对应键值为ManagerUtil.ALLOW_ALARM_APP_List_KEY数据库中。

最后,通知AlarmManagerService。

(2)、如何通知AlarmManagerService?

上面数据保存完毕后,发送广播:com.***.androID.savepower.forbitalarmappListchanged,通知AlarmManagerService。

public static voID notifyFramework(final Context ctx) {    new Thread(){        public voID run() {            try {                Thread.sleep(200);                Intent intent = new Intent();                intent.setAction(ManagerUtil.INTENT_FORBITALARM_List_CHANGED);                ctx.sendbroadcast(intent);            } catch (InterruptedException e) {                Log.e("appList.xml send broadcast error");            }        };    }.start();}

流程图如下:

安装第三方应用

在PackageReceiver类中接收到包安装的广播后,将第三方应用添加到白名单,重新获取对齐唤醒数据。

              new Thread(new Runnable() {                    @OverrIDe                    public voID run() {                        // Todo auto-generated method stub                        Log.d("automatically add newly installed applications into blackList."                                + " packagename = " + packagename);                         synchronized (PackageReceiver.this) {                            mForbitAlarmlogic = ForbitAlarmlogic                                    .getInstance(mCtx);                            mForbitAlarmlogic                                    .packageReceiverApkAdded(packagename);                        }                    }                }).start();
AlarmManagerService实现机制接收广播

当对齐唤醒名单发生变化时,会发送forbitalarmappListchanged 广播。AlarmManagerService定义了该广播的接收器,用来接收APK发送的广播。从appList.xml(/data/data/com.***.androID.security/app_bin/appList.xml)文件中读取应用保存到全局变量mHashtable中。

class UpdateXmlReceiver extends broadcastReceiver {    public UpdateXmlReceiver() {         IntentFilter filter = new IntentFilter();         filter.addAction(ACTION_SAVEPOWER_UPDATEXML);         getContext().registerReceiver(this, filter);    }    @OverrIDe    public voID onReceive(Context context, Intent intent) {        synchronized (mlock) {            // Todo auto-generated method stub            if(YulongFeature.FEATURE_REDUCE_RTC_WAKEUP){                mHashtable.clear();                Slog.d(TAG, "Receive savepower broadcast, read xml again.");                getPackagenameFromXml();            }        }    }}
private voID getPackagenameFromXml() {    fileReader permReader = null;    try {        permReader = new fileReader(xmlNewfile);        Slog.d(TAG, "getPackagenameFromXml : read xmlNewfile ");    } catch (fileNotFoundException e) {        try {            permReader = new fileReader(xmlfile);            Slog.d(TAG, "getPackagenameFromXml : read xmlfile ");        } catch (fileNotFoundException e1) {            // Todo auto-generated catch block            Slog.d(TAG, "getPackagenameFromXml, can not find config xml ");            return;        }    }    try {        XmlPullParser parser = Xml.newPullParser();        parser.setinput(permReader);        XmlUtils.begindocument(parser, "channel");        while (true) {            XmlUtils.nextElement(parser);            if (parser.getEventType() == XmlPullParser.END_document) {                break;            }            String name = parser.getname();            if ("item".equals(name)) {                int ID = Integer.parseInt(parser.getAttributeValue(null, "ID"));                if (ID <= 0) {                     Slog.w(TAG, "<item> without name at "                             + parser.getpositionDescription());                     XmlUtils.skipCurrentTag(parser);                     continue;                 }                String packagename = parser.getAttributeValue(null, "name");                if (packagename == null) {                    Slog.w(TAG, "<item> without name at "                            + parser.getpositionDescription());                    XmlUtils.skipCurrentTag(parser);                    continue;                }                Slog.d(TAG, "getPackagenameFromXml : ID is " + ID + "  name is " + packagename);                mHashtable.put(ID, packagename);                XmlUtils.skipCurrentTag(parser);            } else {                XmlUtils.skipCurrentTag(parser);                continue;            }        }        permReader.close();    } catch (XmlPullParserException e) {        Slog.w(TAG, "Got execption parsing permissions.", e);    } catch (IOException e) {        Slog.w(TAG, "Got execption parsing permissions.", e);    }}
修改闹钟类型

在调用setImpl方法设置闹钟时,我们通过修改闹钟的类型来实现对齐唤醒功能。

if (type == AlarmManager.RTC_WAKEUP || type == AlarmManager.ELAPSED_REALTIME_WAKEUP) {             if(mHashtable.containsValue(callingPackage)){                if (AlarmManager.RTC_WAKEUP == type) {                    type = AlarmManager.RTC;                    Slog.v(TAG, "change alarm type RTC_WAKEUP to RTC for " + callingPackage);                }                if (AlarmManager.ELAPSED_REALTIME_WAKEUP == type) {                    type = AlarmManager.ELAPSED_REALTIME;                    Slog.v(TAG, "change alarm type ELAPSED_REALTIME_WAKEUP to ELAPSED_REALTIME for " + callingPackage);                }            }        }
对齐唤醒添加机制

(1)、第三方应用全部添加到对齐唤醒名单;

(2)、禁止系统应用验证前添加到对齐唤醒名单,避免导致系统异常。

A. 系统核心应用不允许加入对齐唤醒名单,即位于system/priv-app目录下的应用不可以加入对齐唤醒名单;

总结

以上是内存溢出为你收集整理的android功耗优化(2)--对齐唤醒全部内容,希望文章能够帮你解决android功耗优化(2)--对齐唤醒所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/web/1060041.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-25
下一篇 2022-05-25

发表评论

登录后才能评论

评论列表(0条)

保存