Keep wifi on during Android Zero-touch enrollment - android

I created a json by following guide here https://developers.google.com/zero-touch/guides/customer/emm#provision
My sample json:
{
"android.app.extra.PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME": "sample-component-name",
"android.app.extra.PROVISIONING_DEVICE_ADMIN_SIGNATURE_CHECKSUM": "device admin signature",
"android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION": "http://download/location/that.apk",
"android.app.extra.PROVISIONING_SKIP_ENCRYPTION": false,
"android.app.extra.PROVISIONING_ADMIN_EXTRAS_BUNDLE": {
"serverurl": "my-mdm.server.url",
"gid": "testGid",
"un":"testUn",
"pw":"testPass"
},
"android.app.extra.PROVISIONING_WIFI_SSID": "wifi-ssid",
"android.app.extra.PROVISIONING_WIFI_PASSWORD": "correct-password",
"android.app.extra.PROVISIONING_WIFI_PROXY_HOST": "my-wifi.proxy.host.url",
"android.app.extra.PROVISIONING_WIFI_PROXY_PORT": 9999
}
Now the problem is when device connects to wifi, it takes few minutes to actually download apk and install. During that time, sometimes screen turns off which causes wifi to sleep. I understand this it to save battery, but it is sort failing the zero-touch idea.
I found link to a list of Global Settings on DevicePolicyManager doc page. https://developer.android.com/reference/android/provider/Settings.Global.html#WIFI_SLEEP_POLICY
However I am not sure how to set this property through enrollment json. Can anybody please share any doc or example on how to achieve this?
I tried to add wifi_sleep_policy = 2 in EXTRAS_BUNDLE, but it didn't work :(
Device is on Android-7-Nougat.

Related

Ping 8.8.8.8 every 1 minute, after some pings the ping times out

I am having an Android app which needs continuous network monitoring and I require to be notified when I have internet and when not. I have tried Android connectivity manager, which only tells if the internet wifi is connected or not, but doesn't tell if there is reachability. So I used the following ping method to check the reachability.
private fun isOnline(): Boolean {
return try {
val timeoutMs = 1500
val sock = Socket()
val socketAddress = InetSocketAddress("8.8.8.8", 53)
sock.connect(socketAddress, timeoutMs)
sock.close()
true
} catch (e: IOException) {
Logger.e(TAG, e.toString())
false
}
}
Now to keep checking this every 1 minute I am using a fixedRateTimer which will call this method every 1 minute and notify accordingly.
Now the problem I am facing is, this works fine for few hours and I get proper connection status. But after few hours the ping starts timing out. I get a timeout exception every alternate ping.
I want to understand few things,
First thing, is it okay to ping for every 1 minute to check the network?
Can the client be blocked by Google for frequent pings?
Or is it anything related to the ISP?
Is there a better approach in android to achieve what I want?
Any advice would be appreciated. Thanks in advance!
PS : I have also tried onCapabilitiesChanged and the callbacks are not immediate for every connection and disconnection, though the google documentation says callbacks will be immediate.
but doesn't tell if there is reachability. So I used the following ping method to check the reachability
First, that is not a ping. That is opening and closing a socket.
Second, it can only tell you if you can open a socket connection to that IP address. It does not tell you if you can access anything else. So, this is subject to false positives (you can reach 8.8.8.8 but not your real server) and false negatives (8.8.8.8 is blocked by network management, but your real server is not).
Now to keep checking this every 1 minute I am using a fixedRateTimer which will call this method every 1 minute and notify accordingly.
That will only work so long as your process is running, and only until you lose Internet access due to Doze mode/app standby/manufacturer-specific power management solutions.
First thing, is it okay to ping for every 1 minute to check the network?
It has flaws. "Okay" is a subjective measure; only you can decide whether it is "okay" for you.
Can the client be blocked by Google for frequent pings?
This is not a ping. It is certainly within Google's power to take action for buggy clients like this.
Or is it anything related to the ISP?
There are lots of pieces involved in an Android device reaching 8.8.8.8:
The network management for whatever WiFi network the phone is using for connectivity (where relevant)
The mobile carrier or ISP
The various other ISPs between you and Google
Google's own network management
Any of them could take steps, if they so chose.
Is there a better approach in android to achieve what I want?
I would aim to eliminate the "need" entirely, as Android and device manufacturers will be fighting you every step of the way.
At minimum:
Do a valid expected operation, such as an actual ping; and
Do it against a relevant server
IIRC, 8.8.8.8 is a DNS server. If your app is a DNS client, you are welcome perform a valid, useful DNS operation against 8.8.8.8. If your app is not a DNS client, quit messing with somebody else's server. Run your own server and test reaching it. For example, you could run a Web server and test whether you can retrieve your robots.txt file.
Most of the question has been answered, but I want to pick up on the most important one.
First thing, is it okay to ping for every 1 minute to check the network?
No. It is not OK.
It is wasteful
You are consuming Google's resources. Resources that you are not paying for. If everyone did what you are doing it would cost Google a lot of money ... to run a much larger fleet of DNS servers, etc to cope with bazillions of vacuous connections.
You are also consuming resources in the along the route from the user's app to Google with the (unnecessary) network traffic.
This would also apply if you were doing real (ICMP) pings, though not to the same extent.
And bear in mind, this is also consuming electricity. And that means more fossil fuel is burned.
It may be incurring costs for the user
Depending on the what their mobile phone plan is, this may be costing the user of your app network charges. Each of those connections your App is making probably being metered. If they are not aware of this ... or they can't turn this (mis-)feature off, they could get rather annoyed about this. (I would be!)
It doesn't actually work
What you are doing doesn't actually test if the internet is available. What you are actually doing is seeing if your App can connect to the Google DNS services. But the fact that the DNS server is accepting connections doesn't mean that the real services that the user wants to use will be accessible and working. (And vice versa!)
As you noted, connections will occasionally fail for reasons that are probably due to transient problems that resolve themselves. There is nothing you can do about that. That could be a false negative for the internet being "up".
Even if there was a reliable way to find out if the internet is "working", your "pinging" is only giving you a single sample. The internet could go "down" (or come back "up") any time in the up to 60 seconds between your pings. More false negatives and positives.
And as noted, Google DNS is not the same as "the internet", and "the internet" is not the same as the service that the user of you App is really interested in.
Your app doesn't REALLY need this information
The user does not need to know minute by minute that the internet is available.
Most of the time a typical user is doing something else.
They only actually need to know if they are actively using some service. And even then, knowing that the internet was up 60 seconds ago is probably no help to them.
Unfortunately, the only way that the user can tell if the service they are talking to is available right now ... is to actually try to use it.
So what is the real solution?
IMO, there are two approaches:
Forget it. In most cases, the user really doesn't need to know. It is not actually going to materially effect the user if your App does not distinguish "service down" from "internet down".
If you can't forget it.
Implement an end-point on your service that you can ping ... and pay the bills!
If you are trying to implement this in an App where you are talking to someone else's services, stop free-loading on Google. If you want an "internet is up/down" feature in your App, implement your own service for doing this ... and pay the bills.
Note that you will still have false positives and false negatives to deal with. There is no solution to that. It is a fundamental property of the internet.

