2015-07-22 7 views
10

Я использую PendingIntent, запущенный AlarmManagersetRepeating), чтобы начать wifi-сканирование (используя IntentService) каждые несколько минут. На большинстве устройств и в большинстве случаев нет проблем с этим. Однако на нескольких устройствах я получаю следующее сообщение об ошибке (. Не удалось воспроизвести ошибку на любом тестовом устройстве Это журнал аварии с устройства пользователя):SecurityException брошен при вызове WifiManager startScan

java.lang.RuntimeException: Unable to start service [email protected] 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) 
     ... 

Я создаю PendingIntent из моего приложения поэтому я не вижу причины для SecurityException, выброшенного из WifiManager (тем более, что это случается редко).

The IntentService запущен из PendingIntent кода выглядит следующим образом:

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

boolean ok = mWifiManager.startScan(); 

Любые идеи о том, что может быть причиной этого?

+0

Он говорит, что он требует android.permission.INTERACT_ACROSS_USERS_FULL или android.permission.INTERACT_ACROSS_USERS premission, вы пытаетесь добавить некоторые в манифесте? –

+3

@ Berťák, это разрешение - системное разрешение, и никакое приложение (если это не системное приложение) не может запросить это. Кроме того, это не требуется для вызова 'startScan' и получения результатов через трансляцию SCAN_RESULTS_AVAILABLE_ACTION. Вот что делает его странным ... – Muzikant

+0

Кажется, ваш IntentService работает в другом контексте пользователя. Кажется, один или несколько пользователей вошли в ваш телефон. Это странно. – ShihabSoft

ответ

3

Это происходит из-за новых разрешений приложений для android m. См комментарий выше исходный код 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; 
     } 
    } 

Таким образом, вы должны спросить у пользователя разрешения на выполнения. Поместите эти разрешения в вашем 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"/> 

С апи 23 года вам требуется разрешение на доступ к местоположению пользователя, чтобы использовать его. Я предлагаю вам использовать проверку разрешений на основе уровня api и начать выполнение только в том случае, если разрешения предоставлены. Что-то вроде 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); 
     } 
} 

Кроме того, чтобы проверить на результаты

@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 является разрешение уровня подписи. Просто добавьте этот android: protectionLevel = "подпись" в ваш манифест.

Для получения более подробной информации вы можете проверить это

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

<permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" android:protectionLevel="signature"/> 
+0

Спасибо за подробный ответ, но это не дает решения проблемы. Я знаю изменения разрешений в SDK 23, и манифест имеет разрешения, о которых вы упомянули, но это не объясняет, что ошибка 'broadcast from android просит запустить как пользователь -1, но вызывает от пользователя 0; это требует android.permission.INTERACT_ACROSS_USERS_FULL или android.permission.INTERACT_ACROSS_USERS'. Кроме того, это происходит очень редко, и я не смог воспроизвести ту же ошибку на том же самом устройстве с тем же уровнем API – Muzikant

+0

. Еще одна вещь, фрагмент кода в вашем ответе относится к 'getScanResults', в то время как ошибка получена на' startScan' – Muzikant

+0

@Muzikant wifimanager вызывает getScanResults для получения результатов сканирования после вызова startscsan. Также я обновил свой ответ. –

0

Если вы собираетесь переопределить

onCreate() 

в вашем

IntentService, 

затем сделать Сюр e вы звоните

super.onCreate() 

в нём. Скорее всего, это ваша проблема.

-1

Ваша проблема заключается в том, что вы звоните от другого пользователя и просите работать у другого пользователя, а для этого требуется android.permission.INTERACT_ACROSS_USERS_FULL, и это разрешение уровня подписки.Просто добавьте это android:protectionLevel="signature" в ваш манифест.

Для получения более подробной информации вы можете проверить это

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

<permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" android:protectionLevel="signature"/>