一、kernel部分主要发按键信息到android上层。
diff --git a/kernel/drivers/misc/key/reset_key.c b/kernel-4.14/drivers/misc/key/reset_key.c index 127319a29fa..8d954fc28c5 100755 --- a/kernel/drivers/misc/key/reset_key.c +++ b/kernel/drivers/misc/key/reset_key.c @@ -12,12 +12,14 @@ #include#include #include - +#include +#include struct reset_key { struct device_node *nd; int reset_gpio; unsigned int irq; struct delayed_work rest_work; + struct input_dev *reset_key_dev ; }; struct reset_key key; @@ -28,39 +30,53 @@ struct file_operations reset_key_fops = { struct miscdevice reset_key_misc = { .minor = MISC_DYNAMIC_MINOR, - .name = "reset_key", - .fops = &reset_key_fops, + .name = "reset_key", + .fops = &reset_key_fops, }; void rest_work_func(struct work_struct *work) { - int value = 0; - + int value = 0 ; + static int key_is_down = 0; + disable_irq(key.irq); value = gpio_get_value(key.reset_gpio); - printk("[%s] value = %dn",__func__,value); + printk(" [%s] value = %d irq=%dn",__func__,value,key.irq); if(1 == value) { // orderly_reboot(); - kernel_restart(NULL); + // kernel_restart(NULL); // 重置 // reset_control_reset(struct reset_control *rstc); - irq_set_irq_type(key.irq,IRQF_TRIGGER_FALLING); + // test_temp = irq_set_irq_type(key.irq,IRQ_TYPE_LEVEL_LOW); + if(key_is_down){ + input_report_key(key.reset_key_dev, KEY_F10, 0); + input_sync(key.reset_key_dev); + } + key_is_down = 0; printk("[%s] if value = %dn",__func__,value); } else { // orderly_reboot(); - irq_set_irq_type(key.irq,IRQF_TRIGGER_RISING); + // test_temp = irq_set_irq_type(key.irq,IRQ_TYPE_LEVEL_HIGH); + if(key_is_down == 0){ + input_report_key(key.reset_key_dev, KEY_F10, 1); + input_sync(key.reset_key_dev); + key_is_down = 1; + } + printk("[%s] else value = %dn",__func__,value); } + enable_irq(key.irq); // orderly_reboot(); } irqreturn_t reset_key_irq_handler(int data, void *arg) { - schedule_delayed_work(&key.rest_work,msecs_to_jiffies(20)); + schedule_delayed_work(&key.rest_work, msecs_to_jiffies(50)); + // schedule_work 结构体名不一样 return IRQ_HANDLED; } @@ -93,14 +109,15 @@ int reset_key_probe(struct platform_device *dev) printk("gpio_request failedn"); return -1; } - +gpio_direction_input(key.reset_gpio); // INIT_WORK(&key.rest_work,rest_work_func); INIT_DELAYED_WORK(&key.rest_work,rest_work_func); //中断注册 中断下文用工作队列 key.irq = irq_of_parse_and_map(key.nd,0); - ret = request_irq(key.irq,reset_key_irq_handler,IRQF_TRIGGER_FALLING, + ret = request_irq(key.irq,reset_key_irq_handler,IRQ_TYPE_EDGE_BOTH, "reset_key_irq", NULL); + //gpio_set_debounce(key.reset_gpio, 10 * 1000); if(ret < 0) { printk("request_irq failedn"); @@ -115,6 +132,14 @@ int reset_key_probe(struct platform_device *dev) printk("misc_register failedn"); return -1; } + key.reset_key_dev = input_allocate_device(); + key.reset_key_dev->name = "reset-key"; + __set_bit(EV_KEY, key.reset_key_dev->evbit); + __set_bit(KEY_F10, key.reset_key_dev->keybit); + ret = input_register_device(key.reset_key_dev); + if(ret){ + printk("key.reset_key_dev register input err!n"); + } //定时器 可以使用函数来消抖 return 0; } -- 2.25.1
二、frameworks里面PhoneWindowManager.java接收kernel 上传上来的按键信息,然后发广播进行恢复出厂设置。核心是发广播。用event.getDownTime()和 event.getEventTime()计算按键的时间。
三、frameworks里面处理按键的部分的代码如下:
---
frameworks/base/api/test-current.txt | 2 +-
.../base/core/java/android/view/KeyEvent.java | 4 +++-
frameworks/base/core/res/res/values/attrs.xml | 1 +
frameworks/base/data/keyboards/Generic.kl | 2 +-
.../server/policy/PhoneWindowManager.java | 19 +++++++++++++++++++
frameworks/native/include/android/keycodes.h | 4 +++-
.../native/include/input/InputEventLabels.h | 1 +
7 files changed, 29 insertions(+), 4 deletions(-)
diff --git a/frameworks/base/api/test-current.txt b/frameworks/base/api/test-current.txt
index 539aaa0a5fa..cff226972b1 100644
--- a/frameworks/base/api/test-current.txt
+++ b/frameworks/base/api/test-current.txt
@@ -5125,7 +5125,7 @@ package android.view {
public class KeyEvent extends android.view.InputEvent implements android.os.Parcelable {
method public static String actionToString(int);
method public final void setDisplayId(int);
- field public static final int LAST_KEYCODE = 289; // 0x121
+ field public static final int LAST_KEYCODE = 290; // 0x122
}
public final class KeyboardShortcutGroup implements android.os.Parcelable {
diff --git a/frameworks/base/core/java/android/view/KeyEvent.java b/frameworks/base/core/java/android/view/KeyEvent.java
index f1bc5ee216b..7a8e81486f2 100644
--- a/frameworks/base/core/java/android/view/KeyEvent.java
+++ b/frameworks/base/core/java/android/view/KeyEvent.java
@@ -826,12 +826,14 @@ public class KeyEvent extends InputEvent implements Parcelable {
public static final int KEYCODE_PROFILE_SWITCH = 288;
public static final int KEYCODE_SCREEN_SHOT = 289;
+
+ public static final int KEYCODE_FACTORY_RESET = 290;
@TestApi
- public static final int LAST_KEYCODE = KEYCODE_SCREEN_SHOT;
+ public static final int LAST_KEYCODE = KEYCODE_FACTORY_RESET;
// NOTE: If you add a new keycode here you must also add it to:
// isSystem()
diff --git a/frameworks/base/core/res/res/values/attrs.xml b/frameworks/base/core/res/res/values/attrs.xml
index cfad781a8e6..0aeb8bb7726 100644
--- a/frameworks/base/core/res/res/values/attrs.xml
+++ b/frameworks/base/core/res/res/values/attrs.xml
@@ -1927,6 +1927,7 @@
+
diff --git a/frameworks/base/data/keyboards/Generic.kl b/frameworks/base/data/keyboards/Generic.kl
index 28be888fe0c..fa461d22ca2 100644
--- a/frameworks/base/data/keyboards/Generic.kl
+++ b/frameworks/base/data/keyboards/Generic.kl
@@ -87,7 +87,7 @@ key 64 F6
key 65 F7
key 66 F8
key 67 F9
-key 68 F10
+key 68 FACTORY_RESET
key 69 NUM_LOCK
key 70 SCROLL_LOCK
key 71 NUMPAD_7
diff --git a/frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java b/frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java
index f0db3107b72..c8675119557 100644
--- a/frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -577,6 +577,10 @@ public class PhoneWindowManager implements WindowManagerPolicy {
private boolean mScreenshotChordPowerKeyTriggered;
private long mScreenshotChordPowerKeyTime;
private long mScreenshotDownKeyTime;
+ private static final long FACTORY_RESET_DELAY_MILLIS = 8*1000;
+ private long mFactoryResetDownKeyTime;
+ private long mFactoryResetEventKeyTime;
+ private long mFactoryResetEndkeyTime;
// Ringer toggle should reuse timing and triggering from screenshot power and a11y vol up
private int mRingerToggleChord = VOLUME_HUSH_OFF;
@@ -1358,6 +1362,15 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mHandler.postDelayed(mScreenshotRunnable, getScreenshotChordLongPressDelay());
}
}
+
+ private void factoryReset(){
+ long endKeyTime = mFactoryResetEventKeyTime - mFactoryResetDownKeyTime;
+ if(endKeyTime >= FACTORY_RESET_DELAY_MILLIS){
+ Intent intent = new Intent("android.intent.action.MASTER_CLEAR");
+ intent.setPackage("android");
+ mContext.sendBroadcast(intent);
+ }
+ }
private void interceptAccessibilityShortcutChord() {
if (mAccessibilityShortcutController.isAccessibilityShortcutAvailable(isKeyguardLocked())
&& mScreenshotChordVolumeDownKeyTriggered && mA11yShortcutChordVolumeUpKeyTriggered
@@ -3722,6 +3735,12 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
break;
}
+ case KeyEvent.KEYCODE_FACTORY_RESET:{
+ mFactoryResetDownKeyTime = event.getDownTime();
+ mFactoryResetEventKeyTime = event.getEventTime();
+ factoryReset();
+ break;
+ }
case KeyEvent.KEYCODE_VOLUME_DOWN:
case KeyEvent.KEYCODE_VOLUME_UP:
case KeyEvent.KEYCODE_VOLUME_MUTE: {
diff --git a/frameworks/native/include/android/keycodes.h b/frameworks/native/include/android/keycodes.h
index 9061eeeba95..9d9944e7087 100644
--- a/frameworks/native/include/android/keycodes.h
+++ b/frameworks/native/include/android/keycodes.h
@@ -778,7 +778,9 @@ enum {
* May be consumed by system to switch current viewer profile. */
AKEYCODE_PROFILE_SWITCH = 288,
- AKEYCODE_SCREEN_SHOT = 289
+ AKEYCODE_SCREEN_SHOT = 289,
+
+ AKEYCODE_FACTORY_RESET = 290
// NOTE: If you add a new keycode here you must also add it to several other files.
// Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list.
};
diff --git a/frameworks/native/include/input/InputEventLabels.h b/frameworks/native/include/input/InputEventLabels.h
index 0891d00a84d..5773a829e1b 100644
--- a/frameworks/native/include/input/InputEventLabels.h
+++ b/frameworks/native/include/input/InputEventLabels.h
@@ -329,6 +329,7 @@ static const InputEventLabel KEYCODES[] = {
DEFINE_KEYCODE(THUMBS_DOWN),
DEFINE_KEYCODE(PROFILE_SWITCH),
DEFINE_KEYCODE(SCREEN_SHOT),
+ DEFINE_KEYCODE(FACTORY_RESET),
{ nullptr, 0 }
--
2.25.1
四、收到广播后进入恢复出厂设置
1、frameworksbasecoreresAndroidManifest.xml
2、frameworksbaseservicescorejavacomandroidserverMasterClearReceiver.java
package com.android.server;
import android.app.ProgressDialog;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.RecoverySystem;
import android.os.UserHandle;
import android.os.storage.StorageManager;
import android.text.TextUtils;
import android.util.Log;
import android.util.Slog;
import android.view.WindowManager;
import com.android.internal.R;
import java.io.IOException;
public class MasterClearReceiver extends BroadcastReceiver {
private static final String TAG = "MasterClear";
private boolean mWipeExternalStorage;
private boolean mWipeEsims;
@Override
public void onReceive(final Context context, final Intent intent) {
if (intent.getAction().equals(Intent.ACTION_REMOTE_INTENT)) {
if (!"google.com".equals(intent.getStringExtra("from"))) {
Slog.w(TAG, "Ignoring master clear request -- not from trusted server.");
return;
}
}
if (Intent.ACTION_MASTER_CLEAR.equals(intent.getAction())) {
Slog.w(TAG, "The request uses the deprecated Intent#ACTION_MASTER_CLEAR, "
+ "Intent#ACTION_FACTORY_RESET should be used instead.");
}
if (intent.hasExtra(Intent.EXTRA_FORCE_MASTER_CLEAR)) {
Slog.w(TAG, "The request uses the deprecated Intent#EXTRA_FORCE_MASTER_CLEAR, "
+ "Intent#EXTRA_FORCE_FACTORY_RESET should be used instead.");
}
final String factoryResetPackage = context
.getString(com.android.internal.R.string.config_factoryResetPackage);
if (Intent.ACTION_FACTORY_RESET.equals(intent.getAction())
&& !TextUtils.isEmpty(factoryResetPackage)) {
intent.setPackage(factoryResetPackage).setComponent(null);
context.sendBroadcastAsUser(intent, UserHandle.SYSTEM);
return;
}
final boolean shutdown = intent.getBooleanExtra("shutdown", false);
final String reason = intent.getStringExtra(Intent.EXTRA_REASON);
mWipeExternalStorage = intent.getBooleanExtra(Intent.EXTRA_WIPE_EXTERNAL_STORAGE, false);
mWipeEsims = intent.getBooleanExtra(Intent.EXTRA_WIPE_ESIMS, false);
final boolean forceWipe = intent.getBooleanExtra(Intent.EXTRA_FORCE_MASTER_CLEAR, false)
|| intent.getBooleanExtra(Intent.EXTRA_FORCE_FACTORY_RESET, false);
Slog.w(TAG, "!!! FACTORY RESET !!!");
// The reboot call is blocking, so we need to do it on another thread.
Thread thr = new Thread("Reboot") {
@Override
public void run() {
try {
RecoverySystem
.rebootWipeUserData(context, shutdown, reason, forceWipe, mWipeEsims);
Log.wtf(TAG, "Still running after master clear?!");
} catch (IOException e) {
Slog.e(TAG, "Can't perform master clear/factory reset", e);
} catch (SecurityException e) {
Slog.e(TAG, "Can't perform master clear/factory reset", e);
}
}
};
if (mWipeExternalStorage) {
// thr will be started at the end of this task.
new WipeDataTask(context, thr).execute();
} else {
thr.start();
}
}
private class WipeDataTask extends AsyncTask {
private final Thread mChainedTask;
private final Context mContext;
private final ProgressDialog mProgressDialog;
public WipeDataTask(Context context, Thread chainedTask) {
mContext = context;
mChainedTask = chainedTask;
mProgressDialog = new ProgressDialog(context);
}
@Override
protected void onPreExecute() {
mProgressDialog.setIndeterminate(true);
mProgressDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_alert);
mProgressDialog.setMessage(mContext.getText(R.string.progress_erasing));
mProgressDialog.show();
}
@Override
protected Void doInBackground(Void... params) {
Slog.w(TAG, "Wiping adoptable disks");
if (mWipeExternalStorage) {
StorageManager sm = (StorageManager) mContext.getSystemService(
Context.STORAGE_SERVICE);
sm.wipeAdoptableDisks();
}
return null;
}
@Override
protected void onPostExecute(Void result) {
mProgressDialog.dismiss();
mChainedTask.start();
}
}
}
五、长按相应的按键后,机器会重启进入恢复出厂设置,看log,又相应的打印。