Detect if an always-on VPN is configured on Android

I have an Android VPN application. When I fire the intent to start the VPN (via VPNService.prepare), it fails immediately if there's an always-on VPN already configured on the device. That seems reasonable, but I'd like to be able to easily detect that case, so I can show a helpful message to the user.
By 'always on' I mean the specific VPN always-on Android VPN flag: https://developer.android.com/guide/topics/connectivity/vpn#always-on
I can't seem to find a way to access that info, even though it is used internally in Android (e.g. here but that getAlwaysOnVpnPackage doesn't seem to be available publicly AFAICT).
The best option I've seen is Check if a VPN connection is active in Android?, which will tell you if any VPN connection is currently active, but that's not enough, because:
I don't want to know about temporary VPN connections: I'm only interested if it's an always-on VPN connection.
Sometimes 'always-on' connections aren't actually always on. If you have a disconnected connection and set it as 'always-on', it's configured as such, and blocks all other VPN installs, but there's no network connection created (Android shows a persistent warning instead, which takes you to the other app to activate the connection). Because there's no connection, the above technique doesn't work. I still need to detect this case, since it still blocks my VPN setup.
Is there any way to check whether the device currently has a VPN configured as 'always-on'?
You can use this method
private fun isVpnAlwaysOn(): Boolean {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {
val alwaysOn = Settings.Secure.getString(contentResolver, "always_on_vpn_app")
return !alwaysOn.isNullOrEmpty()
} else false
}
'alwaysOn' contains the package name of the app for which always-on is configured.
In the end, it seems this isn't possible on a normal device any way that I can find. I think is possible if you're a device admin, but that requires managed enterprise devices etc.
For now, I've handled this by watching for near-instant (less than 200ms) VPN setup failures (between running startActivityForResult(vpnIntent) and receiving onActivityResult with RESULT_CANCELED) and then showing a helpful message in that case.
Full implementation is in https://github.com/httptoolkit/httptoolkit-android/commit/928fbf92a4f868042789471be0d42800a226194b in case you're trying to do the same.

WiFi suggestion API fail on Android

