SecurityException thrown when calling WifiManager startScan
Asked Answered
B

3

10

I'm using a PendingIntent launched by AlarmManager (with setRepeating) to start wifi scans (using IntentService) every few minutes. On most devices and in most cases, there is no problem with that. However, on several devices I get the following error (Couldn't reproduce the error on any test device. This is a crash log from a user's device):

java.lang.RuntimeException: Unable to start service com.myapp.android.service.MyService@44a9701 with Intent { act=com.myapp.android.ACTION_PERFORM_WIFI_SCAN flg=0x4 cmp=com.myapp/com.mayapp.android.service.MyService (has extras) }: java.lang.SecurityException: Permission Denial: broadcast from android asks to run as user -1 but is calling from user 0; this requires android.permission.INTERACT_ACROSS_USERS_FULL or android.permission.INTERACT_ACROSS_USERS
       at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:3021)
       at android.app.ActivityThread.-wrap17(ActivityThread.java)
       at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1443)
       at android.os.Handler.dispatchMessage(Handler.java:102)
       at android.os.Looper.loop(Looper.java:148)
       at android.app.ActivityThread.main(ActivityThread.java:5415)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:725)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:615)
Caused by: java.lang.SecurityException: Permission Denial: broadcast from android asks to run as user -1 but is calling from user 0; this requires android.permission.INTERACT_ACROSS_USERS_FULL or android.permission.INTERACT_ACROSS_USERS
       at android.os.Parcel.readException(Parcel.java:1599)
       at android.os.Parcel.readException(Parcel.java:1552)
       at android.net.wifi.IWifiManager$Stub$Proxy.startScan(IWifiManager.java:1045)
       at android.net.wifi.WifiManager.startScan(WifiManager.java:1088)
       ...

I'm creating the PendingIntent from my app so I see no reason for the SecurityException thrown from WifiManager (Especially since this happens rarely).

The IntentService launched from the PendingIntent code is as follows:

mContext.registerReceiver(mWifiScanReceiver, new IntentFilter(
                    WifiManager.SCAN_RESULTS_AVAILABLE_ACTION));

boolean ok = mWifiManager.startScan();

Any ideas on what might be causing this?

Biparous answered 22/7, 2015 at 15:24 Comment(12)
It says that it requires android.permission.INTERACT_ACROSS_USERS_FULL or android.permission.INTERACT_ACROSS_USERS premission, did you try to add some into your manifest?Lumenhour
@Berťák, this permission is a system permission and no app (unless it's a system app) can request that. Also, it is not required for calling startScan and getting the results through the SCAN_RESULTS_AVAILABLE_ACTION broadcast. That's what makes it weird...Biparous
It seems your IntentService runs in a different user context.It seems one or more users have logged into your phone.It makes weird.Numeration
@Numeration That's what I thought, but when trying to run the app with multiple users on same device didn't reproduce the errorBiparous
It seems you got a bug in android.Did you tried on any other devices?Numeration
@Numeration I tried on several devices but on none of them could reproduce this error (even on same type of device)Biparous
@Biparous Do you get this crashlog from crashlytics ? If so or if there is other info can you add it as well, like Device details, OS version, Battery level. In other words whatever there is.Serous
@Biparous which API uses?Corriveau
This is happening on Nexus 5 running Android 6.0Biparous
Also try going to Settings>Apps>Your App>Permissions if you are running Android 6.0+Bouton
Have you tried to see if this occurs on rooted phones? That is the only thing that comes to mind if it works on all other phones you have tried.Regimen
@PabloBaxter I also tried on rooted phones although the error is not received on a rooted deviceBiparous
C
4

This is happening because of the new app permissions for android m. See the comment above the source code of wifimanager's getScanResults() for api 23-

/**
     * Return the results of the latest access point scan.
     * @return the list of access points found in the most recent scan. An app must hold
     * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_COARSE_LOCATION} or
     * {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION} permission
     * in order to get valid results.
     */
public List<ScanResult> getScanResults() {
        try {
            return mService.getScanResults(mContext.getOpPackageName());
        } catch (RemoteException e) {
            return null;
        }
    }

Hence, you will have to ask the user for permissions on runtime. Put these permissions in your manifest-

  <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
  <uses-permission android:name="android.permission.INTERNET"/>
  <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
  <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

From api 23 onwards you require a permission to access user location to use it. I suggest you use a permissions check based on the api level and start intent only if the permissions have been granted. Something like this-

if (Build.VERSION.SDK_INT >= 23) {
int hasReadLocationPermission = checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION);
      if (hasReadLocationPermission != PackageManager.PERMISSION_GRANTED) {
        if (!ActivityCompat.shouldShowRequestPermissionRationale(HomeActivity.this, Manifest.permission.ACCESS_FINE_LOCATION)) {
          showMessageOKCancel("You need to allow access to GPS",
              new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                  ActivityCompat.requestPermissions(HomeActivity.this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, GPS_ENABLE_REQUEST);
                }
              });
          return;
        }
        ActivityCompat.requestPermissions(HomeActivity.this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, GPS_ENABLE_REQUEST);
        return;
      }
      if (locationManager != null && !locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
        gotoGPSEnableScreen();
      } else {
        //Permissions granted and gps is on
        launchService(true);
      }
}

Further to check results-

@Override
  public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    switch (requestCode) {
      case GPS_ENABLE_REQUEST:
        if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
          if (!locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
            gotoGPSEnableScreen();
          }
        } else {
          launchService(false);
        }
      default:
        return;
    }
  }

UPDATE:

android.permission.INTERACT_ACROSS_USERS_FULL is a signature level permission. Just add this android:protectionLevel="signature" in your manifest .

For more details you can check this

http://developer.android.com/guide/topics/manifest/permission-element.html

<permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" android:protectionLevel="signature"/>
Carrasquillo answered 22/2, 2016 at 7:32 Comment(3)
Thanks for the detailed answer but this does not provide a solution to the issue. I'm aware of the permissions change in SDK 23 and the manifest has the permissions you mentioned but this does not explain the error broadcast from android asks to run as user -1 but is calling from user 0; this requires android.permission.INTERACT_ACROSS_USERS_FULL or android.permission.INTERACT_ACROSS_USERS. Furthermore, this happens very rarely and I wasn't able to reproduce the same error on the exact same device with the same API levelBiparous
One more thing, the code fragment in your answer refers to getScanResults while the error is received on startScanBiparous
@Biparous the wifimanager calls getScanResults to get the scan results after you call startscsan. Also I have updated my answer.Carrasquillo
E
0

If you're going to override

onCreate() 

in your

IntentService,

then make sure you call

super.onCreate()

in it. That seems to quite likely be your problem.

Exhilarate answered 22/2, 2016 at 8:0 Comment(0)
H
-1

Your issue is you are calling from different user and asking to run on different user and that requires android.permission.INTERACT_ACROSS_USERS_FULL and that is signature level permission. Just add this android:protectionLevel="signature" in your manifest .

For more details you can check this

http://developer.android.com/guide/topics/manifest/permission-element.html

<permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" android:protectionLevel="signature"/>
Heyward answered 23/2, 2016 at 8:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.