SC20 Android 7.1 ACC(GPIO) 系统服务监测及操作

功能:ACC状态通过内核switch上报,系统通过Observer监测状态变化,根据状态变化做灭屏和关机的操作。

1.添加frameworks/base/services/core/java/com/android/server/AccObserver.java

package com.android.server;

import android.content.ContentResolver;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.provider.Settings;
import android.media.AudioManager;
import android.media.Ringtone;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Binder;
import android.os.Handler;
import android.os.Message;
import android.os.PowerManager;
import android.os.SystemClock;
import android.os.UEventObserver;
import android.os.UserHandle;
import android.os.SystemProperties;
import android.provider.Settings;
import android.util.Log;
import android.util.Slog;

import android.content.Intent;
import android.content.IntentFilter;


import java.io.FileDescriptor;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.PrintWriter;


public class AccObserver extends SystemService {


    private static final String TAG = "AccObserver";
    private static final String ACC_UEVENT_MATCH = "DEVPATH=/devices/virtual/switch/car-acc";
    private static final String ACC_STATE_PATH = "sys/class/switch/car-acc/state";

    private static final int MSG_ACC_STATE_CHANGED = 1;
    private static final int MSG_ACC_SCREEN_ON_ACTION = 2;
    private static final int MSG_ACC_SCREEN_OFF_ACTION = 3;
    private static final int MSG_ACC_SHUTDOWN_ACTION = 4;

    private final PowerManager mPowerManager;
    private final PowerManager.WakeLock mWakeLock;

    private final Object mLock = new Object();

    private boolean mSystemReady;

    private int mActualAccState = Intent.EXTRA_ACC_STATE_OFF;

    private int mReportedAccState = -1;
    private int mPreviousAccState = Intent.EXTRA_ACC_STATE_OFF;

    private boolean mUpdatesStopped;
    private long mAcquireLockTime;

    private Context mContext;
    private int screen_state_flag =0;
    private Intent mAccIntent;
    /**
     * Initializes the system service.
     * <p>
     * Subclasses must define a single argument constructor that accepts the context
     * and passes it to super.
     * </p>
     *
     * @param context The system server context.
     */
    public AccObserver(Context context) {
        super(context);
        mContext = context;
        mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
        mWakeLock = mPowerManager.newWakeLock(PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.SCREEN_BRIGHT_WAKE_LOCK, TAG);
    
        mAccIntent = new Intent("com.waysion.acc.screen_to_off");//通知Settings
        mObserver.startObserving(ACC_UEVENT_MATCH);
    }

    @Override
    public void onStart() {
        publishBinderService(TAG, new BinderService());
    }

    @Override
    public void onBootPhase(int phase) {
        if (phase == PHASE_ACTIVITY_MANAGER_READY) {
            synchronized (mLock) {
                mSystemReady = true;

                // don't bother broadcasting undocked here
                if (mReportedAccState != Intent.EXTRA_ACC_STATE_OFF) {
                    //updateLocked();
                }

                BootReceiver mBootReceiver = new BootReceiver();
                IntentFilter filter = new IntentFilter();
                filter.addAction(Intent.ACTION_BOOT_COMPLETED);
                mContext.registerReceiver(mBootReceiver, filter);

                AccControlReceiver mAccControlReceiver = new AccControlReceiver();
                IntentFilter accfilter = new IntentFilter();
                accfilter.addAction("acc_setting_screen_control");
                accfilter.addAction("acc_setting_shutdown_control");
                mContext.registerReceiver(mAccControlReceiver, accfilter);
            }
        }
    }

    private void init() {
        synchronized (mLock) {
            try {
                char[] buffer = new char[1024];
                FileReader file = new FileReader(ACC_STATE_PATH);
                try {
                    int len = file.read(buffer, 0, 1024);
                    mActualAccState = Integer.valueOf((new String(buffer, 0, len)).trim());
                    mPreviousAccState = mActualAccState;
                } finally {
                    file.close();
                }
            } catch (FileNotFoundException e) {
                Log.w(TAG, "This kernel does not have acc station support");
            } catch (Exception e) {
                Log.e(TAG, "" , e);
            }
        }
    }
    private void setActualAccStateLocked(int newState) {
        mActualAccState = newState;
        if (!mUpdatesStopped) {
            setAccStateLocked(newState);
        }
    }


    private void setAccStateLocked(int newState) {
        if (newState != mReportedAccState) {
            mReportedAccState = newState;
            if (mSystemReady) {
                mHandler.sendEmptyMessage(MSG_ACC_STATE_CHANGED);
            }
        }
    }

    private void updateLocked() {
        mAcquireLockTime = SystemClock.uptimeMillis();
        mWakeLock.acquire(5000);
        mHandler.sendEmptyMessage(MSG_ACC_STATE_CHANGED);
    }