I've been trying to use the new Android WiFi Suggestion API with the code taken exactly from the example, but each time I try to connect to a network, when I call wifiManager.addNetworkSuggestions(suggestionsList) I get status 3 in response, which (according to this site) means IP provision failure. What does that mean? How can I handle that?
My app has all the required permissions and even some more (CHANGE_WIFI_STATE, ACCESS_WIFI_STATE, INTERNET, ACCESS_FINE_LOCATION, CHANGE_NETWORK_STATE, ACCESS_NETWORK_STATE), and the location is turned on. I tried with a few WiFi networks (all are visible in the WiFi settings), but still got the same IP provisioning error.
Had the same issue and found it quite confusing because status = 3 can mean two things: STATUS_SUGGESTION_APPROVAL_REJECTED_BY_USER or STATUS_NETWORK_SUGGESTIONS_ERROR_ADD_DUPLICATE.
In my case it was the latter. Basically the suggestion is remembered once submitted. I solved this by removing my suggestion before it's added:
wifiManager.removeNetworkSuggestions(suggestions)
val status = wifiManager.addNetworkSuggestions(suggestions)

How to fix "DOMException" error in Web Bluetooth API?

I'm setting up a Bluetooth LE GATT Server in Android, and want to use Web Bluetooth API in Chrome as a GATT client to check if it properly works. Actually, this is my first step to build a FIDO Authenticator in Android later on.
Firstly, I tried to set my service's uuid is 0000fffd-0000-1000-8000-00805f9b34fb in my Android app. Something like this:
// start gatt server
bluetoothGattServer = bluetoothManager.openGattServer(this, callback);
bluetoothGattServer.addService(
new BluetoothGattService(UUID.fromString("0000fffd-0000-1000-8000-00805f9b34fb"),
BluetoothGattService.SERVICE_TYPE_PRIMARY));
// start advertising
// ...
Then, I executed the following Javascript code in Chrome to check whether the connection can be established.
navigator.bluetooth.requestDevice({
filters: [{ services: ['0000fffd-0000-1000-8000-00805f9b34fb'] }] })
.then(device => { console.log(device); })
.catch(error => { console.log(error); });
However, I only got the exception as below
DOMException
When I changed the uuid to another one such as 62893031-5e68-4a71-94e4-01fb81f16818 in my Android code, then it worked! (I mean it was able to connect to my phone and I could see my device info in Chrome's console)
I didn't know what exactly the problem. What was the problem with my former uuid? How can I debug it to know the root cause?
Thank you for checking!
You can try
console.log(error.messsage);
in stead of
console.log(error);
You will see
requestDevice() called with a filter containing a blocklisted UUID.
https://webbluetoothcg.github.io/web-bluetooth/#attacks-on-devices
Check it out to see the security reason.

CN1 Connectivity - Concerns when internet is unstable in Public places

I'm using Connectivity library to see the internet(Wifi or network data) is active and saving the data in Storage if there is no connectivity(Offline) and synchronize with server when connected to internet. I'm having issues in public places where the internet is consistently unstable(esp. in basements, offices, stores, Coffee shops etc., where there is internet connects in and out). When I check the Connectivity is active but by the time I started synchronizing internet goes offline (Something like this). this leads inconsistent /partial updates to the server. Also, in coffee shops and Airports where wifi gets connected but there will be "Agree Terms and Conditions" page to connect. Not all the browsers will take you to that page directly after joining the Wifi. In that case I see the wifi is active in Mobile but actually it is not activated until I accept the terms and Conditions in IE or some specific browser. Any one else having difficulty in handling these kind of issue from Mobile App?
My App - Hangs on Login screen if I'm trying to login when there is in-stable/in consistent internet.It thinks wifi is there but not.
IF I'm on a screen where I will display list, screen will show blank for infinite time. Adding timeout for server request/response or something will help such scenario.
I know I'm not handling this case in code to show some kind of error message but I need some guidance to detect these conditions suing CN1 API to handle through my app.Please advise.
Code:
public boolean isOffline() {
if (Connectivity.isConnected() && forceOffline) {
relogin();
}
return forceOffline || !Connectivity.isConnected();
}
The problem is that it's impossible to detect online/offline properly as you might be connected to a local wifi/network but it might be a bad connection that won't let you reach the server. As far as the library is concerned you are connected... But in reality you don't have a connection.
First set the timeout values in NetworkManager to lower values to improve the experience although this won't solve a situation where data starts downloading and stops in the middle.
Next you need to handle these cases one by one and provide the user with a way to toggle the offline mode. Unfortunately there is no silver bullet for network reliability. You just need to go through every path and try to detect these things.

Categories

Resources