Detection of key-pressing at boot-time.

Search This thread

sgt. meow

Senior Member
Dec 21, 2011
4,423
2,973
25
Dhaka
Hi good people of N7 land,

I wanted to ask if it's possible to make keys get detected at boot-time so that a certain function is carried out. If so how?
For example:
The N7 is booting up. I press the Vol + key, and due to a script executed by the init.delta.rc, /system is mounted to a IMG file in the sdcard. A dual-boot mod.
I also ask if this is the best way to do this, and please for the love of God, don't point me to MultiROM. I want to work on my own mod.

I expect helpful answers. And if you can't answer my question, don't even bother posting here.

Although this is a question, this is more dev-related than anything I've encountered in the Q/A section. So I thought of posting it here.
Please move this if this is not the right place, and accept my apologies.

sgt. meow
 

Tasssadar

Inactive Recognized Developer
Dec 31, 2010
818
6,128
Brno
tasssadar.github.com
I don't think this is possible using just some script - init has no way to get input events from keys, so you would have to either edit the init binary or use exec init command.

You could use it to run another binary, which would check if volwhatever is pressed and either did nothing or did the dual-boot stuff.
It depends on when you want to check for the keypress, because if it is after the /system partition is mounted, you could use busybox and run bash script, otherwise it would have to be real binary, because when init is started, you have pretty much "just" kernel running and no userspace.

Or you could pack busybox to boot.img, but if you can code, the binary is pretty easy to make.
 
  • Like
Reactions: sgt. meow

sgt. meow

Senior Member
Dec 21, 2011
4,423
2,973
25
Dhaka
@up
Exactly the kind of answer I was hoping to find. Sucks to realize that I still don't know a lot of coding. But I'm willing to learn if you could point me to the right direction.
 

Androguide.fr

Account currently disabled
Jul 21, 2012
2,056
7,236
GB
meettomy.site
Hi good people of N7 land,

I wanted to ask if it's possible to make keys get detected at boot-time so that a certain function is carried out. If so how?
For example:
The N7 is booting up. I press the Vol + key, and due to a script executed by the init.delta.rc, /system is mounted to a IMG file in the sdcard. A dual-boot mod.
I also ask if this is the best way to do this, and please for the love of God, don't point me to MultiROM. I want to work on my own mod.

I expect helpful answers. And if you can't answer my question, don't even bother posting here.

Although this is a question, this is more dev-related than anything I've encountered in the Q/A section. So I thought of posting it here.
Please move this if this is not the right place, and accept my apologies.

sgt. meow

The first idea that comes to my mind would be to code a simple no-UI app which would use a Service executed by a BroadCastReceiver set to BOOT_COMPLETED.
Then, when triggered (=at boot-time), the service would wait for the user to press a defined key (i.e : volume up). When the service receives the key press, it would mount /system or whatever you wanna do, then stop running (so that other volume up presses don't trigger this event again).

The code could be something like :

Your AndroidManifest.xml :
Code:
< ?xml version="1.0" encoding="utf-8"?>
< manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.sgtmeow.boot.service"
      android:versionCode="1"
      android:versionName="1.0">
      < uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
    < application android:icon="@drawable/icon" android:label="@string/app_name">
       < service android:name=".BootService">
       < intent-filter>
       < action
       android:name = "com.sgtmeow.boot.service.BootService">
       < /action>
       < /intent-filter>
       < /service>
       < receiver android:name=".BootReceiver">
       < intent-filter>
       < action
       android:name ="android.intent.action.BOOT_COMPLETED">
       < /action>
       < /intent-filter>
       < /receiver>
    < /application>
    < uses-sdk android:minSdkVersion="8"
       android:targetSdkVersion="17"android:targetSdkVersion="17" />
< /manifest>

BootReceiver.java :
Code:
package com.sgtmeow.boot.service;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;

public class BootDemoReceiver extends BroadcastReceiver {

 @Override
 public void onReceive(final Context context, final Intent bootintent) {
  Intent mServiceIntent = new Intent();
mServiceIntent.setAction("com.sgtmeow.boot.service.BootService");
  context.startService(mServiceIntent);
 }
}

BootService.java
Code:
package com.sgtmeow.boot.service;

import java.io.DataOutputStream;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
import android.view.KeyEvent;

import com.sgtmeow.boot.service.BootReceiver;

public class BootService extends Service {

	Runtime mRuntime;
	Process mProcess = null;
	DataOutputStream mOutput = null;

	@Override
	public IBinder onBind(final Intent intent) {
		return null;
	}

	@Override
	public void onCreate() {
		super.onCreate();

	}

	public boolean onKeyDown(int keyCode, KeyEvent event) {
		super.onKeyDown(keyCode, event);

		if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
			mountSystem();
			Log.w("SGT.MEOW", "Volume Up has been pressed");
			return true;
		}
		return true;
	}

	public void onStartCommand(final Intent intent, final int startId) {
		super.onStartCommand(intent, startId, startId);

		mountSystem();
	}

	private void mountSystem() {

		Runtime.getRuntime();

		// The service is now started, ask for root and mount /system using
		// busybox (or not)
		try {
			mProcess = mRuntime.exec("su");
			mOutput = new DataOutputStream(mProcess.getOutputStream());
			mOutput.writeBytes("busybox mount -o remount,rw /system");
			mOutput.flush();
			stopService(new Intent(BootService.this, BootReceiver.class));

		} catch (Exception e) {
			Log.e("SGT.MEOW", "An Error Has Occured", e);
			e.printStackTrace();
		}

	}
}

