Bug 1095914 - Copy over CellScanner from mozstumbler github. r=nalexander

This has a few important changes:
1) Null-check the TelephonyManager availability.
2) The cell scanning code was split to remove wcdma scanning on Fennec due to an older API level on Fennec. This is no longer the case. CellScannerNoWCDMA.java renamed to CellScannerImplementation.java.
3) Remove broadcastsync on the timer thread, have the timer thread message back to the owning class through a handler (guaranteed thread-safe mechanism to notify the owning class that work is done).
This commit is contained in:
Garvan Keeley 2014-11-13 11:54:00 -05:00
parent bc52a3e288
commit d2471eea6c
7 changed files with 145 additions and 93 deletions

View File

@ -32,6 +32,7 @@ import org.mozilla.mozstumbler.service.stumblerthread.scanners.WifiScanner;
public final class Reporter extends BroadcastReceiver {
private static final String LOG_TAG = AppGlobals.makeLogTag(Reporter.class.getSimpleName());
public static final String ACTION_FLUSH_TO_BUNDLE = AppGlobals.ACTION_NAMESPACE + ".FLUSH";
public static final String ACTION_NEW_BUNDLE = AppGlobals.ACTION_NAMESPACE + ".NEW_BUNDLE";
private boolean mIsStarted;
/* The maximum number of Wi-Fi access points in a single observation. */

View File

@ -17,7 +17,6 @@ import org.mozilla.mozstumbler.service.stumblerthread.blocklist.WifiBlockListInt
import org.mozilla.mozstumbler.service.stumblerthread.datahandling.DataStorageManager;
import org.mozilla.mozstumbler.service.stumblerthread.scanners.ScanManager;
import org.mozilla.mozstumbler.service.stumblerthread.scanners.cellscanner.CellScanner;
import org.mozilla.mozstumbler.service.stumblerthread.scanners.cellscanner.CellScannerNoWCDMA;
import org.mozilla.mozstumbler.service.uploadthread.UploadAlarmReceiver;
import org.mozilla.mozstumbler.service.utils.NetworkUtils;
import org.mozilla.mozstumbler.service.utils.PersistentIntentService;
@ -109,10 +108,6 @@ public class StumblerService extends PersistentIntentService
return mScanManager.getCellInfoCount();
}
public int getCurrentCellInfoCount() {
return mScanManager.getCurrentCellInfoCount();
}
public boolean isGeofenced () {
return mScanManager.isGeofenced();
}
@ -125,10 +120,6 @@ public class StumblerService extends PersistentIntentService
NetworkUtils.createGlobalInstance(this);
DataStorageManager.createGlobalInstance(this, this);
if (!CellScanner.isCellScannerImplSet()) {
CellScanner.setCellScannerImpl(new CellScannerNoWCDMA(this));
}
mReporter.startup(this);
}
@ -144,8 +135,6 @@ public class StumblerService extends PersistentIntentService
public void onDestroy() {
super.onDestroy();
UploadAlarmReceiver.cancelAlarm(this, !mScanManager.isPassiveMode());
if (!mScanManager.isScanning()) {
return;
}

View File

@ -424,8 +424,8 @@ public class DataStorageManager {
}
mCurrentReports.reports.add(report);
mCurrentReports.wifiCount = wifiCount;
mCurrentReports.cellCount = cellCount;
mCurrentReports.wifiCount += wifiCount;
mCurrentReports.cellCount += cellCount;
if (mCurrentReports.reports.size() >= MAX_REPORTS_IN_MEMORY) {
// save to disk

View File

@ -158,10 +158,6 @@ public class ScanManager {
return (mCellScanner == null)? 0 :mCellScanner.getCellInfoCount();
}
public int getCurrentCellInfoCount() {
return (mCellScanner == null)? 0 :mCellScanner.getCurrentCellInfoCount();
}
public int getLocationCount() {
return (mGPSScanner == null)? 0 : mGPSScanner.getLocationCount();
}

View File

@ -4,21 +4,28 @@
package org.mozilla.mozstumbler.service.stumblerthread.scanners.cellscanner;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Handler;
import android.os.Message;
import android.support.v4.content.LocalBroadcastManager;
import android.telephony.TelephonyManager;
import android.util.Log;
import org.mozilla.mozstumbler.service.AppGlobals;
import org.mozilla.mozstumbler.service.AppGlobals.ActiveOrPassiveStumbling;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
import org.mozilla.mozstumbler.service.AppGlobals;
import java.util.concurrent.atomic.AtomicBoolean;
import org.mozilla.mozstumbler.service.AppGlobals.ActiveOrPassiveStumbling;
import org.mozilla.mozstumbler.service.stumblerthread.Reporter;
public class CellScanner {
public static final String ACTION_BASE = AppGlobals.ACTION_NAMESPACE + ".CellScanner.";
@ -30,47 +37,30 @@ public class CellScanner {
private static final long CELL_MIN_UPDATE_TIME = 1000; // milliseconds
private final Context mContext;
private static CellScannerImpl sImpl;
private Timer mCellScanTimer;
private final Set<String> mCells = new HashSet<String>();
private int mCurrentCellInfoCount;
private final ReportFlushedReceiver mReportFlushedReceiver = new ReportFlushedReceiver();
private final AtomicBoolean mReportWasFlushed = new AtomicBoolean();
private Handler mBroadcastScannedHandler;
private final CellScannerImpl mCellScannerImplementation;
public ArrayList<CellInfo> sTestingModeCellInfoArray;
public interface CellScannerImpl {
public void start();
public void stop();
public List<CellInfo> getCellInfo();
void start();
boolean isStarted();
boolean isSupportedOnThisDevice();
void stop();
List<CellInfo> getCellInfo();
}
public CellScanner(Context context) {
mContext = context;
}
private static synchronized CellScannerImpl getImplementation() {
return sImpl;
}
public static synchronized boolean isCellScannerImplSet() {
return sImpl != null;
}
/* Fennec doesn't support the apis needed for full scanning, we have different implementations.*/
public static synchronized void setCellScannerImpl(CellScannerImpl cellScanner) {
sImpl = cellScanner;
mCellScannerImplementation = new CellScannerImplementation(context);
}
public void start(final ActiveOrPassiveStumbling stumblingMode) {
if (getImplementation() == null) {
return;
}
try {
getImplementation().start();
} catch (UnsupportedOperationException uoe) {
Log.e(LOG_TAG, "Cell scanner probe failed", uoe);
if (!mCellScannerImplementation.isSupportedOnThisDevice()) {
return;
}
@ -78,58 +68,95 @@ public class CellScanner {
return;
}
LocalBroadcastManager.getInstance(mContext).registerReceiver(mReportFlushedReceiver,
new IntentFilter(Reporter.ACTION_NEW_BUNDLE));
// This is to ensure the broadcast happens from the same thread the CellScanner start() is on
mBroadcastScannedHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
Intent intent = (Intent) msg.obj;
LocalBroadcastManager.getInstance(mContext).sendBroadcastSync(intent);
}
};
mCellScannerImplementation.start();
mCellScanTimer = new Timer();
mCellScanTimer.schedule(new TimerTask() {
int mPassiveScanCount;
@Override
public void run() {
if (getImplementation() == null) {
if (!mCellScannerImplementation.isStarted()) {
return;
}
if (stumblingMode == ActiveOrPassiveStumbling.PASSIVE_STUMBLING &&
mPassiveScanCount++ > AppGlobals.PASSIVE_MODE_MAX_SCANS_PER_GPS)
mPassiveScanCount++ > AppGlobals.PASSIVE_MODE_MAX_SCANS_PER_GPS)
{
mPassiveScanCount = 0;
stop();
return;
}
//if (SharedConstants.isDebug) Log.d(LOG_TAG, "Cell Scanning Timer fired");
final long curTime = System.currentTimeMillis();
ArrayList<CellInfo> cells = (sTestingModeCellInfoArray != null)? sTestingModeCellInfoArray :
new ArrayList<CellInfo>(getImplementation().getCellInfo());
new ArrayList<CellInfo>(mCellScannerImplementation.getCellInfo());
if (mReportWasFlushed.getAndSet(false)) {
clearCells();
}
mCurrentCellInfoCount = cells.size();
if (cells.isEmpty()) {
return;
}
for (CellInfo cell: cells) mCells.add(cell.getCellIdentity());
for (CellInfo cell : cells) {
addToCells(cell.getCellIdentity());
}
Intent intent = new Intent(ACTION_CELLS_SCANNED);
intent.putParcelableArrayListExtra(ACTION_CELLS_SCANNED_ARG_CELLS, cells);
intent.putExtra(ACTION_CELLS_SCANNED_ARG_TIME, curTime);
LocalBroadcastManager.getInstance(mContext).sendBroadcastSync(intent);
// send to handler, so broadcast is not from timer thread
Message message = new Message();
message.obj = intent;
mBroadcastScannedHandler.sendMessage(message);
}
}, 0, CELL_MIN_UPDATE_TIME);
}
public void stop() {
private synchronized void clearCells() {
mCells.clear();
}
private synchronized void addToCells(String cell) {
mCells.add(cell);
}
public synchronized void stop() {
mReportWasFlushed.set(false);
clearCells();
LocalBroadcastManager.getInstance(mContext).unregisterReceiver(mReportFlushedReceiver);
if (mCellScanTimer != null) {
mCellScanTimer.cancel();
mCellScanTimer = null;
}
if (getImplementation() != null) {
getImplementation().stop();
}
mCellScannerImplementation.stop();
}
public int getCellInfoCount() {
public synchronized int getCellInfoCount() {
return mCells.size();
}
public int getCurrentCellInfoCount() {
return mCurrentCellInfoCount;
private class ReportFlushedReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context c, Intent i) {
mReportWasFlushed.set(true);
}
}
}

View File

@ -10,35 +10,40 @@ import android.os.Build;
import android.telephony.CellIdentityCdma;
import android.telephony.CellIdentityGsm;
import android.telephony.CellIdentityLte;
import android.telephony.CellIdentityWcdma;
import android.telephony.CellInfoCdma;
import android.telephony.CellInfoGsm;
import android.telephony.CellInfoLte;
import android.telephony.CellInfoWcdma;
import android.telephony.CellLocation;
import android.telephony.CellSignalStrengthCdma;
import android.telephony.CellSignalStrengthGsm;
import android.telephony.CellSignalStrengthLte;
import android.telephony.CellSignalStrengthWcdma;
import android.telephony.NeighboringCellInfo;
import android.telephony.PhoneStateListener;
import android.telephony.SignalStrength;
import android.telephony.TelephonyManager;
import android.util.Log;
import org.mozilla.mozstumbler.service.AppGlobals;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
/* Fennec does not yet support the api level for WCDMA import */
public class CellScannerNoWCDMA implements CellScanner.CellScannerImpl {
public class CellScannerImplementation implements CellScanner.CellScannerImpl {
protected static String LOG_TAG = AppGlobals.makeLogTag(CellScannerNoWCDMA.class.getSimpleName());
protected static String LOG_TAG = AppGlobals.makeLogTag(CellScannerImplementation.class.getSimpleName());
protected GetAllCellInfoScannerImpl mGetAllInfoCellScanner;
protected TelephonyManager mTelephonyManager;
protected boolean mIsStarted;
protected int mPhoneType;
protected final Context mContext;
protected volatile int mSignalStrength;
protected volatile int mCdmaDbm;
protected volatile int mSignalStrength = CellInfo.UNKNOWN_SIGNAL;
protected volatile int mCdmaDbm = CellInfo.UNKNOWN_SIGNAL;
private PhoneStateListener mPhoneStateListener;
@ -53,13 +58,28 @@ public class CellScannerNoWCDMA implements CellScanner.CellScannerImpl {
List<CellInfo> getAllCellInfo(TelephonyManager tm);
}
public CellScannerNoWCDMA(Context context) {
public CellScannerImplementation(Context context) {
mContext = context;
}
public boolean isSupportedOnThisDevice() {
TelephonyManager telephonyManager = mTelephonyManager;
if (telephonyManager == null) {
telephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
}
return telephonyManager != null &&
(telephonyManager.getPhoneType() == TelephonyManager.PHONE_TYPE_CDMA ||
telephonyManager.getPhoneType() == TelephonyManager.PHONE_TYPE_GSM);
}
@Override
public void start() {
if (mIsStarted) {
public synchronized boolean isStarted() {
return mIsStarted;
}
@Override
public synchronized void start() {
if (mIsStarted || !isSupportedOnThisDevice()) {
return;
}
mIsStarted = true;
@ -72,23 +92,8 @@ public class CellScannerNoWCDMA implements CellScanner.CellScannerImpl {
}
mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
if (mTelephonyManager == null) {
throw new UnsupportedOperationException("TelephonyManager service is not available");
}
mPhoneType = mTelephonyManager.getPhoneType();
if (mPhoneType != TelephonyManager.PHONE_TYPE_GSM
&& mPhoneType != TelephonyManager.PHONE_TYPE_CDMA) {
throw new UnsupportedOperationException("Unexpected Phone Type: " + mPhoneType);
}
mSignalStrength = CellInfo.UNKNOWN_SIGNAL;
mCdmaDbm = CellInfo.UNKNOWN_SIGNAL;
}
mSignalStrength = CellInfo.UNKNOWN_SIGNAL;
mCdmaDbm = CellInfo.UNKNOWN_SIGNAL;
mPhoneStateListener = new PhoneStateListener() {
@Override
public void onSignalStrengthsChanged(SignalStrength ss) {
@ -103,9 +108,9 @@ public class CellScannerNoWCDMA implements CellScanner.CellScannerImpl {
}
@Override
public void stop() {
public synchronized void stop() {
mIsStarted = false;
if (mTelephonyManager != null) {
if (mTelephonyManager != null && mPhoneStateListener != null) {
mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE);
}
mSignalStrength = CellInfo.UNKNOWN_SIGNAL;
@ -113,7 +118,7 @@ public class CellScannerNoWCDMA implements CellScanner.CellScannerImpl {
}
@Override
public List<CellInfo> getCellInfo() {
public synchronized List<CellInfo> getCellInfo() {
List<CellInfo> records = new ArrayList<CellInfo>();
List<CellInfo> allCells = mGetAllInfoCellScanner.getAllCellInfo(mTelephonyManager);
@ -186,10 +191,39 @@ public class CellScannerNoWCDMA implements CellScanner.CellScannerImpl {
return records;
}
@TargetApi(18)
protected boolean addWCDMACellToList(List<CellInfo> cells,
android.telephony.CellInfo observedCell,
TelephonyManager tm) {
boolean added = false;
if (Build.VERSION.SDK_INT >= 18 &&
observedCell instanceof CellInfoWcdma) {
CellIdentityWcdma ident = ((CellInfoWcdma) observedCell).getCellIdentity();
if (ident.getMnc() != Integer.MAX_VALUE && ident.getMcc() != Integer.MAX_VALUE) {
CellInfo cell = new CellInfo(tm.getPhoneType());
CellSignalStrengthWcdma strength = ((CellInfoWcdma) observedCell).getCellSignalStrength();
cell.setWcmdaCellInfo(ident.getMcc(),
ident.getMnc(),
ident.getLac(),
ident.getCid(),
ident.getPsc(),
strength.getAsuLevel());
cells.add(cell);
added = true;
}
}
return added;
}
@TargetApi(18)
protected boolean addCellToList(List<CellInfo> cells,
android.telephony.CellInfo observedCell,
TelephonyManager tm) {
android.telephony.CellInfo observedCell,
TelephonyManager tm) {
if (tm.getPhoneType() == 0) {
return false;
}
boolean added = false;
if (observedCell instanceof CellInfoGsm) {
CellIdentityGsm ident = ((CellInfoGsm) observedCell).getCellIdentity();
@ -226,10 +260,15 @@ public class CellScannerNoWCDMA implements CellScanner.CellScannerImpl {
ident.getTac(),
strength.getAsuLevel(),
strength.getTimingAdvance());
cells.add(cell);
added = true;
cells.add(cell);
added = true;
}
}
if (!added && Build.VERSION.SDK_INT >= 18) {
added = addWCDMACellToList(cells, observedCell, tm);
}
return added;
}

View File

@ -17,7 +17,7 @@ stumbler_sources = [
'java/org/mozilla/mozstumbler/service/stumblerthread/Reporter.java',
'java/org/mozilla/mozstumbler/service/stumblerthread/scanners/cellscanner/CellInfo.java',
'java/org/mozilla/mozstumbler/service/stumblerthread/scanners/cellscanner/CellScanner.java',
'java/org/mozilla/mozstumbler/service/stumblerthread/scanners/cellscanner/CellScannerNoWCDMA.java',
'java/org/mozilla/mozstumbler/service/stumblerthread/scanners/cellscanner/CellScannerImplementation.java',
'java/org/mozilla/mozstumbler/service/stumblerthread/scanners/GPSScanner.java',
'java/org/mozilla/mozstumbler/service/stumblerthread/scanners/LocationBlockList.java',
'java/org/mozilla/mozstumbler/service/stumblerthread/scanners/ScanManager.java',