    private void handleDockStateChange() {

        synchronized (mLock) {
            // 读取数据库判断是否开启acc功能
            boolean enabling = (Settings.Global.getInt(mContext.getContentResolver(),
                Settings.Global.ACC_PROVISIONED, 0) != 0);
            if (!enabling) {
                Log.i(TAG, "ACC disable !!  return !!");
                return;
            }

            //TODO 
            Log.i(TAG, "ACC state changed from " + mPreviousAccState + " to "
                    + mReportedAccState);
            if (mReportedAccState == -1) {
                return;
            }
            final int previousDockState = mPreviousAccState;
            mPreviousAccState = mReportedAccState;

            // Skip the acc intent if not yet provisioned.
            final ContentResolver cr = getContext().getContentResolver();
           
            // Pack up the values and broadcast them to everyone
            Intent intent = new Intent(Intent.ACTION_ACC_EVENT);
            intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
            intent.putExtra(Intent.EXTRA_ACC_STATE, mReportedAccState);

            // Send the acc event intent.
            // There are many components in the system watching for this so as to
            // adjust audio routing, screen orientation, etc.
            getContext().sendStickyBroadcastAsUser(intent, UserHandle.ALL);
            String screenValue = SystemProperties.get("persist.sys.acc_screen","0");
            String shutdownValue = SystemProperties.get("persist.sys.acc_shutdown","0");
            String screenDelay = SystemProperties.get("persist.sys.screen_delay","10");
            String shutdownDelay = SystemProperties.get("persist.sys.shutdown_delay","10");
            //TODO 执行ACC开关需要的操作
            if (mReportedAccState == 1) {
                if(screenValue.equals("1")){
                    mHandler.removeMessages(MSG_ACC_SCREEN_OFF_ACTION);
                    mHandler.sendEmptyMessage(MSG_ACC_SCREEN_ON_ACTION);
                }else{
                   mHandler.removeMessages(MSG_ACC_SCREEN_OFF_ACTION);
                   mHandler.removeMessages(MSG_ACC_SHUTDOWN_ACTION);    
                
                }
            }else {

                if(screenValue.equals("1")){
                    mHandler.sendEmptyMessageDelayed(MSG_ACC_SCREEN_OFF_ACTION,Integer.parseInt(screenDelay)*1000);
                }

                if(shutdownValue.equals("1")){
                    mHandler.sendEmptyMessageDelayed(MSG_ACC_SHUTDOWN_ACTION,Integer.parseInt(shutdownDelay)*1000);
                }

            }
        }
    }