EDIT : unfortunately after some research I found out that Services cannot act as an onKeyListener, you'll have to call an activity to actually listen to the keypress so maybe just a dialog or something, but you won't be able to do it completely UI-less this way, my bad.
 
Last edited:
  • Like
Reactions: sgt. meow

aaronpoweruser

Inactive Recognized Developer
Jul 19, 2007
1,708
7,505
earth
This is not something i would attempt to if you dont know what your doing due to the chance of bricks. but your best bet would be to luanch a binary from early init in the ram disk
 
  • Like
Reactions: sgt. meow

Entropy512

Senior Recognized Developer
Aug 31, 2007
14,088
25,086
Owego, NY
You might want to take a look at how custom recoveries on the Xperia T handles the initial recovery vs. boot selection. On that device, there is no recovery partition, so a single kernel image must support both recovery and normal operation. The bootloader doesn't support an "enter recovery" poweron keycombo, so on the T there are some tricks so that at boot, it:
Sets the LED to purple
Waits 3 seconds or so
If the VolUp key is pressed during those 3 seconds, boot to recovery
Otherwise, boot normally

I believe the same approach is also used on the Xperia Z.
 
  • Like
Reactions: sgt. meow

AidenM

Senior Member
Mar 10, 2011
1,166
335
Maybe you could have a custom recovery that allows this? TWRP and CWM Touch both have source code available that you can check out so you can make your own recovery, which could allow booting of separate ROMS. Recoveries generally boot faster than full ROMs.
 
  • Like
Reactions: sgt. meow

sgt. meow

Senior Member
Dec 21, 2011
4,423
2,973
25
Dhaka
That's not what I was aiming to achieve. If I can manage to map the keys and find a way to detect them at boot-time, the rest is easy as pie. :). Thanks though.
 
  • Like
Reactions: Nbsss

bandoncontortion

Senior Member
Oct 31, 2012
58
23
You might want to take a look at how custom recoveries on the Xperia T handles the initial recovery vs. boot selection. On that device, there is no recovery partition, so a single kernel image must support both recovery and normal operation. The bootloader doesn't support an "enter recovery" poweron keycombo, so on the T there are some tricks so that at boot, it:
Sets the LED to purple
Waits 3 seconds or so
If the VolUp key is pressed during those 3 seconds, boot to recovery
Otherwise, boot normally

I believe the same approach is also used on the Xperia Z.
That's not what I was aiming to achieve. If I can manage to map the keys and find a way to detect them at boot-time, the rest is easy as pie. :). Thanks though.

None of the phones made by Sony have a recovery partition so they have to use a work around to detect keys on boot up. This is what all Xperia devices do to get into recovery: on boot check to see if the desired key is being pressed and if it is unzip the recovery, if it isn't being pressed unzip the normal ramdisk. (I'll post the ramdisk here for you to see how everything works yourself) So with the Xperia Play CyanogenMod kernel that I have how it works is it has two .cpio files. One for the ramdisk and one for the recovery. It uses a .sh file in the sbin to check if keys are being pressed by using /dev/input/event# which in most cases is event1 for volume down (on Nexus 7 the is event0, event1, and event2. My guess is 0 = power button and one and two are vol + and vol -). It then has a link to the init.sh in the root of the ramdisk called init so that when the kernel starts and calls init it starts the script. So what you could do is the same but instead of having two .cpio files you could rename the init file to something else then place the script and link in your ramdisk so that when the key is pressed it calls both what you want to do and the rename init executable. (Not sure how well this would work this is just an idea, if not depending on what you want to do you can keep the compressed ramdisk idea...)

