I have a problem that has been nagging me to an extreme extend in the past few days. I would like to write an Android sh script that does the following (to help me sync music, pics etc.):
1) Turn on wifi (wifi is off by default to save power)
2) Check if my wifi connection is in range (lets call it myWifi)
3) If myWifi is not in range, disable wifi, if it is in range, connect and start some synch software
Now, to enable / disable wifi, I use the following command, which requires root:
svc wifi enable / disable
To scan for avaible wifi connections, I use the following command:
iwlist eth0 scan
The strage thing is, that iwlist eth0 scan will only work if I am NOT logged in as root (I am very curious to why this is the case, if anyone knows anything?), running it while root will return:
eth0: Interface doesn't support scanning : Invalid argument
but running it while not logged in as root, will give me the info I need. I have tried different approaches to get around this problem. The most obvious one is logging in as the standard user in the Android system right before invoking the iwlist command:
su -c app_1
However, any command that involves su will return permission denied even when invoking it as root, and since sudo does not exist in Android, I feel pretty lost here. I did also try a workaround involving splitting the script into two parts, and trying to run the first as root and the second as non root (the default user in Android i app_1), but this will only delay the problem...
If anyone has an answer to how to either get around this user problem, or how to use iwlist eth0 scan (or another command that does the same) while logged in as root, I would be very gratefull.
Thank you.
According to man iwlist normal users can only see some left-over scanning results. To initiate a new scan as root you first need to start up your interface (after starting wifi):
ifconfig wlan0 up
Related
this has many similar questions (google for: "no internet access detected. won't automatically reconnect." or: android force wifi connection programmatically).
i thought i had a answer here, but it stopped working after installing 6.0.1 updates (i have may 1 security patches).
seems like this is a behaviour change.
i have some 2013 nexus 7's with 6.0.1 that run a kiosk type app and want to connect programmatically to a specific wireless network that has no internet connection. each tablet has a unique static ip address of the form: 192.168.0.xx. i use the normal java socket constructors and check to see if the interface is up using: NetworkInterface.getNetworkInterfaces().
a manual connection has been made. sometimes there is a dialog that asks whether or not you want to always connect. i always check yes.
but the wifi says: "no internet access detected. won't automatically reconnect" after the router cycles power.
doing a disconnect, enable, reconnect does not work. at best it gets: ip6-localhost/::1.
has anyone had any luck using a request object, or bindProcessToNetwork?
edit: related.
edit: the problem seems to be with: CAPTIVE_PORTAL_DETECTION_ENABLED - this string seems to be defined in the source:
public static final String
CAPTIVE_PORTAL_DETECTION_ENABLED = "captive_portal_detection_enabled";
...
MOVED_TO_GLOBAL.add(Settings.Global.CAPTIVE_PORTAL_DETECTION_ENABLED);
but throws" android.provider.Settings$SettingNotFoundException: captive_portal_detection_enabled when used explicitly and is not visible to android studio.
also, doing a settings list global does not contain the constant.
edit doing a adb shell settings put global captive_portal_detection_enabled 0 does seem to work, but this can not be done in the field when the router cycles power. this value seems to persist when the tablet cycles power. and now this value shows up in a settings list global. also, using the raw string: Settings.Global.getInt(getContentResolver(),"captive_portal_detection_enabled"); now returns 0.
edit: looks like setting it requires: android.permission.WRITE_SECURE_SETTINGS, but of course this fails when put into the manifest since we are not a system app.
edit: trying to exec the shell command throws: java.lang.SecurityException, so it looks like you need to issue the command from adb :(
thanks
Could you try and set the global setting captive_portal_detection_enabled to 0 (false).
What's actually happening is that by default, everytime you connect to a wifi, the FW will test against a server (typically google) to see if it's a captive wifi (needs login). So if your wifi is not connected to google, this check will fail. After that, the device knows that wifi has no internet connection and simply will not autoconnect to it.
Setting this setting to 0, will avoid this check.
Programatically Settings.Global.putInt(getContentResolver(), Settings.Global.CAPTIVE_PORTAL_DETECTION_ENABLED, 0);
You can do it through adb for testing purposes:
adb shell settings put global captive_portal_detection_enabled 0
And retrieve it's value like this:
adb shell settings list global | grep "captive"
IMHO this is not very nice thing to do, since you are changing a setting for the user and many FWs don't provide even an advanced setting to enable/disable this by the user itself. (Google doesn't). But maybe it suits your needs.
Hope it helps!
A non-root solution which is a kind of hack tech. :P
Reboot phone, connect to the non-Internet Wifi;
Go to Settings and create a new user;
Continue, continue, and continue until you see "Checking connection";
As soon as you see "checking connection", switch off your phone;
Switch on your phone again, you will be in "Owner" user, keep it;
Toggle Wifi, and the exclamation mark should disappear quickly :)
Remove that new user or just leave it there;
I don't know why, but it works...
I'm working on a non phone device that run Android 2.3.3. We have a custom Android version (with some additionnal driver) and my application has "system" privileges since we build our apps with the same key used to build android.
I had unlocked full Android API (including com.android.internal.*) following this post : https://devmaze.wordpress.com/2011/01/18/using-com-android-internal-part-1-introduction/.
I deleted the Phone.apk from the device to ensure that no process is using rild.
I can instanciate a GSMPhone from my app, but after, I'm unable to execute any commands like supplyPin or getImei. I always have the same error :
CommandException: RADIO_NOT_AVAILABLE.
I'm really stuck here, any help would be precious.
CommandException: RADIO_NOT_AVAILABLE indicates that the rild socket is not opened. In other words, the rild service is not attached to the underlying basebane/modem you are using.
Run ps in adb shell to check if rild service is in the list. If it is in the list, run ls -l /dev/tty* and check if the modem device attached with the Android platform exists here or not. If it does not exist, it means that the Kernel is unable to enumerate your modem device and you need to add support in kernel for it. If it exists, run adb logcat -b radio and check the radio logs output which would really be helpful to diagnose the issue further.
adb shell ps | grep rild to check if RILD is in runing.
Since you can access all the api, do some initialization like PhoneApp do in Phone application OnCreate(mostly like setting params to modem, set radio power which will power on/off the modem, etc)
I am trying to record my device screen using the shell command as outlined here:
http://developer.android.com/tools/help/adb.html#screenrecord
Using the verbose flag, I am getting a Permission Denial that I think is connected to the fact there is an Owner profile on the device, as it references User 0 and User 1 in the error message.
Does anyone know how I can remove the Owner profile (can't see any options to do so) or how I can set the Owner to user 0?
EDIT - clarification, the error states "broadcast asks to run as user -1 but is calling from user 0"
I got the recording to work.
It seems that for whatever reason, you need to do this via adb shell.
Whilst adb shell is running shell commands on the connected device, running the screenrecord commands directly on the device just doesn't want to work.
I have been doing some low-level hacking on Android.
I'm trying to enable wifi i.e. establish Internet Connectivity through terminal (adb shell). I have written a C program to achieve this by hacking into android's bionic library and libnetutils library to get things working.
Everything works fine. I'm able to acquire an IP address via dhcp request. The problem is that whenever I try to open any site for ex. google.com via browser, it does not opens. But when I enter the IP address of the site "74.125.228.66" (google.com), the page gets loaded.
I have tried several options, like modifying the dns entries in file "resolv.conf" (present in /system/etc) and in file "20-dns.conf" (in /system/etc/dhcpcd/dhcpcd-hooks).
I also tried using "setprop" call to set dns values manually for "dhcp.eth0.dns*" and "dhcp.wlan0.dns*".
But nothing seems to work. There's also an interesting behavior I noticed. If I turn on wifi manually from "settings" menu and then turn it off and then run my program, I don't face this issue anymore. Looks like it uses some settings that I could not figure out.
My guess is that this is DNS issue, but it may be something else. Let me know if anyone has faced this issue before.
Here's is what I do to enable wifi:
Enable wpa_supplicant daemon using set_prop().
Send a dhcp request to acquire IP (code from dhcpclient.c in libnetutils).
Enable dhcpcd daemon using set_prop(). (Even without this, everything works. I ran this so that IP lease gets renewed automatically. ( Although I'm not sure about this, if dhcpcd daemon would take care of lease renewal or not) ).
In order to enable WIFI on Android via command line through a C program, you'll need to do the following:
1) Enable wpa_supplicant daemon. (Make sure you have the wpa_supplicant.conf file at /data/misc/wifi with AP (access point) information in it.). wpa_supplicant internally takes care of loading the driver and then establishes connectivity to the specified networks in its configuration file based on availability and strength.
2) Issue a dhcp request. ( To fetch IP, lease, dns1, dns2 etc.)
3) Start dhcpcd daemon. (For Lease renewal)
4) Set net.dns* properties. (Without this, DNS service would not work for any application)
In order to enable daemons (wpa_supplicant and dhcpcd) and set net.dns* properties , you'll need to use Android property system (property_set() and property_get() functions). To learn more about Android Property System, follow this link:
http://rxwen.blogspot.com/2010/01/android-property-system.html
In order to use above 2 functions, you'll need to hack into bionic and core libcutils library.
Location:
/bionic/libc/bionic/system_properties.c
/system/core/libcutils/properties.c
For issuing dhcp request, you need to hack some of the implementation of libnetutils
Location:
/system/core/libnetutils/*
Disabling Wifi:
1) Unload the driver manually.
2) Stop wpa_supplicant daemon.
3) Stop dhcpcd daemon.
4) Unset net.dns* properties.
In this case, driver needs to be unloaded manually unlike loading. If this step is not done, then any of the existing connections will not be torn apart even after 2, 3, and 4. To manually unload the driver, you need to issue "DRIVER STOP" request to wpa_supplicant which will take care of interacting with kernel to unload the driver.
In order to communicate with wpa_supplicant, you'll need to hack into wpa_cli implementation to see how it works. It basically uses UNIX Domain Sockets to interact with the supplicant. You basically need to have a look at wpa_ctrl.c and wpa_cli.c
To learn more about wpa_supplicant, wpa_cli, follow below link:
http://hostap.epitest.fi/wpa_supplicant/devel/
All above that I explained to you is done in Android at HAL layer.
Location:
/hardware/libhardware_legacy/wifi/wifi.c
So, basically whenever you toggle wifi switch from settings menu, control passes from wifi_app code to wifi_frameworks layer (WifiManager and WifiServices) which passes control to wifi.c (HAL layer) through JNI implementation (WifiNative).
A good starting point would be to look at wifi.c if you want to know things that are done at low level to enable wifi.
PS - All above is what I learned after several attempts trying to figure out stuff on my own. There are no documents or blogs (atleast I didn't find any!) that would specify what needs to be done and order of events that should be followed to enable/disable WIFI. So, it may be possible you might find a better way of doing things. This worked for me, something else might work for you!
What I'm doing:
I've built GNU emacs for native use on an phone.
I run emacs in daemon mode on the phone, so I connect to it anytime with emacsclient, to continue working with regular files, run processes, etc.
When logging in from the terminal on the phone, I'm currently user 10157, everything works:
$ id
uid=10157(10157) gid=10157(10157)
groups=10157(10157),1015(1015),1023(1023),1028(1028),3003(3003)
When I connect via ssh to the phone from a PC (I use DigiSSHd on the phone), it logs me in as a regular user 10282, everything works:
$ id
uid=10282 gid=10282 groups=1015(1015),1023(1023),1028(1028),3003(3003)
Emacs runs fine etc. However, this way I can't connect via emacsclient to the emacs process running under user 10157. This is desirable, since I don't want to start two emacs processes, since I want to continue working with files that I have open in emacs under user 10157.
Therefore:
$ su - 10157
Fine, I can run emacs etc. However, I cannot access the web.
$ ping -c1 google.com
You must have internet permissions to use ping. Aborting.
$ id
uid=10157(10157) gid=10157(10157) groups=10157(10157)
Thus I'm no longer in group 3003, necessary for internet access, besides other groups also.
Why does this group info get stripped, and how can I remedy this, so I can continue accessing the web when su as this user under ssh?
When i run the command:
busybox --list
I don't see su in the list.
su --help
shows Superuser.apk in the help text. It means su is provided by Superuser app.
I followed the steps described by you and i could su as another user and still have internet permission as shown below.
I have the following apps installed.
BusyBox v1.18.5-Stericson
Superuser v3.0.7
Terminal Emulator v1.0.45
SSHDroid v1.9.6
Suggestion:
I think the issue is with su on your device. You may try this one.
https://play.google.com/store/apps/details?id=com.noshufou.android.su
If i just use adb shell without running SSHDroid still i can su as another user with internet permission.
Note: The BusyBox id command doesn't show groups information always.
According to the standard man page for su (from a linux box)
When - is used, it must be specified as the last su option. The other forms (-l and --login) do not have this restriction.
Based on that, try
$ su 10157 -
I'm probably missing something here because this seems way too obvious but why not just 'sudo -u 10157' your emacs program?
you'd still have access to the net and your emacs would be working. or did I miss something important?
Permissions are not environment variables that can be inherited via su -.
Moreover, gid are are hard coded and their associations with each APP uid cannot be changed after installation.
10157 should be the uid of the DigiSSHd application, thus you could try to rebuild it after changing the AndroidManifest.xml to require the proper permission.
You can find something useful here and here.
The same should work for BusyBox (see here).
However, you could open some security hole by enabling NETWORK access through such applications.