    private final Handler mHandler = new Handler(true /*async*/) {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_ACC_STATE_CHANGED:
                    handleDockStateChange();
                    //TODO
                    if (mWakeLock.isHeld() && (SystemClock.uptimeMillis() - mAcquireLockTime < 4000)) {
                        mWakeLock.release();
                    }
                    break;
                case MSG_ACC_SCREEN_ON_ACTION:
                    screenOn();
                    break;
                case MSG_ACC_SCREEN_OFF_ACTION:
                    screenOff();
                    break;
                case MSG_ACC_SHUTDOWN_ACTION:
                    if(screen_state_flag==1){
                        screenOn();
                    }
                    Intent intent_shutdown = new Intent(Intent.ACTION_REQUEST_SHUTDOWN);
                    intent_shutdown.putExtra(Intent.EXTRA_KEY_CONFIRM, false);
                    intent_shutdown.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    mContext.startActivityAsUser(intent_shutdown, UserHandle.CURRENT);
                    break;
            }
        }
    };

    private final class AccControlReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            Log.i(TAG, "action is " + intent.getAction());
    
            if (intent.getAction().equals("acc_setting_screen_control")){
                    mHandler.removeMessages(MSG_ACC_SCREEN_OFF_ACTION);
            }else if(intent.getAction().equals("acc_setting_shutdown_control")){
                
                    mHandler.removeMessages(MSG_ACC_SHUTDOWN_ACTION);
            }
        }
    }

    //observer event
    private final UEventObserver mObserver = new UEventObserver() {
        @Override
        public void onUEvent(UEventObserver.UEvent event) {
            try {
                synchronized (mLock) {
                    String gpio_state = getState(event.toString(), "SWITCH_STATE");
                    Log.i(TAG,"gpio_state="+gpio_state);
                    setActualAccStateLocked("1".equals(gpio_state)?1:0);
                }
            } catch (NumberFormatException e) {
                Log.e(TAG, "Could not parse switch state from event " + event);
            }
        }
    };
    private String getState(String strs, String name) {
        char[] strArr = strs.toCharArray();
        String result = "";
        if(strs.contains(name)) {
            for(int index=strs.indexOf(name) + name.length(); strArr[index] !=','; index++) {
                if(strArr[index] != '=') {
                    result += strArr[index];
                }
            }
        } else {
            Log.e(TAG, "no contains " + name);
        }
        return result.replace(" ", "");
    }

    private final class BootReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            Log.i(TAG, "action is " + intent.getAction());
            if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
                synchronized(mLock) {
                    Log.i(TAG, "mActualAccState is " + mActualAccState);
                    init();
                    if (mActualAccState == Intent.EXTRA_ACC_STATE_OFF) {
                        new Thread(new Runnable() {
                            @Override
                            public void run() {
                                try {
                                    Thread.sleep(5000);
                                    setActualAccStateLocked(Intent.EXTRA_ACC_STATE_OFF);//放送handler
                                } catch (InterruptedException e) {
                                    Log.w(TAG, "exception happend");   
                                }
                            }
                        }).start();
                    }
                }
            }
        }
    }

    private final class BinderService extends Binder {
        @Override
        protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
            if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
                    != PackageManager.PERMISSION_GRANTED) {
                pw.println("Permission Denial: can't dump acc observer service from from pid="
                        + Binder.getCallingPid()
                        + ", uid=" + Binder.getCallingUid());
                return;
            }

            final long ident = Binder.clearCallingIdentity();
            try {
                synchronized (mLock) {
                    if (args == null || args.length == 0 || "-a".equals(args[0])) {
                        pw.println("Current Acc Observer Service state:");
                        if (mUpdatesStopped) {
                            pw.println("  (UPDATES STOPPED -- use 'reset' to restart)");
                        }
                        pw.println("  reported state: " + mReportedAccState);
                        pw.println("  previous state: " + mPreviousAccState);
                        pw.println("  actual state: " + mActualAccState);
                    } else if (args.length == 3 && "set".equals(args[0])) {
                        String key = args[1];
                        String value = args[2];
                        try {
                            if ("state".equals(key)) {
                                mUpdatesStopped = true;
                                setAccStateLocked(Integer.parseInt(value));
                            } else {
                                pw.println("Unknown set option: " + key);
                            }
                        } catch (NumberFormatException ex) {
                            pw.println("Bad value: " + value);
                        }
                    } else if (args.length == 1 && "reset".equals(args[0])) {
                        mUpdatesStopped = false;
                        setAccStateLocked(mActualAccState);
                    } else {
                        pw.println("Dump current acc state, or:");
                        pw.println("  set state <value>");
                        pw.println("  reset");
                    }
                }
            } finally {
                Binder.restoreCallingIdentity(ident);
            }
        }
    }

    /**
    * 亮屏
    */
    public void screenOn() {
        mPowerManager.wakeUp(SystemClock.uptimeMillis());
        mWakeLock.acquire();
        mAccIntent.putExtra("screen_off_state","0");
        mContext.sendBroadcastAsUser(mAccIntent, UserHandle.ALL);
        screen_state_flag=0;
        Log.w(TAG, "screenOn");
    }

    /**
    * 释放并直接灭屏
    */
    public void screenOff() {
        mAccIntent.putExtra("screen_off_state","1");
        mContext.sendBroadcastAsUser(mAccIntent, UserHandle.ALL);
        mWakeLock.acquire();
        mWakeLock.release();
        screen_state_flag=1;
        mPowerManager.goToSleep(SystemClock.uptimeMillis());
        Log.w(TAG, "screenOff");
    }
}
2.frameworks/base/core/java/android/provider/Settings.java 增加

        /**
         * Whether the acc has been provisioned (0 = false, 1 = true)
         */
        public static final String ACC_PROVISIONED = "acc_provisioned";

3.修改frameworks/base/core/java/android/content/Intent.java

diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index d08a471..ce246ab 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2733,6 +2733,10 @@ public class Intent implements Parcelable, Cloneable {
     public static final String ACTION_DOCK_EVENT =
             "android.intent.action.DOCK_EVENT";
 
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_ACC_EVENT =
+            "android.intent.action.ACC_EVENT";
+
     /**
      * Broadcast Action: A broadcast when idle maintenance can be started.
      * This means that the user is not interacting with the device and is
@@ -3969,6 +3973,10 @@ public class Intent implements Parcelable, Cloneable {
      */
     public static final int EXTRA_DOCK_STATE_HE_DESK = 4;
 
+    public static final String EXTRA_ACC_STATE = "android.intent.extra.ACC_STATE";
+    public static final int EXTRA_ACC_STATE_ON = 1;
+    public static final int EXTRA_ACC_STATE_OFF = 0;

4.更新api current.txt

diff --git a/api/current.txt b/api/current.txt
index 2cb6f49..3f01723 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -8531,6 +8531,7 @@ package android.content {
     method public deprecated java.lang.String toURI();
     method public java.lang.String toUri(int);
     method public void writeToParcel(android.os.Parcel, int);
+    field public static final java.lang.String ACTION_ACC_EVENT = "android.intent.action.ACC_EVENT";
     field public static final java.lang.String ACTION_AIRPLANE_MODE_CHANGED = "android.intent.action.AIRPLANE_MODE";
     field public static final java.lang.String ACTION_ALL_APPS = "android.intent.action.ALL_APPS";
     field public static final java.lang.String ACTION_ANSWER = "android.intent.action.ANSWER";
@@ -8689,6 +8690,9 @@ package android.content {
     field public static final java.lang.String CATEGORY_UNIT_TEST = "android.intent.category.UNIT_TEST";
     field public static final java.lang.String CATEGORY_VOICE = "android.intent.category.VOICE";
     field public static final android.os.Parcelable.Creator<android.content.Intent> CREATOR;
+    field public static final java.lang.String EXTRA_ACC_STATE = "android.intent.extra.ACC_STATE";
+    field public static final int EXTRA_ACC_STATE_OFF = 0; // 0x0
+    field public static final int EXTRA_ACC_STATE_ON = 1; // 0x1
     field public static final java.lang.String EXTRA_ALARM_COUNT = "android.intent.extra.ALARM_COUNT";
     field public static final java.lang.String EXTRA_ALLOW_MULTIPLE = "android.intent.extra.ALLOW_MULTIPLE";
     field public static final deprecated java.lang.String EXTRA_ALLOW_REPLACE = "android.intent.extra.ALLOW_REPLACE";
@@ -32472,6 +32476,7 @@ package android.provider {
     method public static boolean putInt(android.content.ContentResolver, java.lang.String, int);
     method public static boolean putLong(android.content.ContentResolver, java.lang.String, long);
     method public static boolean putString(android.content.ContentResolver, java.lang.String, java.lang.String);
+    field public static final java.lang.String ACC_PROVISIONED = "acc_provisioned";
 

diff --git a/api/system-current.txt b/api/system-current.txt
index 788c087..392e5c4 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -8871,6 +8871,7 @@ package android.content {
     method public deprecated java.lang.String toURI();
     method public java.lang.String toUri(int);
     method public void writeToParcel(android.os.Parcel, int);
+    field public static final java.lang.String ACTION_ACC_EVENT = "android.intent.action.ACC_EVENT";
     field public static final java.lang.String ACTION_AIRPLANE_MODE_CHANGED = "android.intent.action.AIRPLANE_MODE";
     field public static final java.lang.String ACTION_ALL_APPS = "android.intent.action.ALL_APPS";
     field public static final java.lang.String ACTION_ANSWER = "android.intent.action.ANSWER";
@@ -9036,6 +9037,9 @@ package android.content {
     field public static final java.lang.String CATEGORY_UNIT_TEST = "android.intent.category.UNIT_TEST";
     field public static final java.lang.String CATEGORY_VOICE = "android.intent.category.VOICE";
     field public static final android.os.Parcelable.Creator<android.content.Intent> CREATOR;
+    field public static final java.lang.String EXTRA_ACC_STATE = "android.intent.extra.ACC_STATE";
+    field public static final int EXTRA_ACC_STATE_OFF = 0; // 0x0
+    field public static final int EXTRA_ACC_STATE_ON = 1; // 0x1
     field public static final java.lang.String EXTRA_ALARM_COUNT = "android.intent.extra.ALARM_COUNT";
     field public static final java.lang.String EXTRA_ALLOW_MULTIPLE = "android.intent.extra.ALLOW_MULTIPLE";
     field public static final deprecated java.lang.String EXTRA_ALLOW_REPLACE = "android.intent.extra.ALLOW_REPLACE";
@@ -35228,6 +35232,7 @@ package android.provider {
     method public static boolean putInt(android.content.ContentResolver, java.lang.String, int);
     method public static boolean putLong(android.content.ContentResolver, java.lang.String, long);
     method public static boolean putString(android.content.ContentResolver, java.lang.String, java.lang.String);
+    field public static final java.lang.String ACC_PROVISIONED = "acc_provisioned";
5.frameworks/base/services/java/com/android/server/SystemServer.java 中启动服务

startOtherServices 函数中增加

boolean disableAcc = SystemProperties.getBoolean("config.disable_acc", false);

if (!disableAcc) {
                Slog.d(TAG, "start service AccObserver.class");
                mSystemServiceManager.startService(AccObserver.class);
  }
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Max.Chen

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值