Here is a ramdisk of what I've been talking about that is pulled from my kernel (extracted from an already compiled kernel to make it easy read.):
Link
It's made for the Xperia Play so it also tries to start the LED and vibrator to tell you when to click the Vol - key so how you would tell people to click it on the Nexus 7 I'm not sure...probably just have to have people will just have to spam the key. If you have any questions feel free to ask or if this didn't help I'm sorry just an idea.

Also what it seems like you want to do with the dual boot mod being with the SDCard sounds a lot like what a guy named CosmicDan did on the Xperia Play. You had to change the updater-script in your flashable zip but it worked. Here is the thread: Turbo Kernel and the source code to his kernel: GitHub
 
Last edited:

sgt. meow

Senior Member
Dec 21, 2011
4,423
2,973
25
Dhaka
I know what he did with his kernel. I am working on something similar to the HD2 dual boot method. Haven't had any success yet.

Sent from my Nexus 7 using xda app-developers app
 

Top Liked Posts

  • There are no posts matching your filters.
  • 2
    You might want to take a look at how custom recoveries on the Xperia T handles the initial recovery vs. boot selection. On that device, there is no recovery partition, so a single kernel image must support both recovery and normal operation. The bootloader doesn't support an "enter recovery" poweron keycombo, so on the T there are some tricks so that at boot, it:
    Sets the LED to purple
    Waits 3 seconds or so
    If the VolUp key is pressed during those 3 seconds, boot to recovery
    Otherwise, boot normally

    I believe the same approach is also used on the Xperia Z.
    That's not what I was aiming to achieve. If I can manage to map the keys and find a way to detect them at boot-time, the rest is easy as pie. :). Thanks though.

    None of the phones made by Sony have a recovery partition so they have to use a work around to detect keys on boot up. This is what all Xperia devices do to get into recovery: on boot check to see if the desired key is being pressed and if it is unzip the recovery, if it isn't being pressed unzip the normal ramdisk. (I'll post the ramdisk here for you to see how everything works yourself) So with the Xperia Play CyanogenMod kernel that I have how it works is it has two .cpio files. One for the ramdisk and one for the recovery. It uses a .sh file in the sbin to check if keys are being pressed by using /dev/input/event# which in most cases is event1 for volume down (on Nexus 7 the is event0, event1, and event2. My guess is 0 = power button and one and two are vol + and vol -). It then has a link to the init.sh in the root of the ramdisk called init so that when the kernel starts and calls init it starts the script. So what you could do is the same but instead of having two .cpio files you could rename the init file to something else then place the script and link in your ramdisk so that when the key is pressed it calls both what you want to do and the rename init executable. (Not sure how well this would work this is just an idea, if not depending on what you want to do you can keep the compressed ramdisk idea...)

    Here is a ramdisk of what I've been talking about that is pulled from my kernel (extracted from an already compiled kernel to make it easy read.):
    Link
    It's made for the Xperia Play so it also tries to start the LED and vibrator to tell you when to click the Vol - key so how you would tell people to click it on the Nexus 7 I'm not sure...probably just have to have people will just have to spam the key. If you have any questions feel free to ask or if this didn't help I'm sorry just an idea.

    Also what it seems like you want to do with the dual boot mod being with the SDCard sounds a lot like what a guy named CosmicDan did on the Xperia Play. You had to change the updater-script in your flashable zip but it worked. Here is the thread: Turbo Kernel and the source code to his kernel: GitHub
    1
    I don't think this is possible using just some script - init has no way to get input events from keys, so you would have to either edit the init binary or use exec init command.

    You could use it to run another binary, which would check if volwhatever is pressed and either did nothing or did the dual-boot stuff.
    It depends on when you want to check for the keypress, because if it is after the /system partition is mounted, you could use busybox and run bash script, otherwise it would have to be real binary, because when init is started, you have pretty much "just" kernel running and no userspace.

    Or you could pack busybox to boot.img, but if you can code, the binary is pretty easy to make.
    1
    Hi good people of N7 land,

    I wanted to ask if it's possible to make keys get detected at boot-time so that a certain function is carried out. If so how?
    For example:
    The N7 is booting up. I press the Vol + key, and due to a script executed by the init.delta.rc, /system is mounted to a IMG file in the sdcard. A dual-boot mod.
    I also ask if this is the best way to do this, and please for the love of God, don't point me to MultiROM. I want to work on my own mod.

    I expect helpful answers. And if you can't answer my question, don't even bother posting here.

    Although this is a question, this is more dev-related than anything I've encountered in the Q/A section. So I thought of posting it here.
    Please move this if this is not the right place, and accept my apologies.

    sgt. meow

    The first idea that comes to my mind would be to code a simple no-UI app which would use a Service executed by a BroadCastReceiver set to BOOT_COMPLETED.
    Then, when triggered (=at boot-time), the service would wait for the user to press a defined key (i.e : volume up). When the service receives the key press, it would mount /system or whatever you wanna do, then stop running (so that other volume up presses don't trigger this event again).

    The code could be something like :

    Your AndroidManifest.xml :
    Code:
    < ?xml version="1.0" encoding="utf-8"?>
    < manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.sgtmeow.boot.service"
          android:versionCode="1"
          android:versionName="1.0">
          < uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
        < application android:icon="@drawable/icon" android:label="@string/app_name">
           < service android:name=".BootService">
           < intent-filter>
           < action
           android:name = "com.sgtmeow.boot.service.BootService">
           < /action>
           < /intent-filter>
           < /service>
           < receiver android:name=".BootReceiver">
           < intent-filter>
           < action
           android:name ="android.intent.action.BOOT_COMPLETED">
           < /action>
           < /intent-filter>
           < /receiver>
        < /application>
        < uses-sdk android:minSdkVersion="8"
           android:targetSdkVersion="17"android:targetSdkVersion="17" />
    < /manifest>

    BootReceiver.java :
    Code:
    package com.sgtmeow.boot.service;
    
    import android.content.BroadcastReceiver;
    import android.content.Context;
    import android.content.Intent;
    
    public class BootDemoReceiver extends BroadcastReceiver {
    
     @Override
     public void onReceive(final Context context, final Intent bootintent) {
      Intent mServiceIntent = new Intent();
    mServiceIntent.setAction("com.sgtmeow.boot.service.BootService");
      context.startService(mServiceIntent);
     }
    }

    BootService.java
    Code:
    package com.sgtmeow.boot.service;
    
    import java.io.DataOutputStream;
    
    import android.app.Service;
    import android.content.Intent;
    import android.os.IBinder;
    import android.util.Log;
    import android.view.KeyEvent;
    
    import com.sgtmeow.boot.service.BootReceiver;
    
    public class BootService extends Service {
    
    	Runtime mRuntime;
    	Process mProcess = null;
    	DataOutputStream mOutput = null;
    
    	@Override
    	public IBinder onBind(final Intent intent) {
    		return null;
    	}
    
    	@Override
    	public void onCreate() {
    		super.onCreate();
    
    	}
    
    	public boolean onKeyDown(int keyCode, KeyEvent event) {
    		super.onKeyDown(keyCode, event);
    
    		if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
    			mountSystem();
    			Log.w("SGT.MEOW", "Volume Up has been pressed");
    			return true;
    		}
    		return true;
    	}
    
    	public void onStartCommand(final Intent intent, final int startId) {
    		super.onStartCommand(intent, startId, startId);
    
    		mountSystem();
    	}
    
    	private void mountSystem() {
    
    		Runtime.getRuntime();
    
    		// The service is now started, ask for root and mount /system using
    		// busybox (or not)
    		try {
    			mProcess = mRuntime.exec("su");
    			mOutput = new DataOutputStream(mProcess.getOutputStream());
    			mOutput.writeBytes("busybox mount -o remount,rw /system");
    			mOutput.flush();
    			stopService(new Intent(BootService.this, BootReceiver.class));
    
    		} catch (Exception e) {
    			Log.e("SGT.MEOW", "An Error Has Occured", e);
    			e.printStackTrace();
    		}
    
    	}
    }

    EDIT : unfortunately after some research I found out that Services cannot act as an onKeyListener, you'll have to call an activity to actually listen to the keypress so maybe just a dialog or something, but you won't be able to do it completely UI-less this way, my bad.
    1
    This is not something i would attempt to if you dont know what your doing due to the chance of bricks. but your best bet would be to luanch a binary from early init in the ram disk
    1
    This is not something i would attempt to if you dont know what your doing due to the chance of bricks. but your best bet would be to luanch a binary from early init in the ram disk

    I know how to launch the binary during init. The binary is the problem I am running into.
    Thanks though.