Merge "Use new ISurfaceComposer::destroyDisplay method" into klp-dev
diff --git a/Android.mk b/Android.mk
index 7e34c84..df10876 100644
--- a/Android.mk
+++ b/Android.mk
@@ -128,6 +128,8 @@
core/java/android/hardware/display/IDisplayManagerCallback.aidl \
core/java/android/hardware/input/IInputManager.aidl \
core/java/android/hardware/input/IInputDevicesChangedListener.aidl \
+ core/java/android/hardware/location/IFusedLocationHardware.aidl \
+ core/java/android/hardware/location/IFusedLocationHardwareSink.aidl \
core/java/android/hardware/location/IGeofenceHardware.aidl \
core/java/android/hardware/location/IGeofenceHardwareCallback.aidl \
core/java/android/hardware/location/IGeofenceHardwareMonitorCallback.aidl \
@@ -232,12 +234,14 @@
keystore/java/android/security/IKeyChainService.aidl \
location/java/android/location/ICountryDetector.aidl \
location/java/android/location/ICountryListener.aidl \
+ location/java/android/location/IFusedProvider.aidl \
location/java/android/location/IGeocodeProvider.aidl \
location/java/android/location/IGeofenceProvider.aidl \
location/java/android/location/IGpsStatusListener.aidl \
location/java/android/location/IGpsStatusProvider.aidl \
location/java/android/location/ILocationListener.aidl \
location/java/android/location/ILocationManager.aidl \
+ location/java/android/location/IFusedGeofenceHardware.aidl \
location/java/android/location/IGpsGeofenceHardware.aidl \
location/java/android/location/INetInitiatedListener.aidl \
location/java/com/android/internal/location/ILocationProvider.aidl \
@@ -379,6 +383,7 @@
frameworks/base/location/java/android/location/Geofence.aidl \
frameworks/base/location/java/android/location/Location.aidl \
frameworks/base/location/java/android/location/LocationRequest.aidl \
+ frameworks/base/location/java/android/location/FusedBatchOptions.aidl \
frameworks/base/location/java/com/android/internal/location/ProviderProperties.aidl \
frameworks/base/location/java/com/android/internal/location/ProviderRequest.aidl \
frameworks/base/telephony/java/android/telephony/ServiceState.aidl \
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 4e6c3dc..c65f17e 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -16,14 +16,13 @@
package android.app;
-import android.R;
import android.os.BatteryStats;
import android.os.IBinder;
import com.android.internal.app.IUsageStats;
+import com.android.internal.app.ProcessStats;
import com.android.internal.os.PkgUsageStats;
import com.android.internal.os.TransferPipe;
import com.android.internal.util.FastPrintWriter;
-import com.android.internal.util.MemInfoReader;
import android.content.ComponentName;
import android.content.Context;
@@ -35,9 +34,7 @@
import android.content.pm.UserInfo;
import android.content.res.Resources;
import android.graphics.Bitmap;
-import android.graphics.Point;
import android.graphics.Rect;
-import android.hardware.display.DisplayManagerGlobal;
import android.os.Bundle;
import android.os.Debug;
import android.os.Handler;
@@ -52,7 +49,6 @@
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.Slog;
-import android.view.Display;
import java.io.FileDescriptor;
import java.io.FileOutputStream;
@@ -2253,7 +2249,7 @@
PrintWriter pw = new FastPrintWriter(fout);
dumpService(pw, fd, Context.ACTIVITY_SERVICE, new String[] { "package", packageName });
pw.println();
- dumpService(pw, fd, "procstats", new String[] { packageName });
+ dumpService(pw, fd, ProcessStats.SERVICE_NAME, new String[] { packageName });
pw.println();
dumpService(pw, fd, "usagestats", new String[] { "--packages", packageName });
pw.println();
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index 6318e38..1c28138 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -786,10 +786,14 @@
// 2 most significant bits in screenLayout).
setLayoutDirection(locale);
}
+ if (delta.screenLayout != 0 && screenLayout != delta.screenLayout) {
+ changed |= ActivityInfo.CONFIG_LAYOUT_DIRECTION;
+ setLayoutDirection(locale);
+ }
if (delta.userSetLocale && (!userSetLocale || ((changed & ActivityInfo.CONFIG_LOCALE) != 0)))
{
- userSetLocale = true;
changed |= ActivityInfo.CONFIG_LOCALE;
+ userSetLocale = true;
}
if (delta.touchscreen != TOUCHSCREEN_UNDEFINED
&& touchscreen != delta.touchscreen) {
@@ -933,6 +937,9 @@
changed |= ActivityInfo.CONFIG_LOCALE;
changed |= ActivityInfo.CONFIG_LAYOUT_DIRECTION;
}
+ if (delta.screenLayout != 0 && screenLayout != delta.screenLayout) {
+ changed |= ActivityInfo.CONFIG_LAYOUT_DIRECTION;
+ }
if (delta.touchscreen != TOUCHSCREEN_UNDEFINED
&& touchscreen != delta.touchscreen) {
changed |= ActivityInfo.CONFIG_TOUCHSCREEN;
@@ -1005,7 +1012,7 @@
public static boolean needNewResources(int configChanges, int interestingChanges) {
return (configChanges & (interestingChanges|ActivityInfo.CONFIG_FONT_SCALE)) != 0;
}
-
+
/**
* @hide Return true if the sequence of 'other' is better than this. Assumes
* that 'this' is your current sequence and 'other' is a new one you have
diff --git a/core/java/android/database/DefaultDatabaseErrorHandler.java b/core/java/android/database/DefaultDatabaseErrorHandler.java
old mode 100644
new mode 100755
index a9e39c3..b234e34
--- a/core/java/android/database/DefaultDatabaseErrorHandler.java
+++ b/core/java/android/database/DefaultDatabaseErrorHandler.java
@@ -99,7 +99,7 @@
}
Log.e(TAG, "deleting the database file: " + fileName);
try {
- new File(fileName).delete();
+ SQLiteDatabase.deleteDatabase(new File(fileName));
} catch (Exception e) {
/* print warning and ignore exception */
Log.w(TAG, "delete failed: " + e.getMessage());
diff --git a/core/java/android/hardware/location/IFusedLocationHardware.aidl b/core/java/android/hardware/location/IFusedLocationHardware.aidl
new file mode 100644
index 0000000..382c12c
--- /dev/null
+++ b/core/java/android/hardware/location/IFusedLocationHardware.aidl
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2013, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/license/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.location;
+
+import android.hardware.location.IFusedLocationHardwareSink;
+import android.location.FusedBatchOptions;
+
+/**
+ * Fused Location hardware interface.
+ * This interface is the basic set of supported functionality by Fused Hardware
+ * modules that offer Location batching capabilities.
+ *
+ * @hide
+ */
+interface IFusedLocationHardware {
+ /**
+ * Registers a sink with the Location Hardware object.
+ *
+ * @param eventSink The sink to register.
+ */
+ void registerSink(in IFusedLocationHardwareSink eventSink);
+
+ /**
+ * Unregisters a sink with the Location Hardware object.
+ *
+ * @param eventSink The sink to unregister.
+ */
+ void unregisterSink(in IFusedLocationHardwareSink eventSink);
+
+ /**
+ * Provides access to the batch size available in Hardware.
+ *
+ * @return The batch size the hardware supports.
+ */
+ int getSupportedBatchSize();
+
+ /**
+ * Requests the Hardware to start batching locations.
+ *
+ * @param id An Id associated with the request.
+ * @param batchOptions The options required for batching.
+ *
+ * @throws RuntimeException if the request Id exists.
+ */
+ void startBatching(in int id, in FusedBatchOptions batchOptions);
+
+ /**
+ * Requests the Hardware to stop batching for the given Id.
+ *
+ * @param id The request that needs to be stopped.
+ * @throws RuntimeException if the request Id is unknown.
+ */
+ void stopBatching(in int id);
+
+ /**
+ * Updates a batching operation in progress.
+ *
+ * @param id The Id of the operation to update.
+ * @param batchOptions The options to apply to the given operation.
+ *
+ * @throws RuntimeException if the Id of the request is unknown.
+ */
+ void updateBatchingOptions(in int id, in FusedBatchOptions batchOptions);
+
+ /**
+ * Requests the most recent locations available in Hardware.
+ * This operation does not dequeue the locations, so still other batching
+ * events will continue working.
+ *
+ * @param batchSizeRequested The number of locations requested.
+ */
+ void requestBatchOfLocations(in int batchSizeRequested);
+
+ /**
+ * Flags if the Hardware supports injection of diagnostic data.
+ *
+ * @return True if data injection is supported, false otherwise.
+ */
+ boolean supportsDiagnosticDataInjection();
+
+ /**
+ * Injects diagnostic data into the Hardware subsystem.
+ *
+ * @param data The data to inject.
+ * @throws RuntimeException if injection is not supported.
+ */
+ void injectDiagnosticData(in String data);
+
+ /**
+ * Flags if the Hardware supports injection of device context information.
+ *
+ * @return True if device context injection is supported, false otherwise.
+ */
+ boolean supportsDeviceContextInjection();
+
+ /**
+ * Injects device context information into the Hardware subsystem.
+ *
+ * @param deviceEnabledContext The context to inject.
+ * @throws RuntimeException if injection is not supported.
+ */
+ void injectDeviceContext(in int deviceEnabledContext);
+}
diff --git a/core/java/android/hardware/location/IFusedLocationHardwareSink.aidl b/core/java/android/hardware/location/IFusedLocationHardwareSink.aidl
new file mode 100644
index 0000000..a11d8ab
--- /dev/null
+++ b/core/java/android/hardware/location/IFusedLocationHardwareSink.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2013, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/license/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.location;
+
+import android.location.Location;
+
+/**
+ * Fused Location hardware event sink interface.
+ * This interface defines the set of events that the FusedLocationHardware provides.
+ *
+ * @hide
+ */
+interface IFusedLocationHardwareSink {
+ /**
+ * Event generated when a batch of location information is available.
+ *
+ * @param locations The batch of location information available.
+ */
+ void onLocationAvailable(in Location[] locations);
+
+ /**
+ * Event generated from FLP HAL to provide diagnostic data to the platform.
+ *
+ * @param data The diagnostic data provided by FLP HAL.
+ */
+ void onDiagnosticDataAvailable(in String data);
+}
\ No newline at end of file
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 12646bd..38ffb96 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -155,6 +155,7 @@
private static final String BATTERY_LEVEL_DATA = "lv";
private static final String WIFI_DATA = "wfl";
private static final String MISC_DATA = "m";
+ private static final String HISTORY_DATA = "h";
private static final String SCREEN_BRIGHTNESS_DATA = "br";
private static final String SIGNAL_STRENGTH_TIME_DATA = "sgt";
private static final String SIGNAL_SCANNING_TIME_DATA = "sst";
@@ -2390,7 +2391,7 @@
while (getNextHistoryLocked(rec)) {
pw.print(BATTERY_STATS_CHECKIN_VERSION); pw.print(',');
pw.print(0); pw.print(',');
- pw.print("h"); pw.print(',');
+ pw.print(HISTORY_DATA); pw.print(',');
hprinter.printNextItemCheckin(pw, rec, now);
pw.println();
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 1ba39b3..4865fd0 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -5662,6 +5662,12 @@
public static final String SELINUX_STATUS = "selinux_status";
/**
+ * Developer setting to force RTL layout.
+ * @hide
+ */
+ public static final String DEVELOPMENT_FORCE_RTL = "debug.force_rtl";
+
+ /**
* Settings to backup. This is here so that it's in the same place as the settings
* keys and easy to update.
*
diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java
index e2035c2..596ca8c 100644
--- a/core/java/android/text/TextUtils.java
+++ b/core/java/android/text/TextUtils.java
@@ -19,6 +19,8 @@
import android.content.res.Resources;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.SystemProperties;
+import android.provider.Settings;
import android.text.style.AbsoluteSizeSpan;
import android.text.style.AlignmentSpan;
import android.text.style.BackgroundColorSpan;
@@ -1743,8 +1745,10 @@
return View.LAYOUT_DIRECTION_RTL;
}
}
-
- return View.LAYOUT_DIRECTION_LTR;
+ // If forcing into RTL layout mode, return RTL as default, else LTR
+ return SystemProperties.getBoolean(Settings.Global.DEVELOPMENT_FORCE_RTL, false)
+ ? View.LAYOUT_DIRECTION_RTL
+ : View.LAYOUT_DIRECTION_LTR;
}
/**
diff --git a/services/java/com/android/server/ProcessMap.java b/core/java/com/android/internal/app/ProcessMap.java
similarity index 97%
rename from services/java/com/android/server/ProcessMap.java
rename to core/java/com/android/internal/app/ProcessMap.java
index 20c97ba..6ff0304 100644
--- a/services/java/com/android/server/ProcessMap.java
+++ b/core/java/com/android/internal/app/ProcessMap.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server;
+package com.android.internal.app;
import android.util.ArrayMap;
import android.util.SparseArray;
diff --git a/services/java/com/android/internal/app/ProcessStats.java b/core/java/com/android/internal/app/ProcessStats.java
similarity index 92%
rename from services/java/com/android/internal/app/ProcessStats.java
rename to core/java/com/android/internal/app/ProcessStats.java
index 5e9b6a1..39c23cf 100644
--- a/services/java/com/android/internal/app/ProcessStats.java
+++ b/core/java/com/android/internal/app/ProcessStats.java
@@ -29,7 +29,6 @@
import android.util.TimeUtils;
import android.webkit.WebViewFactory;
import com.android.internal.util.ArrayUtils;
-import com.android.server.ProcessMap;
import dalvik.system.VMRuntime;
import java.io.PrintWriter;
@@ -39,10 +38,12 @@
import java.util.Comparator;
import java.util.Objects;
-final public class ProcessStats implements Parcelable {
+public final class ProcessStats implements Parcelable {
static final String TAG = "ProcessStats";
static final boolean DEBUG = false;
-
+
+ public static final String SERVICE_NAME = "procstats";
+
public static final int STATE_NOTHING = -1;
public static final int STATE_PERSISTENT = 0;
public static final int STATE_TOP = 1;
@@ -84,13 +85,20 @@
public static final int FLAG_SHUTDOWN = 1<<1;
public static final int FLAG_SYSPROPS = 1<<2;
- static final int[] ALL_MEM_ADJ = new int[] { ADJ_MEM_FACTOR_NORMAL, ADJ_MEM_FACTOR_MODERATE,
- ADJ_MEM_FACTOR_LOW, ADJ_MEM_FACTOR_CRITICAL };
- static final int[] ALL_SCREEN_ADJ = new int[] { ADJ_SCREEN_OFF, ADJ_SCREEN_ON };
- static final int[] NON_CACHED_PROC_STATES = new int[] { STATE_PERSISTENT,
- STATE_TOP, STATE_IMPORTANT_FOREGROUND,
+ public static final int[] ALL_MEM_ADJ = new int[] { ADJ_MEM_FACTOR_NORMAL,
+ ADJ_MEM_FACTOR_MODERATE, ADJ_MEM_FACTOR_LOW, ADJ_MEM_FACTOR_CRITICAL };
+
+ public static final int[] ALL_SCREEN_ADJ = new int[] { ADJ_SCREEN_OFF, ADJ_SCREEN_ON };
+
+ public static final int[] NON_CACHED_PROC_STATES = new int[] {
+ STATE_PERSISTENT, STATE_TOP, STATE_IMPORTANT_FOREGROUND,
STATE_IMPORTANT_BACKGROUND, STATE_BACKUP, STATE_HEAVY_WEIGHT,
- STATE_SERVICE, STATE_SERVICE_RESTARTING, STATE_RECEIVER, STATE_HOME
+ STATE_SERVICE, STATE_SERVICE_RESTARTING, STATE_RECEIVER
+ };
+
+ public static final int[] BACKGROUND_PROC_STATES = new int[] {
+ STATE_IMPORTANT_FOREGROUND, STATE_IMPORTANT_BACKGROUND, STATE_BACKUP,
+ STATE_HEAVY_WEIGHT, STATE_SERVICE, STATE_SERVICE_RESTARTING, STATE_RECEIVER
};
// Map from process states to the states we track.
@@ -215,7 +223,7 @@
}
};
- static private void printScreenLabel(PrintWriter pw, int offset) {
+ private static void printScreenLabel(PrintWriter pw, int offset) {
switch (offset) {
case ADJ_NOTHING:
pw.print(" ");
@@ -232,7 +240,7 @@
}
}
- static public void printScreenLabelCsv(PrintWriter pw, int offset) {
+ public static void printScreenLabelCsv(PrintWriter pw, int offset) {
switch (offset) {
case ADJ_NOTHING:
break;
@@ -248,7 +256,7 @@
}
}
- static private void printMemLabel(PrintWriter pw, int offset) {
+ private static void printMemLabel(PrintWriter pw, int offset) {
switch (offset) {
case ADJ_NOTHING:
pw.print(" ");
@@ -271,7 +279,7 @@
}
}
- static public void printMemLabelCsv(PrintWriter pw, int offset) {
+ public static void printMemLabelCsv(PrintWriter pw, int offset) {
if (offset >= ADJ_MEM_FACTOR_NORMAL) {
if (offset <= ADJ_MEM_FACTOR_CRITICAL) {
pw.print(ADJ_MEM_NAMES_CSV[offset]);
@@ -281,7 +289,7 @@
}
}
- static long dumpSingleTime(PrintWriter pw, String prefix, long[] durations,
+ public static long dumpSingleTime(PrintWriter pw, String prefix, long[] durations,
int curState, long curStartTime, long now) {
long totalTime = 0;
int printedScreen = -1;
@@ -361,7 +369,7 @@
if (type != serviceType) {
continue;
}
- long time = svc.mProcessStats.getLong(off, 0);
+ long time = svc.mStats.getLong(off, 0);
if (curState == memFactor) {
didCurState = true;
time += now - curStartTime;
@@ -374,7 +382,7 @@
pw.println();
}
- static void computeProcessData(ProcessState proc, ProcessDataCollection data, long now) {
+ public static void computeProcessData(ProcessState proc, ProcessDataCollection data, long now) {
data.totalTime = 0;
data.numPss = data.minPss = data.avgPss = data.maxPss =
data.minUss = data.avgUss = data.maxUss = 0;
@@ -815,7 +823,7 @@
for (int i=0; i<proc.mDurationsTableSize; i++) {
int off = proc.mDurationsTable[i];
int type = (off>>OFFSET_TYPE_SHIFT)&OFFSET_TYPE_MASK;
- long time = proc.mProcessStats.getLong(off, 0);
+ long time = proc.mStats.getLong(off, 0);
if (proc.mCurState == type) {
didCurState = true;
time += now - proc.mStartTime;
@@ -831,13 +839,13 @@
for (int i=0; i<proc.mPssTableSize; i++) {
int off = proc.mPssTable[i];
int type = (off>>OFFSET_TYPE_SHIFT)&OFFSET_TYPE_MASK;
- long count = proc.mProcessStats.getLong(off, PSS_SAMPLE_COUNT);
- long min = proc.mProcessStats.getLong(off, PSS_MINIMUM);
- long avg = proc.mProcessStats.getLong(off, PSS_AVERAGE);
- long max = proc.mProcessStats.getLong(off, PSS_MAXIMUM);
- long umin = proc.mProcessStats.getLong(off, PSS_USS_MINIMUM);
- long uavg = proc.mProcessStats.getLong(off, PSS_USS_AVERAGE);
- long umax = proc.mProcessStats.getLong(off, PSS_USS_MAXIMUM);
+ long count = proc.mStats.getLong(off, PSS_SAMPLE_COUNT);
+ long min = proc.mStats.getLong(off, PSS_MINIMUM);
+ long avg = proc.mStats.getLong(off, PSS_AVERAGE);
+ long max = proc.mStats.getLong(off, PSS_MAXIMUM);
+ long umin = proc.mStats.getLong(off, PSS_USS_MINIMUM);
+ long uavg = proc.mStats.getLong(off, PSS_USS_AVERAGE);
+ long umax = proc.mStats.getLong(off, PSS_USS_MAXIMUM);
pw.print(',');
printProcStateTag(pw, type);
pw.print(':');
@@ -979,6 +987,37 @@
out.writeInt(PSS_COUNT);
out.writeInt(LONGS_SIZE);
+ // First commit all running times.
+ ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap();
+ final int NPROC = procMap.size();
+ for (int ip=0; ip<NPROC; ip++) {
+ SparseArray<ProcessState> uids = procMap.valueAt(ip);
+ final int NUID = uids.size();
+ for (int iu=0; iu<NUID; iu++) {
+ uids.valueAt(iu).commitStateTime(now);
+ }
+ }
+ ArrayMap<String, SparseArray<PackageState>> pkgMap = mPackages.getMap();
+ final int NPKG = pkgMap.size();
+ for (int ip=0; ip<NPKG; ip++) {
+ SparseArray<PackageState> uids = pkgMap.valueAt(ip);
+ final int NUID = uids.size();
+ for (int iu=0; iu<NUID; iu++) {
+ PackageState pkgState = uids.valueAt(iu);
+ final int NPROCS = pkgState.mProcesses.size();
+ for (int iproc=0; iproc<NPROCS; iproc++) {
+ ProcessState proc = pkgState.mProcesses.valueAt(iproc);
+ if (proc.mCommonProcess != proc) {
+ proc.commitStateTime(now);
+ }
+ }
+ final int NSRVS = pkgState.mServices.size();
+ for (int isvc=0; isvc<NSRVS; isvc++) {
+ pkgState.mServices.valueAt(isvc).commitStateTime(now);
+ }
+ }
+ }
+
out.writeLong(mTimePeriodStartClock);
out.writeLong(mTimePeriodStartRealtime);
out.writeLong(mTimePeriodEndRealtime);
@@ -991,7 +1030,7 @@
for (int i=0; i<(mLongs.size()-1); i++) {
out.writeLongArray(mLongs.get(i));
}
- long[] lastLongs = mLongs.get(mLongs.size()-1);
+ long[] lastLongs = mLongs.get(mLongs.size() - 1);
for (int i=0; i<mNextLong; i++) {
out.writeLong(lastLongs[i]);
if (DEBUG) Slog.d(TAG, "Writing last long #" + i + ": " + lastLongs[i]);
@@ -1003,8 +1042,6 @@
}
out.writeLongArray(mMemFactorDurations);
- ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap();
- final int NPROC = procMap.size();
out.writeInt(NPROC);
for (int ip=0; ip<NPROC; ip++) {
out.writeString(procMap.keyAt(ip));
@@ -1018,8 +1055,6 @@
proc.writeToParcel(out, now);
}
}
- ArrayMap<String, SparseArray<PackageState>> pkgMap = mPackages.getMap();
- final int NPKG = pkgMap.size();
out.writeInt(NPKG);
for (int ip=0; ip<NPKG; ip++) {
out.writeString(pkgMap.keyAt(ip));
@@ -1530,11 +1565,8 @@
long time = service.getDuration(serviceType, curState, curStartTime,
state, now);
String running = "";
- if (curState == state) {
- time += now - curStartTime;
- if (pw != null) {
- running = " (running)";
- }
+ if (curState == state && pw != null) {
+ running = " (running)";
}
if (time != 0) {
if (pw != null) {
@@ -1824,11 +1856,11 @@
}
public static final class ProcessState {
- final ProcessStats mProcessStats;
- final ProcessState mCommonProcess;
- final String mPackage;
- final int mUid;
- final String mName;
+ public final ProcessStats mStats;
+ public final ProcessState mCommonProcess;
+ public final String mPackage;
+ public final int mUid;
+ public final String mName;
int[] mDurationsTable;
int mDurationsTableSize;
@@ -1849,14 +1881,14 @@
boolean mMultiPackage;
- long mTmpTotalTime;
+ public long mTmpTotalTime;
/**
* Create a new top-level process state, for the initial case where there is only
* a single package running in a process. The initial state is not running.
*/
public ProcessState(ProcessStats processStats, String pkg, int uid, String name) {
- mProcessStats = processStats;
+ mStats = processStats;
mCommonProcess = this;
mPackage = pkg;
mUid = uid;
@@ -1870,7 +1902,7 @@
*/
public ProcessState(ProcessState commonProcess, String pkg, int uid, String name,
long now) {
- mProcessStats = commonProcess.mProcessStats;
+ mStats = commonProcess.mStats;
mCommonProcess = commonProcess;
mPackage = pkg;
mUid = uid;
@@ -1882,32 +1914,32 @@
ProcessState clone(String pkg, long now) {
ProcessState pnew = new ProcessState(this, pkg, mUid, mName, now);
if (mDurationsTable != null) {
- mProcessStats.mAddLongTable = new int[mDurationsTable.length];
- mProcessStats.mAddLongTableSize = 0;
+ mStats.mAddLongTable = new int[mDurationsTable.length];
+ mStats.mAddLongTableSize = 0;
for (int i=0; i<mDurationsTableSize; i++) {
int origEnt = mDurationsTable[i];
int type = (origEnt>>OFFSET_TYPE_SHIFT)&OFFSET_TYPE_MASK;
- int newOff = mProcessStats.addLongData(i, type, 1);
- mProcessStats.mAddLongTable[i] = newOff | type;
- mProcessStats.setLong(newOff, 0, mProcessStats.getLong(origEnt, 0));
+ int newOff = mStats.addLongData(i, type, 1);
+ mStats.mAddLongTable[i] = newOff | type;
+ mStats.setLong(newOff, 0, mStats.getLong(origEnt, 0));
}
- pnew.mDurationsTable = mProcessStats.mAddLongTable;
- pnew.mDurationsTableSize = mProcessStats.mAddLongTableSize;
+ pnew.mDurationsTable = mStats.mAddLongTable;
+ pnew.mDurationsTableSize = mStats.mAddLongTableSize;
}
if (mPssTable != null) {
- mProcessStats.mAddLongTable = new int[mPssTable.length];
- mProcessStats.mAddLongTableSize = 0;
+ mStats.mAddLongTable = new int[mPssTable.length];
+ mStats.mAddLongTableSize = 0;
for (int i=0; i<mPssTableSize; i++) {
int origEnt = mPssTable[i];
int type = (origEnt>>OFFSET_TYPE_SHIFT)&OFFSET_TYPE_MASK;
- int newOff = mProcessStats.addLongData(i, type, PSS_COUNT);
- mProcessStats.mAddLongTable[i] = newOff | type;
+ int newOff = mStats.addLongData(i, type, PSS_COUNT);
+ mStats.mAddLongTable[i] = newOff | type;
for (int j=0; j<PSS_COUNT; j++) {
- mProcessStats.setLong(newOff, j, mProcessStats.getLong(origEnt, j));
+ mStats.setLong(newOff, j, mStats.getLong(origEnt, j));
}
}
- pnew.mPssTable = mProcessStats.mAddLongTable;
- pnew.mPssTableSize = mProcessStats.mAddLongTableSize;
+ pnew.mPssTable = mStats.mAddLongTable;
+ pnew.mPssTableSize = mStats.mAddLongTableSize;
}
pnew.mNumExcessiveWake = mNumExcessiveWake;
pnew.mNumExcessiveCpu = mNumExcessiveCpu;
@@ -1928,7 +1960,6 @@
}
void writeToParcel(Parcel out, long now) {
- commitStateTime(now);
out.writeInt(mMultiPackage ? 1 : 0);
out.writeInt(mDurationsTableSize);
for (int i=0; i<mDurationsTableSize; i++) {
@@ -1952,13 +1983,13 @@
mMultiPackage = multiPackage;
}
if (DEBUG) Slog.d(TAG, "Reading durations table...");
- mDurationsTable = mProcessStats.readTableFromParcel(in, mName, "durations");
+ mDurationsTable = mStats.readTableFromParcel(in, mName, "durations");
if (mDurationsTable == BAD_TABLE) {
return false;
}
mDurationsTableSize = mDurationsTable != null ? mDurationsTable.length : 0;
if (DEBUG) Slog.d(TAG, "Reading pss table...");
- mPssTable = mProcessStats.readTableFromParcel(in, mName, "pss");
+ mPssTable = mStats.readTableFromParcel(in, mName, "pss");
if (mPssTable == BAD_TABLE) {
return false;
}
@@ -2017,13 +2048,13 @@
if (idx >= 0) {
off = mDurationsTable[idx];
} else {
- mProcessStats.mAddLongTable = mDurationsTable;
- mProcessStats.mAddLongTableSize = mDurationsTableSize;
- off = mProcessStats.addLongData(~idx, mCurState, 1);
- mDurationsTable = mProcessStats.mAddLongTable;
- mDurationsTableSize = mProcessStats.mAddLongTableSize;
+ mStats.mAddLongTable = mDurationsTable;
+ mStats.mAddLongTableSize = mDurationsTableSize;
+ off = mStats.addLongData(~idx, mCurState, 1);
+ mDurationsTable = mStats.mAddLongTable;
+ mDurationsTableSize = mStats.mAddLongTableSize;
}
- long[] longs = mProcessStats.mLongs.get((off>>OFFSET_ARRAY_SHIFT)&OFFSET_ARRAY_MASK);
+ long[] longs = mStats.mLongs.get((off>>OFFSET_ARRAY_SHIFT)&OFFSET_ARRAY_MASK);
longs[(off>>OFFSET_INDEX_SHIFT)&OFFSET_INDEX_MASK] += dur;
}
}
@@ -2068,13 +2099,13 @@
if (idx >= 0) {
off = mPssTable[idx];
} else {
- mProcessStats.mAddLongTable = mPssTable;
- mProcessStats.mAddLongTableSize = mPssTableSize;
- off = mProcessStats.addLongData(~idx, mCurState, PSS_COUNT);
- mPssTable = mProcessStats.mAddLongTable;
- mPssTableSize = mProcessStats.mAddLongTableSize;
+ mStats.mAddLongTable = mPssTable;
+ mStats.mAddLongTableSize = mPssTableSize;
+ off = mStats.addLongData(~idx, mCurState, PSS_COUNT);
+ mPssTable = mStats.mAddLongTable;
+ mPssTableSize = mStats.mAddLongTableSize;
}
- long[] longs = mProcessStats.mLongs.get((off>>OFFSET_ARRAY_SHIFT)&OFFSET_ARRAY_MASK);
+ long[] longs = mStats.mLongs.get((off>>OFFSET_ARRAY_SHIFT)&OFFSET_ARRAY_MASK);
idx = (off>>OFFSET_INDEX_SHIFT)&OFFSET_INDEX_MASK;
long count = longs[idx+PSS_SAMPLE_COUNT];
if (count == 0) {
@@ -2134,7 +2165,7 @@
// The array map is still pointing to a common process state
// that is now shared across packages. Update it to point to
// the new per-package state.
- ProcessState proc = mProcessStats.mPackages.get(pkgName,
+ ProcessState proc = mStats.mPackages.get(pkgName,
mUid).mProcesses.get(mName);
if (proc == null) {
throw new IllegalStateException("Didn't create per-package process");
@@ -2151,7 +2182,7 @@
// The array map is still pointing to a common process state
// that is now shared across packages. Update it to point to
// the new per-package state.
- proc = mProcessStats.mPackages.get(pkgList.keyAt(index),
+ proc = mStats.mPackages.get(pkgList.keyAt(index),
proc.mUid).mProcesses.get(proc.mName);
if (proc == null) {
throw new IllegalStateException("Didn't create per-package process");
@@ -2163,7 +2194,7 @@
long getDuration(int state, long now) {
int idx = binarySearch(mDurationsTable, mDurationsTableSize, state);
- long time = idx >= 0 ? mProcessStats.getLong(mDurationsTable[idx], 0) : 0;
+ long time = idx >= 0 ? mStats.getLong(mDurationsTable[idx], 0) : 0;
if (mCurState == state) {
time += now - mStartTime;
}
@@ -2172,42 +2203,42 @@
long getPssSampleCount(int state) {
int idx = binarySearch(mPssTable, mPssTableSize, state);
- return idx >= 0 ? mProcessStats.getLong(mPssTable[idx], PSS_SAMPLE_COUNT) : 0;
+ return idx >= 0 ? mStats.getLong(mPssTable[idx], PSS_SAMPLE_COUNT) : 0;
}
long getPssMinimum(int state) {
int idx = binarySearch(mPssTable, mPssTableSize, state);
- return idx >= 0 ? mProcessStats.getLong(mPssTable[idx], PSS_MINIMUM) : 0;
+ return idx >= 0 ? mStats.getLong(mPssTable[idx], PSS_MINIMUM) : 0;
}
long getPssAverage(int state) {
int idx = binarySearch(mPssTable, mPssTableSize, state);
- return idx >= 0 ? mProcessStats.getLong(mPssTable[idx], PSS_AVERAGE) : 0;
+ return idx >= 0 ? mStats.getLong(mPssTable[idx], PSS_AVERAGE) : 0;
}
long getPssMaximum(int state) {
int idx = binarySearch(mPssTable, mPssTableSize, state);
- return idx >= 0 ? mProcessStats.getLong(mPssTable[idx], PSS_MAXIMUM) : 0;
+ return idx >= 0 ? mStats.getLong(mPssTable[idx], PSS_MAXIMUM) : 0;
}
long getPssUssMinimum(int state) {
int idx = binarySearch(mPssTable, mPssTableSize, state);
- return idx >= 0 ? mProcessStats.getLong(mPssTable[idx], PSS_USS_MINIMUM) : 0;
+ return idx >= 0 ? mStats.getLong(mPssTable[idx], PSS_USS_MINIMUM) : 0;
}
long getPssUssAverage(int state) {
int idx = binarySearch(mPssTable, mPssTableSize, state);
- return idx >= 0 ? mProcessStats.getLong(mPssTable[idx], PSS_USS_AVERAGE) : 0;
+ return idx >= 0 ? mStats.getLong(mPssTable[idx], PSS_USS_AVERAGE) : 0;
}
long getPssUssMaximum(int state) {
int idx = binarySearch(mPssTable, mPssTableSize, state);
- return idx >= 0 ? mProcessStats.getLong(mPssTable[idx], PSS_USS_MAXIMUM) : 0;
+ return idx >= 0 ? mStats.getLong(mPssTable[idx], PSS_USS_MAXIMUM) : 0;
}
}
public static final class ServiceState {
- final ProcessStats mProcessStats;
+ final ProcessStats mStats;
final String mPackage;
ProcessState mProc;
@@ -2234,7 +2265,7 @@
long mExecStartTime;
public ServiceState(ProcessStats processStats, String pkg, ProcessState proc) {
- mProcessStats = processStats;
+ mStats = processStats;
mPackage = pkg;
mProc = proc;
}
@@ -2266,18 +2297,6 @@
}
void writeToParcel(Parcel out, long now) {
- if (mStartedState != STATE_NOTHING) {
- addStateTime(SERVICE_STARTED, mStartedState, now - mStartedStartTime);
- mStartedStartTime = now;
- }
- if (mBoundState != STATE_NOTHING) {
- addStateTime(SERVICE_BOUND, mBoundState, now - mBoundStartTime);
- mBoundStartTime = now;
- }
- if (mExecState != STATE_NOTHING) {
- addStateTime(SERVICE_EXEC, mExecState, now - mExecStartTime);
- mExecStartTime = now;
- }
out.writeInt(mDurationsTableSize);
for (int i=0; i<mDurationsTableSize; i++) {
if (DEBUG) Slog.i(TAG, "Writing service in " + mPackage + " dur #" + i + ": "
@@ -2291,7 +2310,7 @@
boolean readFromParcel(Parcel in) {
if (DEBUG) Slog.d(TAG, "Reading durations table...");
- mDurationsTable = mProcessStats.readTableFromParcel(in, mPackage, "service");
+ mDurationsTable = mStats.readTableFromParcel(in, mPackage, "service");
if (mDurationsTable == BAD_TABLE) {
return false;
}
@@ -2310,17 +2329,32 @@
if (idx >= 0) {
off = mDurationsTable[idx];
} else {
- mProcessStats.mAddLongTable = mDurationsTable;
- mProcessStats.mAddLongTableSize = mDurationsTableSize;
- off = mProcessStats.addLongData(~idx, state, 1);
- mDurationsTable = mProcessStats.mAddLongTable;
- mDurationsTableSize = mProcessStats.mAddLongTableSize;
+ mStats.mAddLongTable = mDurationsTable;
+ mStats.mAddLongTableSize = mDurationsTableSize;
+ off = mStats.addLongData(~idx, state, 1);
+ mDurationsTable = mStats.mAddLongTable;
+ mDurationsTableSize = mStats.mAddLongTableSize;
}
- long[] longs = mProcessStats.mLongs.get((off>>OFFSET_ARRAY_SHIFT)&OFFSET_ARRAY_MASK);
+ long[] longs = mStats.mLongs.get((off>>OFFSET_ARRAY_SHIFT)&OFFSET_ARRAY_MASK);
longs[(off>>OFFSET_INDEX_SHIFT)&OFFSET_INDEX_MASK] += time;
}
}
+ void commitStateTime(long now) {
+ if (mStartedState != STATE_NOTHING) {
+ addStateTime(SERVICE_STARTED, mStartedState, now - mStartedStartTime);
+ mStartedStartTime = now;
+ }
+ if (mBoundState != STATE_NOTHING) {
+ addStateTime(SERVICE_BOUND, mBoundState, now - mBoundStartTime);
+ mBoundStartTime = now;
+ }
+ if (mExecState != STATE_NOTHING) {
+ addStateTime(SERVICE_EXEC, mExecState, now - mExecStartTime);
+ mExecStartTime = now;
+ }
+ }
+
public void setStarted(boolean started, int memFactor, long now) {
if (mActive <= 0) {
throw new IllegalStateException("Service " + this + " has mActive=" + mActive);
@@ -2377,25 +2411,11 @@
}
}
- long getStartDuration(int opType, int memFactor, long now) {
- switch (opType) {
- case SERVICE_STARTED:
- return getDuration(opType, mStartedState, mStartedStartTime, memFactor, now);
- case SERVICE_BOUND:
- return getDuration(opType, mBoundState, mBoundStartTime, memFactor, now);
- case SERVICE_EXEC:
- return getDuration(opType, mExecState, mExecStartTime, memFactor, now);
- default:
- throw new IllegalArgumentException("Bad opType: " + opType);
- }
- }
-
-
private long getDuration(int opType, int curState, long startTime, int memFactor,
long now) {
int state = opType + (memFactor*SERVICE_COUNT);
int idx = binarySearch(mDurationsTable, mDurationsTableSize, state);
- long time = idx >= 0 ? mProcessStats.getLong(mDurationsTable[idx], 0) : 0;
+ long time = idx >= 0 ? mStats.getLong(mDurationsTable[idx], 0) : 0;
if (curState == memFactor) {
time += now - startTime;
}
@@ -2415,21 +2435,21 @@
}
}
- static final class ProcessDataCollection {
+ public static final class ProcessDataCollection {
final int[] screenStates;
final int[] memStates;
final int[] procStates;
- long totalTime;
- long numPss;
- long minPss;
- long avgPss;
- long maxPss;
- long minUss;
- long avgUss;
- long maxUss;
+ public long totalTime;
+ public long numPss;
+ public long minPss;
+ public long avgPss;
+ public long maxPss;
+ public long minUss;
+ public long avgUss;
+ public long maxUss;
- ProcessDataCollection(int[] _screenStates, int[] _memStates, int[] _procStates) {
+ public ProcessDataCollection(int[] _screenStates, int[] _memStates, int[] _procStates) {
screenStates = _screenStates;
memStates = _memStates;
procStates = _procStates;
diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp
index 7e70c7c..6d23c32 100644
--- a/core/jni/android_net_NetUtils.cpp
+++ b/core/jni/android_net_NetUtils.cpp
@@ -141,7 +141,7 @@
dns, server, &lease, vendorInfo, domains, mtu);
}
if (result != 0) {
- ALOGD("dhcp_do_request failed");
+ ALOGD("dhcp_do_request failed : %s (%s)", nameStr, renew ? "renew" : "new");
}
env->ReleaseStringUTFChars(ifname, nameStr);
diff --git a/core/jni/android_net_wifi_Wifi.cpp b/core/jni/android_net_wifi_Wifi.cpp
index 08962e2..aa6dbf3 100644
--- a/core/jni/android_net_wifi_Wifi.cpp
+++ b/core/jni/android_net_wifi_Wifi.cpp
@@ -33,11 +33,11 @@
static jint DBG = false;
-static int doCommand(const char *ifname, char *cmd, char *replybuf, int replybuflen)
+static int doCommand(char *cmd, char *replybuf, int replybuflen)
{
size_t reply_len = replybuflen - 1;
- if (::wifi_command(ifname, cmd, BUF_SIZE, replybuf, &reply_len) != 0)
+ if (::wifi_command(cmd, replybuf, &reply_len) != 0)
return -1;
else {
// Strip off trailing newline
@@ -49,7 +49,7 @@
}
}
-static jint doIntCommand(const char *ifname, const char* fmt, ...)
+static jint doIntCommand(const char* fmt, ...)
{
char buf[BUF_SIZE];
va_list args;
@@ -60,13 +60,13 @@
return -1;
}
char reply[BUF_SIZE];
- if (doCommand(ifname, buf, reply, sizeof(reply)) != 0) {
+ if (doCommand(buf, reply, sizeof(reply)) != 0) {
return -1;
}
return static_cast<jint>(atoi(reply));
}
-static jboolean doBooleanCommand(const char *ifname, const char* expect, const char* fmt, ...)
+static jboolean doBooleanCommand(const char* expect, const char* fmt, ...)
{
char buf[BUF_SIZE];
va_list args;
@@ -77,14 +77,14 @@
return JNI_FALSE;
}
char reply[BUF_SIZE];
- if (doCommand(ifname, buf, reply, sizeof(reply)) != 0) {
+ if (doCommand(buf, reply, sizeof(reply)) != 0) {
return JNI_FALSE;
}
return (strcmp(reply, expect) == 0);
}
// Send a command to the supplicant, and return the reply as a String
-static jstring doStringCommand(JNIEnv* env, const char *ifname, const char* fmt, ...) {
+static jstring doStringCommand(JNIEnv* env, const char* fmt, ...) {
char buf[BUF_SIZE];
va_list args;
va_start(args, fmt);
@@ -94,7 +94,7 @@
return NULL;
}
char reply[4096];
- if (doCommand(ifname, buf, reply, sizeof(reply)) != 0) {
+ if (doCommand(buf, reply, sizeof(reply)) != 0) {
return NULL;
}
// TODO: why not just NewStringUTF?
@@ -127,23 +127,20 @@
return (jboolean)(::wifi_stop_supplicant(p2pSupported) == 0);
}
-static jboolean android_net_wifi_connectToSupplicant(JNIEnv* env, jobject, jstring jIface)
+static jboolean android_net_wifi_connectToSupplicant(JNIEnv* env, jobject)
{
- ScopedUtfChars ifname(env, jIface);
- return (jboolean)(::wifi_connect_to_supplicant(ifname.c_str()) == 0);
+ return (jboolean)(::wifi_connect_to_supplicant() == 0);
}
-static void android_net_wifi_closeSupplicantConnection(JNIEnv* env, jobject, jstring jIface)
+static void android_net_wifi_closeSupplicantConnection(JNIEnv* env, jobject)
{
- ScopedUtfChars ifname(env, jIface);
- ::wifi_close_supplicant_connection(ifname.c_str());
+ ::wifi_close_supplicant_connection();
}
-static jstring android_net_wifi_waitForEvent(JNIEnv* env, jobject, jstring jIface)
+static jstring android_net_wifi_waitForEvent(JNIEnv* env, jobject)
{
char buf[EVENT_BUF_SIZE];
- ScopedUtfChars ifname(env, jIface);
- int nread = ::wifi_wait_for_event(ifname.c_str(), buf, sizeof buf);
+ int nread = ::wifi_wait_for_event(buf, sizeof buf);
if (nread > 0) {
return env->NewStringUTF(buf);
} else {
@@ -151,43 +148,36 @@
}
}
-static jboolean android_net_wifi_doBooleanCommand(JNIEnv* env, jobject, jstring jIface,
- jstring jCommand)
+static jboolean android_net_wifi_doBooleanCommand(JNIEnv* env, jobject, jstring jCommand)
{
- ScopedUtfChars ifname(env, jIface);
ScopedUtfChars command(env, jCommand);
if (command.c_str() == NULL) {
return JNI_FALSE;
}
if (DBG) ALOGD("doBoolean: %s", command.c_str());
- return doBooleanCommand(ifname.c_str(), "OK", "%s", command.c_str());
+ return doBooleanCommand("OK", "%s", command.c_str());
}
-static jint android_net_wifi_doIntCommand(JNIEnv* env, jobject, jstring jIface,
- jstring jCommand)
+static jint android_net_wifi_doIntCommand(JNIEnv* env, jobject, jstring jCommand)
{
- ScopedUtfChars ifname(env, jIface);
ScopedUtfChars command(env, jCommand);
if (command.c_str() == NULL) {
return -1;
}
if (DBG) ALOGD("doInt: %s", command.c_str());
- return doIntCommand(ifname.c_str(), "%s", command.c_str());
+ return doIntCommand("%s", command.c_str());
}
-static jstring android_net_wifi_doStringCommand(JNIEnv* env, jobject, jstring jIface,
- jstring jCommand)
+static jstring android_net_wifi_doStringCommand(JNIEnv* env, jobject, jstring jCommand)
{
- ScopedUtfChars ifname(env, jIface);
-
ScopedUtfChars command(env, jCommand);
if (command.c_str() == NULL) {
return NULL;
}
if (DBG) ALOGD("doString: %s", command.c_str());
- return doStringCommand(env, ifname.c_str(), "%s", command.c_str());
+ return doStringCommand(env, "%s", command.c_str());
}
@@ -205,17 +195,13 @@
{ "unloadDriver", "()Z", (void *)android_net_wifi_unloadDriver },
{ "startSupplicant", "(Z)Z", (void *)android_net_wifi_startSupplicant },
{ "killSupplicant", "(Z)Z", (void *)android_net_wifi_killSupplicant },
- { "connectToSupplicant", "(Ljava/lang/String;)Z",
- (void *)android_net_wifi_connectToSupplicant },
- { "closeSupplicantConnection", "(Ljava/lang/String;)V",
+ { "connectToSupplicantNative", "()Z", (void *)android_net_wifi_connectToSupplicant },
+ { "closeSupplicantConnectionNative", "()V",
(void *)android_net_wifi_closeSupplicantConnection },
- { "waitForEvent", "(Ljava/lang/String;)Ljava/lang/String;",
- (void*) android_net_wifi_waitForEvent },
- { "doBooleanCommand", "(Ljava/lang/String;Ljava/lang/String;)Z",
- (void*) android_net_wifi_doBooleanCommand },
- { "doIntCommand", "(Ljava/lang/String;Ljava/lang/String;)I",
- (void*) android_net_wifi_doIntCommand },
- { "doStringCommand", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;",
+ { "waitForEventNative", "()Ljava/lang/String;", (void*)android_net_wifi_waitForEvent },
+ { "doBooleanCommandNative", "(Ljava/lang/String;)Z", (void*)android_net_wifi_doBooleanCommand },
+ { "doIntCommandNative", "(Ljava/lang/String;)I", (void*)android_net_wifi_doIntCommand },
+ { "doStringCommandNative", "(Ljava/lang/String;)Ljava/lang/String;",
(void*) android_net_wifi_doStringCommand },
};
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index b9840e2..0908f36 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -26,7 +26,7 @@
<item><xliff:g id="id">ime</xliff:g></item>
<item><xliff:g id="id">sync_failing</xliff:g></item>
<item><xliff:g id="id">sync_active</xliff:g></item>
- <item><xliff:g id="id">gps</xliff:g></item>
+ <item><xliff:g id="id">location</xliff:g></item>
<item><xliff:g id="id">bluetooth</xliff:g></item>
<item><xliff:g id="id">nfc</xliff:g></item>
<item><xliff:g id="id">tty</xliff:g></item>
diff --git a/docs/html/guide/topics/providers/content-provider-creating.jd b/docs/html/guide/topics/providers/content-provider-creating.jd
index ebd7c25..6ec1e1b 100644
--- a/docs/html/guide/topics/providers/content-provider-creating.jd
+++ b/docs/html/guide/topics/providers/content-provider-creating.jd
@@ -680,7 +680,7 @@
* Notice that the database itself isn't created or opened
* until SQLiteOpenHelper.getWritableDatabase is called
*/
- mOpenHelper = new SQLiteOpenHelper(
+ mOpenHelper = new MainDatabaseHelper(
getContext(), // the application context
DBNAME, // the name of the database)
null, // uses the default SQLite cursor
diff --git a/docs/html/guide/topics/ui/notifiers/notifications.jd b/docs/html/guide/topics/ui/notifiers/notifications.jd
index e0c87d7..3b1292e 100644
--- a/docs/html/guide/topics/ui/notifiers/notifications.jd
+++ b/docs/html/guide/topics/ui/notifiers/notifications.jd
@@ -285,7 +285,7 @@
<p>
Starting an {@link android.app.Activity} when the user clicks the notification is the most
common action scenario. You can also start an {@link android.app.Activity} when the user
- dismisses an {@link android.app.Activity}. In Android 4.1 and later, you can start an
+ dismisses a notification. In Android 4.1 and later, you can start an
{@link android.app.Activity} from an action button. To learn more, read the reference guide for
{@link android.support.v4.app.NotificationCompat.Builder}.
</p>
diff --git a/location/java/android/location/FusedBatchOptions.aidl b/location/java/android/location/FusedBatchOptions.aidl
new file mode 100644
index 0000000..94cb6e1
--- /dev/null
+++ b/location/java/android/location/FusedBatchOptions.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2013, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.location;
+
+parcelable FusedBatchOptions;
\ No newline at end of file
diff --git a/location/java/android/location/FusedBatchOptions.java b/location/java/android/location/FusedBatchOptions.java
new file mode 100644
index 0000000..623d707
--- /dev/null
+++ b/location/java/android/location/FusedBatchOptions.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.location;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * A data class representing a set of options to configure batching sessions.
+ * @hide
+ */
+public class FusedBatchOptions implements Parcelable {
+ private volatile long mPeriodInNS = 0;
+ private volatile int mSourcesToUse = 0;
+ private volatile int mFlags = 0;
+
+ // the default value is set to request fixes at no cost
+ private volatile double mMaxPowerAllocationInMW = 0;
+
+ /*
+ * Getters and setters for properties needed to hold the options.
+ */
+ public void setMaxPowerAllocationInMW(double value) {
+ mMaxPowerAllocationInMW = value;
+ }
+
+ public double getMaxPowerAllocationInMW() {
+ return mMaxPowerAllocationInMW;
+ }
+
+ public void setPeriodInNS(long value) {
+ mPeriodInNS = value;
+ }
+
+ public long getPeriodInNS() {
+ return mPeriodInNS;
+ }
+
+ public void setSourceToUse(int source) {
+ mSourcesToUse |= source;
+ }
+
+ public void resetSourceToUse(int source) {
+ mSourcesToUse &= ~source;
+ }
+
+ public boolean isSourceToUseSet(int source) {
+ return (mSourcesToUse & source) != 0;
+ }
+
+ public int getSourcesToUse() {
+ return mSourcesToUse;
+ }
+
+ public void setFlag(int flag) {
+ mFlags |= flag;
+ }
+
+ public void resetFlag(int flag) {
+ mFlags &= ~flag;
+ }
+
+ public boolean isFlagSet(int flag) {
+ return (mFlags & flag) != 0;
+ }
+
+ public int getFlags() {
+ return mFlags;
+ }
+
+ /**
+ * Definition of enum flag sets needed by this class.
+ * Such values need to be kept in sync with the ones in fused_location.h
+ */
+ public static final class SourceTechnologies {
+ public static int GNSS = 1<<0;
+ public static int WIFI = 1<<1;
+ public static int SENSORS = 1<<2;
+ public static int CELL = 1<<3;
+ public static int BLUETOOTH = 1<<4;
+ }
+
+ public static final class BatchFlags {
+ public static int WAKEUP_ON_FIFO_FULL = 1<<0;
+ public static int CALLBACK_ON_LOCATION_FIX = 1<<1;
+ }
+
+ /*
+ * Method definitions to support Parcelable operations.
+ */
+ public static final Parcelable.Creator<FusedBatchOptions> CREATOR =
+ new Parcelable.Creator<FusedBatchOptions>() {
+ @Override
+ public FusedBatchOptions createFromParcel(Parcel parcel) {
+ FusedBatchOptions options = new FusedBatchOptions();
+ options.setMaxPowerAllocationInMW(parcel.readDouble());
+ options.setPeriodInNS(parcel.readLong());
+ options.setSourceToUse(parcel.readInt());
+ options.setFlag(parcel.readInt());
+ return options;
+ }
+
+ @Override
+ public FusedBatchOptions[] newArray(int size) {
+ return new FusedBatchOptions[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel parcel, int flags) {
+ parcel.writeDouble(mMaxPowerAllocationInMW);
+ parcel.writeLong(mPeriodInNS);
+ parcel.writeInt(mSourcesToUse);
+ parcel.writeInt(mFlags);
+ }
+}
diff --git a/location/java/android/location/IFusedGeofenceHardware.aidl b/location/java/android/location/IFusedGeofenceHardware.aidl
new file mode 100644
index 0000000..9dbf1f4
--- /dev/null
+++ b/location/java/android/location/IFusedGeofenceHardware.aidl
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2013, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/license/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.location;
+
+import android.location.Geofence;
+
+/**
+ * Fused Geofence Hardware interface.
+ *
+ * <p>This interface is the basic set of supported functionality by Fused Hardware modules that offer
+ * Geofencing capabilities.
+ *
+ * All operations are asynchronous and the status codes can be obtained via a set of callbacks.
+ *
+ * @hide
+ */
+interface IFusedGeofenceHardware {
+ /**
+ * Flags if the interface functionality is supported by the platform.
+ *
+ * @return true if the functionality is supported, false otherwise.
+ */
+ boolean isSupported();
+
+ /**
+ * Adds a given list of geofences to the system.
+ *
+ * @param geofenceIdsArray The list of geofence Ids to add.
+ * @param geofencesArray the list of geofences to add.
+ */
+ // TODO: [GeofenceIntegration] GeofenceHardwareRequest is not a parcelable class exposed in aidl
+ void addGeofences(in int[] geofenceIdsArray, in Geofence[] geofencesArray);
+
+ /**
+ * Removes a give list of geofences from the system.
+ *
+ * @param geofences The list of geofences to remove.
+ */
+ void removeGeofences(in int[] geofenceIds);
+
+ /**
+ * Pauses monitoring a particular geofence.
+ *
+ * @param geofenceId The geofence to pause monitoring.
+ */
+ void pauseMonitoringGeofence(in int geofenceId);
+
+ /**
+ * Resumes monitoring a particular geofence.
+ *
+ * @param geofenceid The geofence to resume monitoring.
+ * @param transitionsToMonitor The transitions to monitor upon resume.
+ *
+ * Remarks: keep naming of geofence request options consistent with the naming used in
+ * GeofenceHardwareRequest
+ */
+ void resumeMonitoringGeofence(in int geofenceId, in int monitorTransitions);
+
+ /**
+ * Modifies the request options if a geofence that is already known by the
+ * system.
+ *
+ * @param geofenceId The geofence to modify.
+ * @param lastTransition The last known transition state of
+ * the geofence.
+ * @param monitorTransitions The set of transitions to monitor.
+ * @param notificationResponsiveness The notification responsivness needed.
+ * @param unknownTimer The time span associated with the
+ *
+ * Remarks: keep the options as separate fields to be able to leverage the class
+ * GeofenceHardwareRequest without any changes
+ */
+ void modifyGeofenceOptions(
+ in int geofenceId,
+ in int lastTransition,
+ in int monitorTransitions,
+ in int notificationResponsiveness,
+ in int unknownTimer);
+}
diff --git a/location/java/android/location/IFusedProvider.aidl b/location/java/android/location/IFusedProvider.aidl
new file mode 100644
index 0000000..8870d2a
--- /dev/null
+++ b/location/java/android/location/IFusedProvider.aidl
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.location;
+
+import android.hardware.location.IFusedLocationHardware;
+
+/**
+ * Interface definition for Location providers that require FLP services.
+ * @hide
+ */
+interface IFusedProvider {
+ /**
+ * Provides access to a FusedLocationHardware instance needed for the provider to work.
+ *
+ * @param instance The FusedLocationHardware available for the provider to use.
+ */
+ void onFusedLocationHardwareChange(in IFusedLocationHardware instance);
+}
\ No newline at end of file
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 989178a..e5f1cf5 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -177,6 +177,17 @@
*/
public static final String EXTRA_GPS_ENABLED = "enabled";
+ /**
+ * Broadcast intent action indicating that a high power location requests
+ * has either started or stopped being active. The current state of
+ * active location requests should be read from AppOpsManager using
+ * {@code OP_MONITOR_HIGH_POWER_LOCATION}.
+ *
+ * @hide
+ */
+ public static final String HIGH_POWER_REQUEST_CHANGE_ACTION =
+ "android.location.HIGH_POWER_REQUEST_CHANGE";
+
// Map from LocationListeners to their associated ListenerTransport objects
private HashMap<LocationListener,ListenerTransport> mListeners =
new HashMap<LocationListener,ListenerTransport>();
diff --git a/location/lib/java/com/android/location/provider/FusedLocationHardware.java b/location/lib/java/com/android/location/provider/FusedLocationHardware.java
new file mode 100644
index 0000000..abea9fb
--- /dev/null
+++ b/location/lib/java/com/android/location/provider/FusedLocationHardware.java
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIOS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.location.provider;
+
+import android.hardware.location.IFusedLocationHardware;
+import android.hardware.location.IFusedLocationHardwareSink;
+
+import android.location.Location;
+
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.util.ArrayList;
+
+/**
+ * Class that exposes IFusedLocationHardware functionality to unbundled services.
+ * Namely this is used by GmsCore Fused Location Provider.
+ */
+public final class FusedLocationHardware {
+ private final String TAG = "FusedLocationHardware";
+
+ private IFusedLocationHardware mLocationHardware;
+ ArrayList<FusedLocationHardwareSink> mSinkList = new ArrayList<FusedLocationHardwareSink>();
+
+ private IFusedLocationHardwareSink mInternalSink = new IFusedLocationHardwareSink.Stub() {
+ @Override
+ public void onLocationAvailable(Location[] locations) {
+ dispatchLocations(locations);
+ }
+
+ @Override
+ public void onDiagnosticDataAvailable(String data) {
+ dispatchDiagnosticData(data);
+ }
+ };
+
+ public FusedLocationHardware(IFusedLocationHardware locationHardware) {
+ mLocationHardware = locationHardware;
+ }
+
+ /*
+ * Methods to provide a Facade for IFusedLocationHardware
+ */
+ public void registerSink(FusedLocationHardwareSink sink) {
+ if(sink == null) {
+ return;
+ }
+
+ boolean registerSink = false;
+ synchronized (mSinkList) {
+ // register only on first insertion
+ registerSink = mSinkList.size() == 0;
+ // guarantee uniqueness
+ if(!mSinkList.contains(sink)) {
+ mSinkList.add(sink);
+ }
+ }
+
+ if(registerSink) {
+ try {
+ mLocationHardware.registerSink(mInternalSink);
+ } catch(RemoteException e) {
+ Log.e(TAG, "RemoteException at registerSink");
+ }
+ }
+ }
+
+ public void unregisterSink(FusedLocationHardwareSink sink) {
+ if(sink == null) {
+ return;
+ }
+
+ boolean unregisterSink = false;
+ synchronized(mSinkList) {
+ mSinkList.remove(sink);
+ // unregister after the last sink
+ unregisterSink = mSinkList.size() == 0;
+ }
+
+ if(unregisterSink) {
+ try {
+ mLocationHardware.unregisterSink(mInternalSink);
+ } catch(RemoteException e) {
+ Log.e(TAG, "RemoteException at unregisterSink");
+ }
+ }
+ }
+
+ public int getSupportedBatchSize() {
+ try {
+ return mLocationHardware.getSupportedBatchSize();
+ } catch(RemoteException e) {
+ Log.e(TAG, "RemoteException at getSupportedBatchSize");
+ return 0;
+ }
+ }
+
+ public void startBatching(int id, GmsFusedBatchOptions batchOptions) {
+ try {
+ mLocationHardware.startBatching(id, batchOptions.getParcelableOptions());
+ } catch(RemoteException e) {
+ Log.e(TAG, "RemoteException at startBatching");
+ }
+ }
+
+ public void stopBatching(int id) {
+ try {
+ mLocationHardware.stopBatching(id);
+ } catch(RemoteException e) {
+ Log.e(TAG, "RemoteException at stopBatching");
+ }
+ }
+
+ public void updateBatchingOptions(int id, GmsFusedBatchOptions batchOptions) {
+ try {
+ mLocationHardware.updateBatchingOptions(id, batchOptions.getParcelableOptions());
+ } catch(RemoteException e) {
+ Log.e(TAG, "RemoteException at updateBatchingOptions");
+ }
+ }
+
+ public void requestBatchOfLocations(int batchSizeRequest) {
+ try {
+ mLocationHardware.requestBatchOfLocations(batchSizeRequest);
+ } catch(RemoteException e) {
+ Log.e(TAG, "RemoteException at requestBatchOfLocations");
+ }
+ }
+
+ public boolean supportsDiagnosticDataInjection() {
+ try {
+ return mLocationHardware.supportsDiagnosticDataInjection();
+ } catch(RemoteException e) {
+ Log.e(TAG, "RemoteException at supportsDiagnisticDataInjection");
+ return false;
+ }
+ }
+
+ public void injectDiagnosticData(String data) {
+ try {
+ mLocationHardware.injectDiagnosticData(data);
+ } catch(RemoteException e) {
+ Log.e(TAG, "RemoteException at injectDiagnosticData");
+ }
+ }
+
+ public boolean supportsDeviceContextInjection() {
+ try {
+ return mLocationHardware.supportsDeviceContextInjection();
+ } catch(RemoteException e) {
+ Log.e(TAG, "RemoteException at supportsDeviceContextInjection");
+ return false;
+ }
+ }
+
+ public void injectDeviceContext(int deviceEnabledContext) {
+ try {
+ mLocationHardware.injectDeviceContext(deviceEnabledContext);
+ } catch(RemoteException e) {
+ Log.e(TAG, "RemoteException at injectDeviceContext");
+ }
+ }
+
+ /*
+ * Helper methods
+ */
+ private void dispatchLocations(Location[] locations) {
+ ArrayList<FusedLocationHardwareSink> sinks = null;
+ synchronized (mSinkList) {
+ sinks = new ArrayList<FusedLocationHardwareSink>(mSinkList);
+ }
+
+ for(FusedLocationHardwareSink sink : sinks) {
+ sink.onLocationAvailable(locations);
+ }
+ }
+
+ private void dispatchDiagnosticData(String data) {
+ ArrayList<FusedLocationHardwareSink> sinks = null;
+ synchronized(mSinkList) {
+ sinks = new ArrayList<FusedLocationHardwareSink>(mSinkList);
+ }
+
+ for(FusedLocationHardwareSink sink : sinks) {
+ sink.onDiagnosticDataAvailable(data);
+ }
+ }
+}
diff --git a/location/lib/java/com/android/location/provider/FusedLocationHardwareSink.java b/location/lib/java/com/android/location/provider/FusedLocationHardwareSink.java
new file mode 100644
index 0000000..118b663
--- /dev/null
+++ b/location/lib/java/com/android/location/provider/FusedLocationHardwareSink.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.location.provider;
+
+import android.location.Location;
+
+/**
+ * Base class for sinks to interact with FusedLocationHardware.
+ * This is mainly used by GmsCore Fused Provider.
+ */
+public abstract class FusedLocationHardwareSink {
+ /*
+ * Methods to provide a facade for IFusedLocationHardware
+ */
+ public abstract void onLocationAvailable(Location[] locations);
+ public abstract void onDiagnosticDataAvailable(String data);
+}
\ No newline at end of file
diff --git a/location/lib/java/com/android/location/provider/FusedProvider.java b/location/lib/java/com/android/location/provider/FusedProvider.java
new file mode 100644
index 0000000..bc9feef
--- /dev/null
+++ b/location/lib/java/com/android/location/provider/FusedProvider.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.location.provider;
+
+import android.hardware.location.IFusedLocationHardware;
+import android.location.IFusedProvider;
+import android.os.IBinder;
+
+/**
+ * Base class for Fused providers implemented as unbundled services.
+ *
+ * <p>Fused providers can be implemented as services and return the result of
+ * {@link com.android.location.provider.FusedProvider#getBinder()} in its getBinder() method.
+ *
+ * <p>IMPORTANT: This class is effectively a public API for unbundled applications, and must remain
+ * API stable. See README.txt in the root of this package for more information.
+ *
+ * @hide
+ */
+public abstract class FusedProvider {
+ private IFusedProvider.Stub mProvider = new IFusedProvider.Stub() {
+ @Override
+ public void onFusedLocationHardwareChange(IFusedLocationHardware instance) {
+ setFusedLocationHardware(new FusedLocationHardware(instance));
+ }
+ };
+
+ /**
+ * Gets the Binder associated with the provider.
+ * This is intended to be used for the onBind() method of a service that implements a fused
+ * service.
+ *
+ * @return The IBinder instance associated with the provider.
+ */
+ public IBinder getBinder() {
+ return mProvider;
+ }
+
+ /**
+ * Sets the FusedLocationHardware instance in the provider..
+ * @param value The instance to set. This can be null in cases where the service connection
+ * is disconnected.
+ */
+ public abstract void setFusedLocationHardware(FusedLocationHardware value);
+}
diff --git a/location/lib/java/com/android/location/provider/GmsFusedBatchOptions.java b/location/lib/java/com/android/location/provider/GmsFusedBatchOptions.java
new file mode 100644
index 0000000..fd3f402
--- /dev/null
+++ b/location/lib/java/com/android/location/provider/GmsFusedBatchOptions.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.location.provider;
+
+import android.location.FusedBatchOptions;
+
+/**
+ * Class that exposes FusedBatchOptions to the GmsCore .
+ */
+public class GmsFusedBatchOptions {
+ private FusedBatchOptions mOptions = new FusedBatchOptions();
+
+ /*
+ * Methods that provide a facade for properties in FusedBatchOptions.
+ */
+ public void setMaxPowerAllocationInMW(double value) {
+ mOptions.setMaxPowerAllocationInMW(value);
+ }
+
+ public double getMaxPowerAllocationInMW() {
+ return mOptions.getMaxPowerAllocationInMW();
+ }
+
+ public void setPeriodInNS(long value) {
+ mOptions.setPeriodInNS(value);
+ }
+
+ public long getPeriodInNS() {
+ return mOptions.getPeriodInNS();
+ }
+
+ public void setSourceToUse(int source) {
+ mOptions.setSourceToUse(source);
+ }
+
+ public void resetSourceToUse(int source) {
+ mOptions.resetSourceToUse(source);
+ }
+
+ public boolean isSourceToUseSet(int source) {
+ return mOptions.isSourceToUseSet(source);
+ }
+
+ public int getSourcesToUse() {
+ return mOptions.getSourcesToUse();
+ }
+
+ public void setFlag(int flag) {
+ mOptions.setFlag(flag);
+ }
+
+ public void resetFlag(int flag) {
+ mOptions.resetFlag(flag);
+ }
+
+ public boolean isFlagSet(int flag) {
+ return mOptions.isFlagSet(flag);
+ }
+
+ public int getFlags() {
+ return mOptions.getFlags();
+ }
+
+ /**
+ * Definition of enum flag sets needed by this class.
+ * Such values need to be kept in sync with the ones in fused_location.h
+ */
+
+ public static final class SourceTechnologies {
+ public static int GNSS = 1<<0;
+ public static int WIFI = 1<<1;
+ public static int SENSORS = 1<<2;
+ public static int CELL = 1<<3;
+ public static int BLUETOOTH = 1<<4;
+ }
+
+ public static final class BatchFlags {
+ public static int WAKEUP_ON_FIFO_FULL = 1<<0;
+ public static int CALLBACK_ON_LOCATION_FIX = 1<<1;
+ }
+
+ /*
+ * Method definitions for internal use.
+ */
+
+ /*
+ * @hide
+ */
+ public FusedBatchOptions getParcelableOptions() {
+ return mOptions;
+ }
+}
diff --git a/media/java/android/mtp/MtpDatabase.java b/media/java/android/mtp/MtpDatabase.java
old mode 100644
new mode 100755
index 632334b..cf1238a
--- a/media/java/android/mtp/MtpDatabase.java
+++ b/media/java/android/mtp/MtpDatabase.java
@@ -221,7 +221,7 @@
if (c != null) c.close();
if (db != null) db.close();
}
- databaseFile.delete();
+ context.deleteDatabase(devicePropertiesName);
}
}
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 2267372..5e198a2 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -24,6 +24,7 @@
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.CONFIGURE_WIFI_DISPLAY" />
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
+ <uses-permission android:name="android.permission.GET_APP_OPS_STATS" />
<!-- Networking and telephony -->
<uses-permission android:name="android.permission.BLUETOOTH" />
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_device_access_location_found.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_device_access_location_found.png
new file mode 100644
index 0000000..657a612
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_device_access_location_found.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_device_access_location_found.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_device_access_location_found.png
new file mode 100644
index 0000000..80fc24b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_device_access_location_found.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/stat_sys_device_access_location_found.png b/packages/SystemUI/res/drawable-xhdpi/stat_sys_device_access_location_found.png
new file mode 100644
index 0000000..fd8ad64
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/stat_sys_device_access_location_found.png
Binary files differ
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 0073e60..33a85c3a 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -418,6 +418,9 @@
<!-- Notification text: when GPS has found a fix [CHAR LIMIT=50] -->
<string name="gps_notification_found_text">Location set by GPS</string>
+ <!-- Accessibility text describing the presence of active location requests by one or more apps -->
+ <string name="accessibility_location_active">Location requests active</string>
+
<!-- Content description of the clear button in the notification panel for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_clear_all">Clear all notifications.</string>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java
index 3f8043d..91ddf0f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/LocationController.java
@@ -16,10 +16,8 @@
package com.android.systemui.statusbar.policy;
-import android.app.INotificationManager;
-import android.app.Notification;
-import android.app.NotificationManager;
-import android.app.PendingIntent;
+import android.app.AppOpsManager;
+import android.app.StatusBarManager;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
@@ -28,36 +26,39 @@
import android.database.ContentObserver;
import android.location.LocationManager;
import android.os.Handler;
-import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
import com.android.systemui.R;
import java.util.ArrayList;
+import java.util.List;
+/**
+ * A controller to manage changes of location related states and update the views accordingly.
+ */
public class LocationController extends BroadcastReceiver {
- private static final String TAG = "StatusBar.LocationController";
+ // The name of the placeholder corresponding to the location request status icon.
+ // This string corresponds to config_statusBarIcons in core/res/res/values/config.xml.
+ private static final String LOCATION_STATUS_ICON_PLACEHOLDER = "location";
+ private static final int LOCATION_STATUS_ICON_ID
+ = R.drawable.stat_sys_device_access_location_found;
- private static final int GPS_NOTIFICATION_ID = 374203-122084;
+ private static final int[] mHighPowerRequestAppOpArray
+ = new int[] {AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION};
private Context mContext;
- private INotificationManager mNotificationService;
+ private AppOpsManager mAppOpsManager;
+ private StatusBarManager mStatusBarManager;
- private ArrayList<LocationGpsStateChangeCallback> mChangeCallbacks =
- new ArrayList<LocationGpsStateChangeCallback>();
+ private boolean mAreActiveLocationRequests;
+ private boolean mIsAirplaneMode;
+
private ArrayList<LocationSettingsChangeCallback> mSettingsChangeCallbacks =
new ArrayList<LocationSettingsChangeCallback>();
/**
- * A callback for change in gps status (enabled/disabled, have lock, etc).
- */
- public interface LocationGpsStateChangeCallback {
- public void onLocationGpsStateChanged(boolean inUse, String description);
- }
-
- /**
* A callback for change in location settings (the user has enabled/disabled location).
*/
public interface LocationSettingsChangeCallback {
@@ -74,13 +75,15 @@
mContext = context;
IntentFilter filter = new IntentFilter();
- filter.addAction(LocationManager.GPS_ENABLED_CHANGE_ACTION);
- filter.addAction(LocationManager.GPS_FIX_CHANGE_ACTION);
+ filter.addAction(LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION);
+ // Listen for a change in the airplane mode setting so we can defensively turn off the
+ // high power location icon when radios are disabled.
+ filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
context.registerReceiver(this, filter);
- NotificationManager nm = (NotificationManager)context.getSystemService(
- Context.NOTIFICATION_SERVICE);
- mNotificationService = nm.getService();
+ mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
+ mStatusBarManager
+ = (StatusBarManager) context.getSystemService(Context.STATUS_BAR_SERVICE);
// Register to listen for changes to the location settings
context.getContentResolver().registerContentObserver(
@@ -94,13 +97,11 @@
}
}
});
- }
- /**
- * Add a callback to listen for changes in gps status.
- */
- public void addStateChangedCallback(LocationGpsStateChangeCallback cb) {
- mChangeCallbacks.add(cb);
+ // Examine the current location state and initialize the status view.
+ updateActiveLocationRequests();
+ updateAirplaneMode();
+ refreshViews();
}
/**
@@ -145,76 +146,77 @@
return isGpsEnabled || isNetworkEnabled;
}
+ /**
+ * Returns true if there currently exist active high power location requests.
+ */
+ private boolean areActiveHighPowerLocationRequests() {
+ List<AppOpsManager.PackageOps> packages
+ = mAppOpsManager.getPackagesForOps(mHighPowerRequestAppOpArray);
+ // AppOpsManager can return null when there is no requested data.
+ if (packages != null) {
+ final int numPackages = packages.size();
+ for (int packageInd = 0; packageInd < numPackages; packageInd++) {
+ AppOpsManager.PackageOps packageOp = packages.get(packageInd);
+ List<AppOpsManager.OpEntry> opEntries = packageOp.getOps();
+ if (opEntries != null) {
+ final int numOps = opEntries.size();
+ for (int opInd = 0; opInd < numOps; opInd++) {
+ AppOpsManager.OpEntry opEntry = opEntries.get(opInd);
+ // AppOpsManager should only return OP_MONITOR_HIGH_POWER_LOCATION because
+ // of the mHighPowerRequestAppOpArray filter, but checking defensively.
+ if (opEntry.getOp() == AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION) {
+ if (opEntry.isRunning()) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+
+ // Updates the status view based on the current state of location requests and airplane mode.
+ private void refreshViews() {
+ // The airplane mode check is defensive - there shouldn't be any active high power
+ // location requests when airplane mode is on.
+ if (!mIsAirplaneMode && mAreActiveLocationRequests) {
+ mStatusBarManager.setIcon(LOCATION_STATUS_ICON_PLACEHOLDER, LOCATION_STATUS_ICON_ID, 0,
+ mContext.getString(R.string.accessibility_location_active));
+ } else {
+ mStatusBarManager.removeIcon(LOCATION_STATUS_ICON_PLACEHOLDER);
+ }
+ }
+
+ // Reads the active location requests and updates the status view if necessary.
+ private void updateActiveLocationRequests() {
+ boolean hadActiveLocationRequests = mAreActiveLocationRequests;
+ mAreActiveLocationRequests = areActiveHighPowerLocationRequests();
+ if (mAreActiveLocationRequests != hadActiveLocationRequests) {
+ refreshViews();
+ }
+ }
+
+ // Reads the airplane mode setting and updates the status view if necessary.
+ private void updateAirplaneMode() {
+ boolean wasAirplaneMode = mIsAirplaneMode;
+ // TODO This probably warrants a utility method in Settings.java.
+ mIsAirplaneMode = (Settings.Global.getInt(
+ mContext.getContentResolver(),
+ Settings.Global.AIRPLANE_MODE_ON, 0) == 1);
+ if (mIsAirplaneMode != wasAirplaneMode) {
+ refreshViews();
+ }
+ }
+
@Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
- final boolean enabled = intent.getBooleanExtra(LocationManager.EXTRA_GPS_ENABLED, false);
-
- boolean visible;
- int iconId, textResId;
-
- if (action.equals(LocationManager.GPS_FIX_CHANGE_ACTION) && enabled) {
- // GPS is getting fixes
- iconId = com.android.internal.R.drawable.stat_sys_gps_on;
- textResId = R.string.gps_notification_found_text;
- visible = true;
- } else if (action.equals(LocationManager.GPS_ENABLED_CHANGE_ACTION) && !enabled) {
- // GPS is off
- visible = false;
- iconId = textResId = 0;
- } else {
- // GPS is on, but not receiving fixes
- iconId = R.drawable.stat_sys_gps_acquiring_anim;
- textResId = R.string.gps_notification_searching_text;
- visible = true;
- }
-
- try {
- if (visible) {
- Intent gpsIntent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
- gpsIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-
- PendingIntent pendingIntent = PendingIntent.getActivityAsUser(context, 0,
- gpsIntent, 0, null, UserHandle.CURRENT);
- String text = mContext.getText(textResId).toString();
-
- Notification n = new Notification.Builder(mContext)
- .setSmallIcon(iconId)
- .setContentTitle(text)
- .setOngoing(true)
- .setContentIntent(pendingIntent)
- .getNotification();
-
- // Notification.Builder will helpfully fill these out for you no matter what you do
- n.tickerView = null;
- n.tickerText = null;
-
- n.priority = Notification.PRIORITY_HIGH;
-
- int[] idOut = new int[1];
- mNotificationService.enqueueNotificationWithTag(
- mContext.getPackageName(), mContext.getBasePackageName(),
- null,
- GPS_NOTIFICATION_ID,
- n,
- idOut,
- UserHandle.USER_ALL);
-
- for (LocationGpsStateChangeCallback cb : mChangeCallbacks) {
- cb.onLocationGpsStateChanged(true, text);
- }
- } else {
- mNotificationService.cancelNotificationWithTag(
- mContext.getPackageName(), null,
- GPS_NOTIFICATION_ID, UserHandle.USER_ALL);
-
- for (LocationGpsStateChangeCallback cb : mChangeCallbacks) {
- cb.onLocationGpsStateChanged(false, null);
- }
- }
- } catch (android.os.RemoteException ex) {
- // well, it was worth a shot
+ if (LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION.equals(action)) {
+ updateActiveLocationRequests();
+ } else if (Intent.ACTION_AIRPLANE_MODE_CHANGED.equals(action)) {
+ updateAirplaneMode();
}
}
}
-
diff --git a/services/java/com/android/server/AppOpsService.java b/services/java/com/android/server/AppOpsService.java
index 81572c5..7af95f3 100644
--- a/services/java/com/android/server/AppOpsService.java
+++ b/services/java/com/android/server/AppOpsService.java
@@ -426,12 +426,14 @@
HashMap<Callback, ArrayList<Pair<String, Integer>>> callbacks = null;
synchronized (this) {
boolean changed = false;
- for (int i=0; i<mUidOps.size(); i++) {
+ for (int i=mUidOps.size()-1; i>=0; i--) {
HashMap<String, Ops> packages = mUidOps.valueAt(i);
- for (Map.Entry<String, Ops> ent : packages.entrySet()) {
+ Iterator<Map.Entry<String, Ops>> it = packages.entrySet().iterator();
+ while (it.hasNext()) {
+ Map.Entry<String, Ops> ent = it.next();
String packageName = ent.getKey();
Ops pkgOps = ent.getValue();
- for (int j=0; j<pkgOps.size(); j++) {
+ for (int j=pkgOps.size()-1; j>=0; j--) {
Op curOp = pkgOps.valueAt(j);
if (curOp.mode != AppOpsManager.MODE_ALLOWED) {
curOp.mode = AppOpsManager.MODE_ALLOWED;
@@ -440,9 +442,17 @@
mOpModeWatchers.get(curOp.op));
callbacks = addCallbacks(callbacks, packageName, curOp.op,
mPackageModeWatchers.get(packageName));
- pruneOp(curOp, mUidOps.keyAt(i), packageName);
+ if (curOp.time == 0 && curOp.rejectTime == 0) {
+ pkgOps.removeAt(j);
+ }
}
}
+ if (pkgOps.size() == 0) {
+ it.remove();
+ }
+ }
+ if (packages.size() == 0) {
+ mUidOps.removeAt(i);
}
}
if (changed) {
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 3ae2eb5..1f71471 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -3916,11 +3916,26 @@
// hipri connection so the default connection stays active.
log("isMobileOk: start hipri url=" + params.mUrl);
mCs.setEnableFailFastMobileData(DctConstants.ENABLED);
- mCs.startUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE,
- Phone.FEATURE_ENABLE_HIPRI, new Binder());
// Continue trying to connect until time has run out
long endTime = SystemClock.elapsedRealtime() + params.mTimeOutMs;
+
+ // First wait until we can start using hipri
+ Binder binder = new Binder();
+ while(SystemClock.elapsedRealtime() < endTime) {
+ int ret = mCs.startUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE,
+ Phone.FEATURE_ENABLE_HIPRI, binder);
+ if ((ret == PhoneConstants.APN_ALREADY_ACTIVE)
+ || (ret == PhoneConstants.APN_REQUEST_STARTED)) {
+ log("isMobileOk: hipri started");
+ break;
+ }
+ if (VDBG) log("isMobileOk: hipri not started yet");
+ result = ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION;
+ sleep(1);
+ }
+
+ // Continue trying to connect until time has run out
while(SystemClock.elapsedRealtime() < endTime) {
try {
// Wait for hipri to connect.
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index cde84dc..49746ff 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -63,6 +63,8 @@
import com.android.internal.location.ProviderProperties;
import com.android.internal.location.ProviderRequest;
import com.android.internal.os.BackgroundThread;
+import com.android.server.location.FlpHardwareProvider;
+import com.android.server.location.FusedProxy;
import com.android.server.location.GeocoderProxy;
import com.android.server.location.GeofenceProxy;
import com.android.server.location.GeofenceManager;
@@ -429,6 +431,17 @@
Slog.e(TAG, "no geofence provider found");
}
+ // bind to fused provider
+ // TODO: [GeofenceIntegration] bind #getGeofenceHardware() with the GeofenceProxy
+ FlpHardwareProvider flpHardwareProvider = FlpHardwareProvider.getInstance(mContext);
+ FusedProxy fusedProxy = FusedProxy.createAndBind(
+ mContext,
+ mLocationHandler,
+ flpHardwareProvider.getLocationHardware());
+
+ if(fusedProxy == null) {
+ Slog.e(TAG, "No FusedProvider found.");
+ }
}
/**
@@ -552,8 +565,14 @@
allowHighPower = false;
}
}
+ boolean wasHighPowerMonitoring = mOpHighPowerMonitoring;
mOpHighPowerMonitoring = updateMonitoring(allowHighPower, mOpHighPowerMonitoring,
AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION);
+ if (mOpHighPowerMonitoring != wasHighPowerMonitoring) {
+ // send an intent to notify that a high power request has been added/removed.
+ Intent intent = new Intent(LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION);
+ mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
+ }
}
/**
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 3d8843e..9dba2ed 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -42,7 +42,7 @@
import com.android.server.AppOpsService;
import com.android.server.AttributeCache;
import com.android.server.IntentResolver;
-import com.android.server.ProcessMap;
+import com.android.internal.app.ProcessMap;
import com.android.server.SystemServer;
import com.android.server.Watchdog;
import com.android.server.am.ActivityStack.ActivityState;
@@ -1554,11 +1554,11 @@
try {
ActivityManagerService m = mSelf;
- ServiceManager.addService("activity", m, true);
+ ServiceManager.addService(Context.ACTIVITY_SERVICE, m, true);
+ ServiceManager.addService(ProcessStats.SERVICE_NAME, m.mProcessStats);
ServiceManager.addService("meminfo", new MemBinder(m));
ServiceManager.addService("gfxinfo", new GraphicsBinder(m));
ServiceManager.addService("dbinfo", new DbBinder(m));
- ServiceManager.addService("procstats", new ProcBinder(m));
if (MONITOR_CPU_USAGE) {
ServiceManager.addService("cpuinfo", new CpuBinder(m));
}
@@ -1775,26 +1775,6 @@
}
}
- static class ProcBinder extends Binder {
- ActivityManagerService mActivityManagerService;
- ProcBinder(ActivityManagerService activityManagerService) {
- mActivityManagerService = activityManagerService;
- }
-
- @Override
- protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- if (mActivityManagerService.checkCallingPermission(android.Manifest.permission.DUMP)
- != PackageManager.PERMISSION_GRANTED) {
- pw.println("Permission Denial: can't dump procstats from from pid="
- + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
- + " without permission " + android.Manifest.permission.DUMP);
- return;
- }
-
- mActivityManagerService.mProcessStats.dump(fd, pw, args);
- }
- }
-
private ActivityManagerService() {
Slog.i(TAG, "Memory class: " + ActivityManager.staticGetMemoryClass());
@@ -8453,9 +8433,17 @@
resolver, Settings.Global.WAIT_FOR_DEBUGGER, 0) != 0;
boolean alwaysFinishActivities = Settings.Global.getInt(
resolver, Settings.Global.ALWAYS_FINISH_ACTIVITIES, 0) != 0;
+ boolean forceRtl = Settings.Global.getInt(
+ resolver, Settings.Global.DEVELOPMENT_FORCE_RTL, 0) != 0;
+ // Transfer any global setting for forcing RTL layout, into a System Property
+ SystemProperties.set(Settings.Global.DEVELOPMENT_FORCE_RTL, forceRtl ? "1":"0");
Configuration configuration = new Configuration();
Settings.System.getConfiguration(resolver, configuration);
+ if (forceRtl) {
+ // This will take care of setting the correct layout direction flags
+ configuration.setLayoutDirection(configuration.locale);
+ }
synchronized (this) {
mDebugApp = mOrigDebugApp = debugApp;
diff --git a/services/java/com/android/server/am/ProcessStatsService.java b/services/java/com/android/server/am/ProcessStatsService.java
index 8b4a5a0..81b5618 100644
--- a/services/java/com/android/server/am/ProcessStatsService.java
+++ b/services/java/com/android/server/am/ProcessStatsService.java
@@ -18,6 +18,8 @@
import android.app.AppGlobals;
import android.content.pm.IPackageManager;
+import android.content.pm.PackageManager;
+import android.os.Binder;
import android.os.Parcel;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
@@ -59,7 +61,7 @@
static long WRITE_PERIOD = 30*60*1000; // Write file every 30 minutes or so.
static long COMMIT_PERIOD = 24*60*60*1000; // Commit current stats every day.
- final Object mLock;
+ final ActivityManagerService mAm;
final File mBaseDir;
ProcessStats mProcessStats;
AtomicFile mFile;
@@ -75,15 +77,15 @@
boolean mPendingWriteCommitted;
long mLastWriteTime;
- public ProcessStatsService(Object lock, File file) {
- mLock = lock;
+ public ProcessStatsService(ActivityManagerService am, File file) {
+ mAm = am;
mBaseDir = file;
mBaseDir.mkdirs();
mProcessStats = new ProcessStats(true);
updateFile();
SystemProperties.addChangeCallback(new Runnable() {
@Override public void run() {
- synchronized (mLock) {
+ synchronized (mAm) {
if (mProcessStats.evaluateSystemProperties(false)) {
mProcessStats.mFlags |= ProcessStats.FLAG_SYSPROPS;
writeStateLocked(true, true);
@@ -449,7 +451,7 @@
Parcel current = Parcel.obtain();
mWriteLock.lock();
try {
- synchronized (mLock) {
+ synchronized (mAm) {
mProcessStats.writeToParcel(current, 0);
}
if (historic != null) {
@@ -493,7 +495,16 @@
pw.println(" <package.name>: optional name of package to filter output by.");
}
- public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ @Override
+ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ if (mAm.checkCallingPermission(android.Manifest.permission.DUMP)
+ != PackageManager.PERMISSION_GRANTED) {
+ pw.println("Permission Denial: can't dump procstats from from pid="
+ + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
+ + " without permission " + android.Manifest.permission.DUMP);
+ return;
+ }
+
final long now = SystemClock.uptimeMillis();
boolean isCheckin = false;
@@ -638,7 +649,7 @@
}
}
pw.println();
- synchronized (mLock) {
+ synchronized (mAm) {
dumpFilteredProcessesCsvLocked(pw, null,
csvSepScreenStats, csvScreenStats, csvSepMemStats, csvMemStats,
csvSepProcStats, csvProcStats, now, reqPackage);
@@ -721,7 +732,7 @@
}
}
if (!isCheckin) {
- synchronized (mLock) {
+ synchronized (mAm) {
if (isCompact) {
mProcessStats.dumpCheckinLocked(pw, reqPackage);
} else {
diff --git a/services/java/com/android/server/location/FlpHardwareProvider.java b/services/java/com/android/server/location/FlpHardwareProvider.java
new file mode 100644
index 0000000..469f7ce
--- /dev/null
+++ b/services/java/com/android/server/location/FlpHardwareProvider.java
@@ -0,0 +1,344 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.location;
+
+import android.hardware.location.GeofenceHardwareImpl;
+import android.hardware.location.IFusedLocationHardware;
+import android.hardware.location.IFusedLocationHardwareSink;
+import android.location.IFusedGeofenceHardware;
+import android.location.FusedBatchOptions;
+import android.location.Geofence;
+import android.location.Location;
+import android.location.LocationListener;
+import android.location.LocationManager;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.util.Log;
+import android.util.Slog;
+
+/**
+ * This class is an interop layer for JVM types and the JNI code that interacts
+ * with the FLP HAL implementation.
+ *
+ * {@hide}
+ */
+public class FlpHardwareProvider {
+ private GeofenceHardwareImpl mGeofenceHardwareSink = null;
+ private IFusedLocationHardwareSink mLocationSink = null;
+
+ private static FlpHardwareProvider sSingletonInstance = null;
+
+ private final static String TAG = "FlpHardwareProvider";
+ private final Context mContext;
+
+ public static FlpHardwareProvider getInstance(Context context) {
+ if (sSingletonInstance == null) {
+ sSingletonInstance = new FlpHardwareProvider(context);
+ }
+
+ return sSingletonInstance;
+ }
+
+ private FlpHardwareProvider(Context context) {
+ mContext = context;
+
+ // register for listening for passive provider data
+ Handler handler = new Handler();
+ LocationManager manager = (LocationManager) mContext.getSystemService(
+ Context.LOCATION_SERVICE);
+ manager.requestLocationUpdates(
+ LocationManager.PASSIVE_PROVIDER,
+ 0 /* minTime */,
+ 0 /* minDistance */,
+ new NetworkLocationListener(),
+ handler.getLooper());
+ }
+
+ public static boolean isSupported() {
+ return nativeIsSupported();
+ }
+
+ /**
+ * Private callback functions used by FLP HAL.
+ */
+ // FlpCallbacks members
+ private void onLocationReport(Location[] locations) {
+ for (Location location : locations) {
+ location.setProvider(LocationManager.FUSED_PROVIDER);
+ // set the elapsed time-stamp just as GPS provider does
+ location.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
+ }
+
+ try {
+ if (mLocationSink != null) {
+ mLocationSink.onLocationAvailable(locations);
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException calling onLocationAvailable");
+ }
+ }
+
+ // FlpDiagnosticCallbacks members
+ private void onDataReport(String data) {
+ try {
+ if (mLocationSink != null) {
+ mLocationSink.onDiagnosticDataAvailable(data);
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException calling onDiagnosticDataAvailable");
+ }
+ }
+
+ // FlpGeofenceCallbacks members
+ private void onGeofenceTransition(
+ int geofenceId,
+ Location location,
+ int transition,
+ long timestamp,
+ int sourcesUsed
+ ) {
+ // TODO: [GeofenceIntegration] change GeofenceHardwareImpl to accept a location object
+ }
+
+ private void onGeofenceMonitorStatus(int status, int source, Location location) {
+ // TODO: [GeofenceIntegration]
+ }
+
+ private void onGeofenceAdd(int geofenceId, int result) {
+ // TODO: [GeofenceIntegration] map between GPS and FLP results to pass a consistent status
+ }
+
+ private void onGeofenceRemove(int geofenceId, int result) {
+ // TODO: [GeofenceIntegration] map between GPS and FLP results to pass a consistent status
+ }
+
+ private void onGeofencePause(int geofenceId, int result) {
+ // TODO; [GeofenceIntegration] map between GPS and FLP results
+ }
+
+ private void onGeofenceResume(int geofenceId, int result) {
+ // TODO: [GeofenceIntegration] map between GPS and FLP results
+ }
+
+ /**
+ * Private native methods accessing FLP HAL.
+ */
+ static { nativeClassInit(); }
+
+ // Core members
+ private static native void nativeClassInit();
+ private static native boolean nativeIsSupported();
+
+ // FlpLocationInterface members
+ private native void nativeInit();
+ private native int nativeGetBatchSize();
+ private native void nativeStartBatching(int requestId, FusedBatchOptions options);
+ private native void nativeUpdateBatchingOptions(int requestId, FusedBatchOptions optionsObject);
+ private native void nativeStopBatching(int id);
+ private native void nativeRequestBatchedLocation(int lastNLocations);
+ private native void nativeInjectLocation(Location location);
+ // TODO [Fix] sort out the lifetime of the instance
+ private native void nativeCleanup();
+
+ // FlpDiagnosticsInterface members
+ private native boolean nativeIsDiagnosticSupported();
+ private native void nativeInjectDiagnosticData(String data);
+
+ // FlpDeviceContextInterface members
+ private native boolean nativeIsDeviceContextSupported();
+ private native void nativeInjectDeviceContext(int deviceEnabledContext);
+
+ // FlpGeofencingInterface members
+ private native boolean nativeIsGeofencingSupported();
+ private native void nativeAddGeofences(int[] geofenceIdsArray, Geofence[] geofencesArray);
+ private native void nativePauseGeofence(int geofenceId);
+ private native void nativeResumeGeofence(int geofenceId, int monitorTransitions);
+ private native void nativeModifyGeofenceOption(
+ int geofenceId,
+ int lastTransition,
+ int monitorTransitions,
+ int notificationResponsiveness,
+ int unknownTimer,
+ int sourcesToUse);
+ private native void nativeRemoveGeofences(int[] geofenceIdsArray);
+
+ /**
+ * Interface implementations for services built on top of this functionality.
+ */
+ public static final String LOCATION = "Location";
+ public static final String GEOFENCING = "Geofencing";
+
+ public IFusedLocationHardware getLocationHardware() {
+ nativeInit();
+ return mLocationHardware;
+ }
+
+ public IFusedGeofenceHardware getGeofenceHardware() {
+ nativeInit();
+ return mGeofenceHardwareService;
+ }
+
+ private final IFusedLocationHardware mLocationHardware = new IFusedLocationHardware.Stub() {
+ @Override
+ public void registerSink(IFusedLocationHardwareSink eventSink) {
+ // only one sink is allowed at the moment
+ if (mLocationSink != null) {
+ throw new RuntimeException("IFusedLocationHardware does not support multiple sinks");
+ }
+
+ mLocationSink = eventSink;
+ }
+
+ @Override
+ public void unregisterSink(IFusedLocationHardwareSink eventSink) {
+ // don't throw if the sink is not registered, simply make it a no-op
+ if (mLocationSink == eventSink) {
+ mLocationSink = null;
+ }
+ }
+
+ @Override
+ public int getSupportedBatchSize() {
+ return nativeGetBatchSize();
+ }
+
+ @Override
+ public void startBatching(int requestId, FusedBatchOptions options) {
+ nativeStartBatching(requestId, options);
+ }
+
+ @Override
+ public void stopBatching(int requestId) {
+ nativeStopBatching(requestId);
+ }
+
+ @Override
+ public void updateBatchingOptions(int requestId, FusedBatchOptions options) {
+ nativeUpdateBatchingOptions(requestId, options);
+ }
+
+ @Override
+ public void requestBatchOfLocations(int batchSizeRequested) {
+ nativeRequestBatchedLocation(batchSizeRequested);
+ }
+
+ @Override
+ public boolean supportsDiagnosticDataInjection() {
+ return nativeIsDiagnosticSupported();
+ }
+
+ @Override
+ public void injectDiagnosticData(String data) {
+ nativeInjectDiagnosticData(data);
+ }
+
+ @Override
+ public boolean supportsDeviceContextInjection() {
+ return nativeIsDeviceContextSupported();
+ }
+
+ @Override
+ public void injectDeviceContext(int deviceEnabledContext) {
+ nativeInjectDeviceContext(deviceEnabledContext);
+ }
+ };
+
+ private final IFusedGeofenceHardware mGeofenceHardwareService =
+ new IFusedGeofenceHardware.Stub() {
+ @Override
+ public boolean isSupported() {
+ return nativeIsGeofencingSupported();
+ }
+
+ @Override
+ public void addGeofences(int[] geofenceIdsArray, Geofence[] geofencesArray) {
+ nativeAddGeofences(geofenceIdsArray, geofencesArray);
+ }
+
+ @Override
+ public void removeGeofences(int[] geofenceIds) {
+ nativeRemoveGeofences(geofenceIds);
+ }
+
+ @Override
+ public void pauseMonitoringGeofence(int geofenceId) {
+ nativePauseGeofence(geofenceId);
+ }
+
+ @Override
+ public void resumeMonitoringGeofence(int geofenceId, int monitorTransitions) {
+ nativeResumeGeofence(geofenceId, monitorTransitions);
+ }
+
+ @Override
+ public void modifyGeofenceOptions(int geofenceId,
+ int lastTransition,
+ int monitorTransitions,
+ int notificationResponsiveness,
+ int unknownTimer
+ ) {
+ // TODO: [GeofenceIntegration] set sourcesToUse to the right value
+ // TODO: expose sourcesToUse externally when needed
+ nativeModifyGeofenceOption(
+ geofenceId,
+ lastTransition,
+ monitorTransitions,
+ notificationResponsiveness,
+ unknownTimer,
+ /* sourcesToUse */ 0xFFFF);
+ }
+ };
+
+ /**
+ * Internal classes and functions used by the provider.
+ */
+ private final class NetworkLocationListener implements LocationListener {
+ @Override
+ public void onLocationChanged(Location location) {
+ if (
+ !LocationManager.NETWORK_PROVIDER.equals(location.getProvider()) ||
+ !location.hasAccuracy()
+ ) {
+ return;
+ }
+
+ nativeInjectLocation(location);
+ }
+
+ @Override
+ public void onStatusChanged(String provider, int status, Bundle extras) { }
+
+ @Override
+ public void onProviderEnabled(String provider) { }
+
+ @Override
+ public void onProviderDisabled(String provider) { }
+ }
+
+ private GeofenceHardwareImpl getGeofenceHardwareSink() {
+ if (mGeofenceHardwareSink == null) {
+ // TODO: [GeofenceIntegration] we need to register ourselves with GeofenceHardwareImpl
+ mGeofenceHardwareSink = GeofenceHardwareImpl.getInstance(mContext);
+ }
+
+ return mGeofenceHardwareSink;
+ }
+}
\ No newline at end of file
diff --git a/services/java/com/android/server/location/FusedLocationHardwareSecure.java b/services/java/com/android/server/location/FusedLocationHardwareSecure.java
new file mode 100644
index 0000000..389bd24
--- /dev/null
+++ b/services/java/com/android/server/location/FusedLocationHardwareSecure.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.location;
+
+import android.content.Context;
+import android.hardware.location.IFusedLocationHardware;
+import android.hardware.location.IFusedLocationHardwareSink;
+import android.location.FusedBatchOptions;
+import android.os.RemoteException;
+
+/**
+ * FusedLocationHardware decorator that adds permission checking.
+ * @hide
+ */
+public class FusedLocationHardwareSecure extends IFusedLocationHardware.Stub {
+ private final IFusedLocationHardware mLocationHardware;
+ private final Context mContext;
+ private final String mPermissionId;
+
+ public FusedLocationHardwareSecure(
+ IFusedLocationHardware locationHardware,
+ Context context,
+ String permissionId) {
+ mLocationHardware = locationHardware;
+ mContext = context;
+ mPermissionId = permissionId;
+ }
+
+ private void checkPermissions() {
+ mContext.enforceCallingPermission(
+ mPermissionId,
+ String.format(
+ "Permission '%s' not granted to access FusedLocationHardware",
+ mPermissionId));
+ }
+
+ @Override
+ public void registerSink(IFusedLocationHardwareSink eventSink) throws RemoteException {
+ checkPermissions();
+ mLocationHardware.registerSink(eventSink);
+ }
+
+ @Override
+ public void unregisterSink(IFusedLocationHardwareSink eventSink) throws RemoteException {
+ checkPermissions();
+ mLocationHardware.unregisterSink(eventSink);
+ }
+
+ @Override
+ public int getSupportedBatchSize() throws RemoteException {
+ checkPermissions();
+ return mLocationHardware.getSupportedBatchSize();
+ }
+
+ @Override
+ public void startBatching(int id, FusedBatchOptions batchOptions) throws RemoteException {
+ checkPermissions();
+ mLocationHardware.startBatching(id, batchOptions);
+ }
+
+ @Override
+ public void stopBatching(int id) throws RemoteException {
+ checkPermissions();
+ mLocationHardware.stopBatching(id);
+ }
+
+ @Override
+ public void updateBatchingOptions(
+ int id,
+ FusedBatchOptions batchoOptions
+ ) throws RemoteException {
+ checkPermissions();
+ mLocationHardware.updateBatchingOptions(id, batchoOptions);
+ }
+
+ @Override
+ public void requestBatchOfLocations(int batchSizeRequested) throws RemoteException {
+ checkPermissions();
+ mLocationHardware.requestBatchOfLocations(batchSizeRequested);
+ }
+
+ @Override
+ public boolean supportsDiagnosticDataInjection() throws RemoteException {
+ checkPermissions();
+ return mLocationHardware.supportsDiagnosticDataInjection();
+ }
+
+ @Override
+ public void injectDiagnosticData(String data) throws RemoteException {
+ checkPermissions();
+ mLocationHardware.injectDiagnosticData(data);
+ }
+
+ @Override
+ public boolean supportsDeviceContextInjection() throws RemoteException {
+ checkPermissions();
+ return mLocationHardware.supportsDeviceContextInjection();
+ }
+
+ @Override
+ public void injectDeviceContext(int deviceEnabledContext) throws RemoteException {
+ checkPermissions();
+ mLocationHardware.injectDeviceContext(deviceEnabledContext);
+ }
+}
diff --git a/services/java/com/android/server/location/FusedProxy.java b/services/java/com/android/server/location/FusedProxy.java
new file mode 100644
index 0000000..8278b96
--- /dev/null
+++ b/services/java/com/android/server/location/FusedProxy.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (The "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.location;
+
+import com.android.server.ServiceWatcher;
+
+import android.Manifest;
+import android.content.Context;
+import android.hardware.location.IFusedLocationHardware;
+import android.location.IFusedProvider;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.util.Log;
+
+/**
+ * Proxy that helps bind GCore FusedProvider implementations to the Fused Hardware instances.
+ *
+ * @hide
+ */
+public final class FusedProxy {
+ private final String TAG = "FusedProxy";
+
+ private ServiceWatcher mServiceWatcher;
+
+ private FusedLocationHardwareSecure mLocationHardware;
+
+ /**
+ * Constructor of the class.
+ * This is private as the class follows a factory pattern for construction.
+ *
+ * @param context The context needed for construction.
+ * @param handler The handler needed for construction.
+ * @param locationHardware The instance of the Fused location hardware assigned to the proxy.
+ */
+ private FusedProxy(Context context, Handler handler, IFusedLocationHardware locationHardware) {
+ mLocationHardware = new FusedLocationHardwareSecure(
+ locationHardware,
+ context,
+ Manifest.permission.LOCATION_HARDWARE);
+ Runnable newServiceWork = new Runnable() {
+ @Override
+ public void run() {
+ bindProvider(mLocationHardware);
+ }
+ };
+
+ // prepare the connection to the provider
+ mServiceWatcher = new ServiceWatcher(
+ context,
+ TAG,
+ "com.android.location.service.FusedProvider",
+ com.android.internal.R.bool.config_enableFusedLocationOverlay,
+ com.android.internal.R.string.config_fusedLocationProviderPackageName,
+ com.android.internal.R.array.config_locationProviderPackageNames,
+ newServiceWork,
+ handler);
+ }
+
+ /**
+ * Creates an instance of the proxy and binds it to the appropriate FusedProvider.
+ *
+ * @param context The context needed for construction.
+ * @param handler The handler needed for construction.
+ * @param locationHardware The instance of the Fused location hardware assigned to the proxy.
+ *
+ * @return An instance of the proxy if it could be bound, null otherwise.
+ */
+ public static FusedProxy createAndBind(
+ Context context,
+ Handler handler,
+ IFusedLocationHardware locationHardware
+ ) {
+ FusedProxy fusedProxy = new FusedProxy(context, handler, locationHardware);
+
+ // try to bind the Fused provider
+ if (!fusedProxy.mServiceWatcher.start()) {
+ return null;
+ }
+
+ return fusedProxy;
+ }
+
+ /**
+ * Helper function to bind the FusedLocationHardware to the appropriate FusedProvider instance.
+ *
+ * @param locationHardware The FusedLocationHardware instance to use for the binding operation.
+ */
+ private void bindProvider(IFusedLocationHardware locationHardware) {
+ IFusedProvider provider = IFusedProvider.Stub.asInterface(mServiceWatcher.getBinder());
+
+ if (provider == null) {
+ Log.e(TAG, "No instance of FusedProvider found on FusedLocationHardware connected.");
+ return;
+ }
+
+ try {
+ provider.onFusedLocationHardwareChange(locationHardware);
+ } catch (RemoteException e) {
+ Log.e(TAG, e.toString());
+ }
+ }
+}
diff --git a/services/jni/Android.mk b/services/jni/Android.mk
index 3946f15..93d8e07 100644
--- a/services/jni/Android.mk
+++ b/services/jni/Android.mk
@@ -15,6 +15,7 @@
com_android_server_UsbHostManager.cpp \
com_android_server_VibratorService.cpp \
com_android_server_location_GpsLocationProvider.cpp \
+ com_android_server_location_FlpHardwareProvider.cpp \
com_android_server_connectivity_Vpn.cpp \
onload.cpp
diff --git a/services/jni/com_android_server_location_FlpHardwareProvider.cpp b/services/jni/com_android_server_location_FlpHardwareProvider.cpp
new file mode 100644
index 0000000..48b86db
--- /dev/null
+++ b/services/jni/com_android_server_location_FlpHardwareProvider.cpp
@@ -0,0 +1,901 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the license at
+ *
+ * http://www.apache.org/license/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the license.
+ */
+
+#define LOG_TAG "FuseLocationProvider"
+#define LOG_NDEBUG 0
+
+#define WAKE_LOCK_NAME "FLP"
+#define LOCATION_CLASS_NAME "android/location/Location"
+
+#include "jni.h"
+#include "JNIHelp.h"
+#include "android_runtime/AndroidRuntime.h"
+#include "hardware/fused_location.h"
+#include "hardware_legacy/power.h"
+
+static jobject sCallbacksObj = NULL;
+static JNIEnv *sCallbackEnv = NULL;
+static hw_device_t* sHardwareDevice = NULL;
+
+static jmethodID sOnLocationReport = NULL;
+static jmethodID sOnDataReport = NULL;
+static jmethodID sOnGeofenceTransition = NULL;
+static jmethodID sOnGeofenceMonitorStatus = NULL;
+static jmethodID sOnGeofenceAdd = NULL;
+static jmethodID sOnGeofenceRemove = NULL;
+static jmethodID sOnGeofencePause = NULL;
+static jmethodID sOnGeofenceResume = NULL;
+
+static const FlpLocationInterface* sFlpInterface = NULL;
+static const FlpDiagnosticInterface* sFlpDiagnosticInterface = NULL;
+static const FlpGeofencingInterface* sFlpGeofencingInterface = NULL;
+static const FlpDeviceContextInterface* sFlpDeviceContextInterface = NULL;
+
+namespace android {
+
+static inline void CheckExceptions(JNIEnv* env, const char* methodName) {
+ if(!env->ExceptionCheck()) {
+ return;
+ }
+
+ ALOGE("An exception was thrown by '%s'.", methodName);
+ LOGE_EX(env);
+ env->ExceptionClear();
+}
+
+static inline void ThrowOnError(
+ JNIEnv* env,
+ int resultCode,
+ const char* methodName) {
+ if(resultCode == FLP_RESULT_SUCCESS) {
+ return;
+ }
+
+ ALOGE("Error %d in '%s'", resultCode, methodName);
+ jclass exceptionClass = env->FindClass("java/lang/RuntimeException");
+ env->ThrowNew(exceptionClass, methodName);
+}
+
+static bool IsValidCallbackThread() {
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+
+ if(sCallbackEnv == NULL || sCallbackEnv != env) {
+ ALOGE("CallbackThread check fail: env=%p, expected=%p", env, sCallbackEnv);
+ return false;
+ }
+
+ return true;
+}
+
+static int SetThreadEvent(ThreadEvent event) {
+ JavaVM* javaVm = AndroidRuntime::getJavaVM();
+
+ switch(event) {
+ case ASSOCIATE_JVM:
+ {
+ if(sCallbackEnv != NULL) {
+ ALOGE(
+ "Attempted to associate callback in '%s'. Callback already associated.",
+ __FUNCTION__
+ );
+ return FLP_RESULT_ERROR;
+ }
+
+ JavaVMAttachArgs args = {
+ JNI_VERSION_1_6,
+ "FLP Service Callback Thread",
+ /* group */ NULL
+ };
+
+ jint attachResult = javaVm->AttachCurrentThread(&sCallbackEnv, &args);
+ if (attachResult != 0) {
+ ALOGE("Callback thread attachment error: %d", attachResult);
+ return FLP_RESULT_ERROR;
+ }
+
+ ALOGV("Callback thread attached: %p", sCallbackEnv);
+ break;
+ }
+ case DISASSOCIATE_JVM:
+ {
+ if (!IsValidCallbackThread()) {
+ ALOGE(
+ "Attempted to dissasociate an unnownk callback thread : '%s'.",
+ __FUNCTION__
+ );
+ return FLP_RESULT_ERROR;
+ }
+
+ if (javaVm->DetachCurrentThread() != 0) {
+ return FLP_RESULT_ERROR;
+ }
+
+ sCallbackEnv = NULL;
+ break;
+ }
+ default:
+ ALOGE("Invalid ThreadEvent request %d", event);
+ return FLP_RESULT_ERROR;
+ }
+
+ return FLP_RESULT_SUCCESS;
+}
+
+/*
+ * Initializes the FlpHardwareProvider class from the native side by opening
+ * the HW module and obtaining the proper interfaces.
+ */
+static void ClassInit(JNIEnv* env, jclass clazz) {
+ // get references to the Java provider methods
+ sOnLocationReport = env->GetMethodID(
+ clazz,
+ "onLocationReport",
+ "([Landroid/location/Location;)V");
+ sOnDataReport = env->GetMethodID(
+ clazz,
+ "onDataReport",
+ "(Ljava/lang/String;)V"
+ );
+ sOnGeofenceTransition = env->GetMethodID(
+ clazz,
+ "onGeofenceTransition",
+ "(ILandroid/location/Location;IJI)V"
+ );
+ sOnGeofenceMonitorStatus = env->GetMethodID(
+ clazz,
+ "onGeofenceMonitorStatus",
+ "(IILandroid/location/Location;)V"
+ );
+ sOnGeofenceAdd = env->GetMethodID(clazz, "onGeofenceAdd", "(II)V");
+ sOnGeofenceRemove = env->GetMethodID(clazz, "onGeofenceRemove", "(II)V");
+ sOnGeofencePause = env->GetMethodID(clazz, "onGeofencePause", "(II)V");
+ sOnGeofenceResume = env->GetMethodID(clazz, "onGeofenceResume", "(II)V");
+}
+
+/*
+ * Helper function to unwrap a java object back into a FlpLocation structure.
+ */
+static void TranslateFromObject(
+ JNIEnv* env,
+ jobject locationObject,
+ FlpLocation& location) {
+ location.size = sizeof(FlpLocation);
+ location.flags = 0;
+
+ jclass locationClass = env->GetObjectClass(locationObject);
+
+ jmethodID getLatitude = env->GetMethodID(locationClass, "getLatitude", "()D");
+ location.latitude = env->CallDoubleMethod(locationObject, getLatitude);
+ jmethodID getLongitude = env->GetMethodID(locationClass, "getLongitude", "()D");
+ location.longitude = env->CallDoubleMethod(locationObject, getLongitude);
+ jmethodID getTime = env->GetMethodID(locationClass, "getTime", "()J");
+ location.timestamp = env->CallLongMethod(locationObject, getTime);
+ location.flags |= FLP_LOCATION_HAS_LAT_LONG;
+
+ jmethodID hasAltitude = env->GetMethodID(locationClass, "hasAltitude", "()Z");
+ if (env->CallBooleanMethod(locationObject, hasAltitude)) {
+ jmethodID getAltitude = env->GetMethodID(locationClass, "getAltitude", "()D");
+ location.altitude = env->CallDoubleMethod(locationObject, getAltitude);
+ location.flags |= FLP_LOCATION_HAS_ALTITUDE;
+ }
+
+ jmethodID hasSpeed = env->GetMethodID(locationClass, "hasSpeed", "()Z");
+ if (env->CallBooleanMethod(locationObject, hasSpeed)) {
+ jmethodID getSpeed = env->GetMethodID(locationClass, "getSpeed", "()F");
+ location.speed = env->CallFloatMethod(locationObject, getSpeed);
+ location.flags |= FLP_LOCATION_HAS_SPEED;
+ }
+
+ jmethodID hasBearing = env->GetMethodID(locationClass, "hasBearing", "()Z");
+ if (env->CallBooleanMethod(locationObject, hasBearing)) {
+ jmethodID getBearing = env->GetMethodID(locationClass, "getBearing", "()F");
+ location.bearing = env->CallFloatMethod(locationObject, getBearing);
+ location.flags |= FLP_LOCATION_HAS_BEARING;
+ }
+
+ jmethodID hasAccuracy = env->GetMethodID(locationClass, "hasAccuracy", "()Z");
+ if (env->CallBooleanMethod(locationObject, hasAccuracy)) {
+ jmethodID getAccuracy = env->GetMethodID(
+ locationClass,
+ "getAccuracy",
+ "()F"
+ );
+ location.accuracy = env->CallFloatMethod(locationObject, getAccuracy);
+ location.flags |= FLP_LOCATION_HAS_ACCURACY;
+ }
+
+ // TODO: wire sources_used if Location class exposes them
+}
+
+/*
+ * Helper function to unwrap FlpBatchOptions from the Java Runtime calls.
+ */
+static void TranslateFromObject(
+ JNIEnv* env,
+ jobject batchOptionsObject,
+ FlpBatchOptions& batchOptions) {
+ jclass batchOptionsClass = env->GetObjectClass(batchOptionsObject);
+
+ jmethodID getMaxPower = env->GetMethodID(
+ batchOptionsClass,
+ "getMaxPowerAllocationInMW",
+ "()D"
+ );
+ batchOptions.max_power_allocation_mW = env->CallDoubleMethod(
+ batchOptionsObject,
+ getMaxPower
+ );
+
+ jmethodID getPeriod = env->GetMethodID(
+ batchOptionsClass,
+ "getPeriodInNS",
+ "()J"
+ );
+ batchOptions.period_ns = env->CallLongMethod(batchOptionsObject, getPeriod);
+
+ jmethodID getSourcesToUse = env->GetMethodID(
+ batchOptionsClass,
+ "getSourcesToUse",
+ "()I"
+ );
+ batchOptions.sources_to_use = env->CallIntMethod(
+ batchOptionsObject,
+ getSourcesToUse
+ );
+
+ jmethodID getFlags = env->GetMethodID(batchOptionsClass, "getFlags", "()I");
+ batchOptions.flags = env->CallIntMethod(batchOptionsObject, getFlags);
+}
+
+/*
+ * Helper function to transform FlpLocation into a java object.
+ */
+static void TranslateToObject(const FlpLocation* location, jobject& locationObject) {
+ jclass locationClass = sCallbackEnv->FindClass(LOCATION_CLASS_NAME);
+ jmethodID locationCtor = sCallbackEnv->GetMethodID(
+ locationClass,
+ "<init>",
+ "(Ljava/lang/String;)V"
+ );
+
+ // the provider is set in the upper JVM layer
+ locationObject = sCallbackEnv->NewObject(locationClass, locationCtor, NULL);
+ jint flags = location->flags;
+
+ // set the valid information in the object
+ if (flags & FLP_LOCATION_HAS_LAT_LONG) {
+ jmethodID setLatitude = sCallbackEnv->GetMethodID(
+ locationClass,
+ "setLatitude",
+ "(D)V"
+ );
+ sCallbackEnv->CallVoidMethod(locationObject, setLatitude, location->latitude);
+
+ jmethodID setLongitude = sCallbackEnv->GetMethodID(
+ locationClass,
+ "setLongitude",
+ "(D)V"
+ );
+ sCallbackEnv->CallVoidMethod(
+ locationObject,
+ setLongitude,
+ location->longitude
+ );
+
+ jmethodID setTime = sCallbackEnv->GetMethodID(
+ locationClass,
+ "setTime",
+ "(J)V"
+ );
+ sCallbackEnv->CallVoidMethod(locationObject, setTime, location->timestamp);
+ }
+
+ if (flags & FLP_LOCATION_HAS_ALTITUDE) {
+ jmethodID setAltitude = sCallbackEnv->GetMethodID(
+ locationClass,
+ "setAltitude",
+ "(D)V"
+ );
+ sCallbackEnv->CallVoidMethod(locationObject, setAltitude, location->altitude);
+ }
+
+ if (flags & FLP_LOCATION_HAS_SPEED) {
+ jmethodID setSpeed = sCallbackEnv->GetMethodID(
+ locationClass,
+ "setSpeed",
+ "(F)V"
+ );
+ sCallbackEnv->CallVoidMethod(locationObject, setSpeed, location->speed);
+ }
+
+ if (flags & FLP_LOCATION_HAS_BEARING) {
+ jmethodID setBearing = sCallbackEnv->GetMethodID(
+ locationClass,
+ "setBearing",
+ "(F)V"
+ );
+ sCallbackEnv->CallVoidMethod(locationObject, setBearing, location->bearing);
+ }
+
+ if (flags & FLP_LOCATION_HAS_ACCURACY) {
+ jmethodID setAccuracy = sCallbackEnv->GetMethodID(
+ locationClass,
+ "setAccuracy",
+ "(F)V"
+ );
+ sCallbackEnv->CallVoidMethod(locationObject, setAccuracy, location->accuracy);
+ }
+
+ // TODO: wire FlpLocation::sources_used when needed
+}
+
+/*
+ * Helper function to serialize FlpLocation structures.
+ */
+static void TranslateToObjectArray(
+ int32_t locationsCount,
+ FlpLocation** locations,
+ jobjectArray& locationsArray) {
+ jclass locationClass = sCallbackEnv->FindClass(LOCATION_CLASS_NAME);
+ locationsArray = sCallbackEnv->NewObjectArray(
+ locationsCount,
+ locationClass,
+ /* initialElement */ NULL
+ );
+
+ for (int i = 0; i < locationsCount; ++i) {
+ jobject locationObject = NULL;
+ TranslateToObject(locations[i], locationObject);
+ sCallbackEnv->SetObjectArrayElement(locationsArray, i, locationObject);
+ sCallbackEnv->DeleteLocalRef(locationObject);
+ }
+}
+
+static void LocationCallback(int32_t locationsCount, FlpLocation** locations) {
+ if(!IsValidCallbackThread()) {
+ return;
+ }
+
+ if(locationsCount == 0 || locations == NULL) {
+ ALOGE(
+ "Invalid LocationCallback. Count: %d, Locations: %p",
+ locationsCount,
+ locations
+ );
+ return;
+ }
+
+ jobjectArray locationsArray = NULL;
+ TranslateToObjectArray(locationsCount, locations, locationsArray);
+
+ sCallbackEnv->CallVoidMethod(
+ sCallbacksObj,
+ sOnLocationReport,
+ locationsArray
+ );
+ CheckExceptions(sCallbackEnv, __FUNCTION__);
+}
+
+static void AcquireWakelock() {
+ acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_NAME);
+}
+
+static void ReleaseWakelock() {
+ release_wake_lock(WAKE_LOCK_NAME);
+}
+
+FlpCallbacks sFlpCallbacks = {
+ sizeof(FlpCallbacks),
+ LocationCallback,
+ AcquireWakelock,
+ ReleaseWakelock,
+ SetThreadEvent
+};
+
+static void ReportData(char* data, int length) {
+ jstring stringData = NULL;
+
+ if(length != 0 && data != NULL) {
+ stringData = sCallbackEnv->NewString(reinterpret_cast<jchar*>(data), length);
+ } else {
+ ALOGE("Invalid ReportData callback. Length: %d, Data: %p", length, data);
+ return;
+ }
+
+ sCallbackEnv->CallVoidMethod(sCallbacksObj, sOnDataReport, stringData);
+ CheckExceptions(sCallbackEnv, __FUNCTION__);
+}
+
+FlpDiagnosticCallbacks sFlpDiagnosticCallbacks = {
+ sizeof(FlpDiagnosticCallbacks),
+ SetThreadEvent,
+ ReportData
+};
+
+static void GeofenceTransitionCallback(
+ int32_t geofenceId,
+ FlpLocation* location,
+ int32_t transition,
+ FlpUtcTime timestamp,
+ uint32_t sourcesUsed
+ ) {
+ if(!IsValidCallbackThread()) {
+ return;
+ }
+
+ if(location == NULL) {
+ ALOGE("GeofenceTransition received with invalid location: %p", location);
+ return;
+ }
+
+ jobject locationObject = NULL;
+ TranslateToObject(location, locationObject);
+
+ sCallbackEnv->CallVoidMethod(
+ sCallbacksObj,
+ sOnGeofenceTransition,
+ geofenceId,
+ locationObject,
+ transition,
+ timestamp,
+ sourcesUsed
+ );
+ CheckExceptions(sCallbackEnv, __FUNCTION__);
+}
+
+static void GeofenceMonitorStatusCallback(
+ int32_t status,
+ uint32_t source,
+ FlpLocation* lastLocation) {
+ if(!IsValidCallbackThread()) {
+ return;
+ }
+
+ jobject locationObject = NULL;
+ if(lastLocation != NULL) {
+ TranslateToObject(lastLocation, locationObject);
+ }
+
+ sCallbackEnv->CallVoidMethod(
+ sCallbacksObj,
+ sOnGeofenceMonitorStatus,
+ status,
+ source,
+ locationObject
+ );
+ CheckExceptions(sCallbackEnv, __FUNCTION__);
+}
+
+static void GeofenceAddCallback(int32_t geofenceId, int32_t result) {
+ if(!IsValidCallbackThread()) {
+ return;
+ }
+
+ sCallbackEnv->CallVoidMethod(sCallbacksObj, sOnGeofenceAdd, geofenceId, result);
+ CheckExceptions(sCallbackEnv, __FUNCTION__);
+}
+
+static void GeofenceRemoveCallback(int32_t geofenceId, int32_t result) {
+ if(!IsValidCallbackThread()) {
+ return;
+ }
+
+ sCallbackEnv->CallVoidMethod(
+ sCallbacksObj,
+ sOnGeofenceRemove,
+ geofenceId,
+ result
+ );
+ CheckExceptions(sCallbackEnv, __FUNCTION__);
+}
+
+static void GeofencePauseCallback(int32_t geofenceId, int32_t result) {
+ if(!IsValidCallbackThread()) {
+ return;
+ }
+
+ sCallbackEnv->CallVoidMethod(
+ sCallbacksObj,
+ sOnGeofencePause,
+ geofenceId,
+ result
+ );
+ CheckExceptions(sCallbackEnv, __FUNCTION__);
+}
+
+static void GeofenceResumeCallback(int32_t geofenceId, int32_t result) {
+ if(!IsValidCallbackThread()) {
+ return;
+ }
+
+ sCallbackEnv->CallVoidMethod(
+ sCallbacksObj,
+ sOnGeofenceResume,
+ geofenceId,
+ result
+ );
+ CheckExceptions(sCallbackEnv, __FUNCTION__);
+}
+
+FlpGeofenceCallbacks sFlpGeofenceCallbacks = {
+ sizeof(FlpGeofenceCallbacks),
+ GeofenceTransitionCallback,
+ GeofenceMonitorStatusCallback,
+ GeofenceAddCallback,
+ GeofenceRemoveCallback,
+ GeofencePauseCallback,
+ GeofenceResumeCallback,
+ SetThreadEvent
+};
+
+/*
+ * Initializes the Fused Location Provider in the native side. It ensures that
+ * the Flp interfaces are initialized properly.
+ */
+static void Init(JNIEnv* env, jobject obj) {
+ if(sHardwareDevice != NULL) {
+ ALOGD("Hardware Device already opened.");
+ return;
+ }
+
+ const hw_module_t* module = NULL;
+ int err = hw_get_module(FUSED_LOCATION_HARDWARE_MODULE_ID, &module);
+ if(err != 0) {
+ ALOGE("Error hw_get_module '%s': %d", FUSED_LOCATION_HARDWARE_MODULE_ID, err);
+ return;
+ }
+
+ err = module->methods->open(
+ module,
+ FUSED_LOCATION_HARDWARE_MODULE_ID, &sHardwareDevice);
+ if(err != 0) {
+ ALOGE("Error opening device '%s': %d", FUSED_LOCATION_HARDWARE_MODULE_ID, err);
+ return;
+ }
+
+ sFlpInterface = NULL;
+ flp_device_t* flp_device = reinterpret_cast<flp_device_t*>(sHardwareDevice);
+ sFlpInterface = flp_device->get_flp_interface(flp_device);
+
+ if(sFlpInterface != NULL) {
+ sFlpDiagnosticInterface = reinterpret_cast<const FlpDiagnosticInterface*>(
+ sFlpInterface->get_extension(FLP_DIAGNOSTIC_INTERFACE)
+ );
+
+ sFlpGeofencingInterface = reinterpret_cast<const FlpGeofencingInterface*>(
+ sFlpInterface->get_extension(FLP_GEOFENCING_INTERFACE)
+ );
+
+ sFlpDeviceContextInterface = reinterpret_cast<const FlpDeviceContextInterface*>(
+ sFlpInterface->get_extension(FLP_DEVICE_CONTEXT_INTERFACE)
+ );
+ }
+
+ if(sCallbacksObj == NULL) {
+ sCallbacksObj = env->NewGlobalRef(obj);
+ }
+
+ // initialize the Flp interfaces
+ if(sFlpInterface == NULL || sFlpInterface->init(&sFlpCallbacks) != 0) {
+ ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
+ }
+
+ if(sFlpDiagnosticInterface != NULL) {
+ sFlpDiagnosticInterface->init(&sFlpDiagnosticCallbacks);
+ }
+
+ if(sFlpGeofencingInterface != NULL) {
+ sFlpGeofencingInterface->init(&sFlpGeofenceCallbacks);
+ }
+
+ // TODO: inject any device context if when needed
+}
+
+static jboolean IsSupported(JNIEnv* env, jclass clazz) {
+ return sFlpInterface != NULL;
+}
+
+static jint GetBatchSize(JNIEnv* env, jobject object) {
+ if(sFlpInterface == NULL) {
+ ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
+ }
+
+ return sFlpInterface->get_batch_size();
+}
+
+static void StartBatching(
+ JNIEnv* env,
+ jobject object,
+ jint id,
+ jobject optionsObject) {
+ if(sFlpInterface == NULL || optionsObject == NULL) {
+ ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
+ }
+
+ FlpBatchOptions options;
+ TranslateFromObject(env, optionsObject, options);
+ int result = sFlpInterface->start_batching(id, &options);
+ ThrowOnError(env, result, __FUNCTION__);
+}
+
+static void UpdateBatchingOptions(
+ JNIEnv* env,
+ jobject object,
+ jint id,
+ jobject optionsObject) {
+ if(sFlpInterface == NULL || optionsObject == NULL) {
+ ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
+ }
+
+ FlpBatchOptions options;
+ TranslateFromObject(env, optionsObject, options);
+ int result = sFlpInterface->update_batching_options(id, &options);
+ ThrowOnError(env, result, __FUNCTION__);
+}
+
+static void StopBatching(JNIEnv* env, jobject object, jint id) {
+ if(sFlpInterface == NULL) {
+ ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
+ }
+
+ sFlpInterface->stop_batching(id);
+}
+
+static void Cleanup(JNIEnv* env, jobject object) {
+ if(sFlpInterface == NULL) {
+ ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
+ }
+
+ sFlpInterface->cleanup();
+
+ if(sCallbacksObj != NULL) {
+ env->DeleteGlobalRef(sCallbacksObj);
+ sCallbacksObj = NULL;
+ }
+
+ sFlpInterface = NULL;
+ sFlpDiagnosticInterface = NULL;
+ sFlpDeviceContextInterface = NULL;
+ sFlpGeofencingInterface = NULL;
+
+ if(sHardwareDevice != NULL) {
+ sHardwareDevice->close(sHardwareDevice);
+ sHardwareDevice = NULL;
+ }
+}
+
+static void GetBatchedLocation(JNIEnv* env, jobject object, jint lastNLocations) {
+ if(sFlpInterface == NULL) {
+ ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
+ }
+
+ sFlpInterface->get_batched_location(lastNLocations);
+}
+
+static void InjectLocation(JNIEnv* env, jobject object, jobject locationObject) {
+ if(locationObject == NULL) {
+ ALOGE("Invalid location for injection: %p", locationObject);
+ ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
+ }
+
+ if(sFlpInterface == NULL) {
+ // there is no listener, bail
+ return;
+ }
+
+ FlpLocation location;
+ TranslateFromObject(env, locationObject, location);
+ int result = sFlpInterface->inject_location(&location);
+ if (result != FLP_RESULT_ERROR) {
+ // do not throw but log, this operation should be fire and forget
+ ALOGE("Error %d in '%s'", result, __FUNCTION__);
+ }
+}
+
+static jboolean IsDiagnosticSupported() {
+ return sFlpDiagnosticInterface != NULL;
+}
+
+static void InjectDiagnosticData(JNIEnv* env, jobject object, jstring stringData) {
+ if(stringData == NULL) {
+ ALOGE("Invalid diagnostic data for injection: %p", stringData);
+ ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
+ }
+
+ if(sFlpDiagnosticInterface == NULL) {
+ ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
+ }
+
+ int length = env->GetStringLength(stringData);
+ const jchar* data = env->GetStringChars(stringData, /* isCopy */ NULL);
+ if(data == NULL) {
+ ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
+ }
+
+ int result = sFlpDiagnosticInterface->inject_data((char*) data, length);
+ ThrowOnError(env, result, __FUNCTION__);
+}
+
+static jboolean IsDeviceContextSupported() {
+ return sFlpDeviceContextInterface != NULL;
+}
+
+static void InjectDeviceContext(JNIEnv* env, jobject object, jint enabledMask) {
+ if(sFlpDeviceContextInterface == NULL) {
+ ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
+ }
+
+ int result = sFlpDeviceContextInterface->inject_device_context(enabledMask);
+ ThrowOnError(env, result, __FUNCTION__);
+}
+
+static jboolean IsGeofencingSupported() {
+ return sFlpGeofencingInterface != NULL;
+}
+
+static void AddGeofences(
+ JNIEnv* env,
+ jobject object,
+ jintArray geofenceIdsArray,
+ jobjectArray geofencesArray) {
+ if(geofencesArray == NULL) {
+ ALOGE("Invalid Geofences to add: %p", geofencesArray);
+ ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
+ }
+
+ if (sFlpGeofencingInterface == NULL) {
+ ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
+ }
+
+ jint geofencesCount = env->GetArrayLength(geofenceIdsArray);
+ Geofence* geofences = new Geofence[geofencesCount];
+ if (geofences == NULL) {
+ ThrowOnError(env, FLP_RESULT_INSUFFICIENT_MEMORY, __FUNCTION__);
+ }
+
+ jint* ids = env->GetIntArrayElements(geofenceIdsArray, /* isCopy */ NULL);
+ for (int i = 0; i < geofencesCount; ++i) {
+ geofences[i].geofence_id = ids[i];
+
+ // TODO: fill in the GeofenceData
+
+ // TODO: fill in the GeofenceOptions
+ }
+
+ sFlpGeofencingInterface->add_geofences(geofencesCount, &geofences);
+ if (geofences != NULL) delete[] geofences;
+}
+
+static void PauseGeofence(JNIEnv* env, jobject object, jint geofenceId) {
+ if(sFlpGeofencingInterface == NULL) {
+ ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
+ }
+
+ sFlpGeofencingInterface->pause_geofence(geofenceId);
+}
+
+static void ResumeGeofence(
+ JNIEnv* env,
+ jobject object,
+ jint geofenceId,
+ jint monitorTransitions) {
+ if(sFlpGeofencingInterface == NULL) {
+ ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
+ }
+
+ sFlpGeofencingInterface->resume_geofence(geofenceId, monitorTransitions);
+}
+
+static void ModifyGeofenceOption(
+ JNIEnv* env,
+ jobject object,
+ jint geofenceId,
+ jint lastTransition,
+ jint monitorTransitions,
+ jint notificationResponsiveness,
+ jint unknownTimer,
+ jint sourcesToUse) {
+ if(sFlpGeofencingInterface == NULL) {
+ ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
+ }
+
+ GeofenceOptions options = {
+ lastTransition,
+ monitorTransitions,
+ notificationResponsiveness,
+ unknownTimer,
+ (uint32_t)sourcesToUse
+ };
+
+ sFlpGeofencingInterface->modify_geofence_option(geofenceId, &options);
+}
+
+static void RemoveGeofences(
+ JNIEnv* env,
+ jobject object,
+ jintArray geofenceIdsArray) {
+ if(sFlpGeofencingInterface == NULL) {
+ ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
+ }
+
+ jsize geofenceIdsCount = env->GetArrayLength(geofenceIdsArray);
+ jint* geofenceIds = env->GetIntArrayElements(geofenceIdsArray, /* isCopy */ NULL);
+ if(geofenceIds == NULL) {
+ ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
+ }
+
+ sFlpGeofencingInterface->remove_geofences(geofenceIdsCount, geofenceIds);
+}
+
+static JNINativeMethod sMethods[] = {
+ //{"name", "signature", functionPointer }
+ {"nativeClassInit", "()V", reinterpret_cast<void*>(ClassInit)},
+ {"nativeInit", "()V", reinterpret_cast<void*>(Init)},
+ {"nativeCleanup", "()V", reinterpret_cast<void*>(Cleanup)},
+ {"nativeIsSupported", "()Z", reinterpret_cast<void*>(IsSupported)},
+ {"nativeGetBatchSize", "()I", reinterpret_cast<void*>(GetBatchSize)},
+ {"nativeStartBatching",
+ "(ILandroid/location/FusedBatchOptions;)V",
+ reinterpret_cast<void*>(StartBatching)},
+ {"nativeUpdateBatchingOptions",
+ "(ILandroid/location/FusedBatchOptions;)V",
+ reinterpret_cast<void*>(UpdateBatchingOptions)},
+ {"nativeStopBatching", "(I)V", reinterpret_cast<void*>(StopBatching)},
+ {"nativeRequestBatchedLocation",
+ "(I)V",
+ reinterpret_cast<void*>(GetBatchedLocation)},
+ {"nativeInjectLocation",
+ "(Landroid/location/Location;)V",
+ reinterpret_cast<void*>(InjectLocation)},
+ {"nativeIsDiagnosticSupported",
+ "()Z",
+ reinterpret_cast<void*>(IsDiagnosticSupported)},
+ {"nativeInjectDiagnosticData",
+ "(Ljava/lang/String;)V",
+ reinterpret_cast<void*>(InjectDiagnosticData)},
+ {"nativeIsDeviceContextSupported",
+ "()Z",
+ reinterpret_cast<void*>(IsDeviceContextSupported)},
+ {"nativeInjectDeviceContext",
+ "(I)V",
+ reinterpret_cast<void*>(InjectDeviceContext)},
+ {"nativeIsGeofencingSupported",
+ "()Z",
+ reinterpret_cast<void*>(IsGeofencingSupported)},
+ {"nativeAddGeofences",
+ "([I[Landroid/location/Geofence;)V",
+ reinterpret_cast<void*>(AddGeofences)},
+ {"nativePauseGeofence", "(I)V", reinterpret_cast<void*>(PauseGeofence)},
+ {"nativeResumeGeofence", "(II)V", reinterpret_cast<void*>(ResumeGeofence)},
+ {"nativeModifyGeofenceOption",
+ "(IIIIII)V",
+ reinterpret_cast<void*>(ModifyGeofenceOption)},
+ {"nativeRemoveGeofences", "([I)V", reinterpret_cast<void*>(RemoveGeofences)}
+};
+
+/*
+ * Registration method invoked on JNI Load.
+ */
+int register_android_server_location_FlpHardwareProvider(JNIEnv* env) {
+ return jniRegisterNativeMethods(
+ env,
+ "com/android/server/location/FlpHardwareProvider",
+ sMethods,
+ NELEM(sMethods)
+ );
+}
+
+} /* name-space Android */
diff --git a/services/jni/onload.cpp b/services/jni/onload.cpp
index 736ef24..5427277 100644
--- a/services/jni/onload.cpp
+++ b/services/jni/onload.cpp
@@ -32,6 +32,7 @@
int register_android_server_VibratorService(JNIEnv* env);
int register_android_server_SystemServer(JNIEnv* env);
int register_android_server_location_GpsLocationProvider(JNIEnv* env);
+int register_android_server_location_FlpHardwareProvider(JNIEnv* env);
int register_android_server_connectivity_Vpn(JNIEnv* env);
int register_android_server_AssetAtlasService(JNIEnv* env);
};
@@ -61,6 +62,7 @@
register_android_server_VibratorService(env);
register_android_server_SystemServer(env);
register_android_server_location_GpsLocationProvider(env);
+ register_android_server_location_FlpHardwareProvider(env);
register_android_server_connectivity_Vpn(env);
register_android_server_AssetAtlasService(env);
diff --git a/wifi/java/android/net/wifi/WifiMonitor.java b/wifi/java/android/net/wifi/WifiMonitor.java
index fe3c709..92b8e46 100644
--- a/wifi/java/android/net/wifi/WifiMonitor.java
+++ b/wifi/java/android/net/wifi/WifiMonitor.java
@@ -32,7 +32,10 @@
import com.android.internal.util.Protocol;
import com.android.internal.util.StateMachine;
+import java.util.HashMap;
+import java.util.Iterator;
import java.util.List;
+import java.util.Map;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
@@ -44,6 +47,7 @@
*/
public class WifiMonitor {
+ private static final boolean DBG = false;
private static final String TAG = "WifiMonitor";
/** Events we receive from the supplicant daemon */
@@ -279,9 +283,6 @@
/* AP-STA-DISCONNECTED 42:fc:89:a8:96:09 */
private static final String AP_STA_DISCONNECTED_STR = "AP-STA-DISCONNECTED";
- private final StateMachine mStateMachine;
- private final WifiNative mWifiNative;
-
/* Supplicant events reported to a state machine */
private static final int BASE = Protocol.BASE_WIFI_MONITOR;
@@ -347,164 +348,324 @@
private static final String WPA_RECV_ERROR_STR = "recv error";
/**
- * Tracks consecutive receive errors
- */
- private int mRecvErrors = 0;
-
- /**
* Max errors before we close supplicant connection
*/
private static final int MAX_RECV_ERRORS = 10;
+ private final String mInterfaceName;
+ private final WifiNative mWifiNative;
+ private final StateMachine mWifiStateMachine;
+ private boolean mMonitoring;
+
public WifiMonitor(StateMachine wifiStateMachine, WifiNative wifiNative) {
- mStateMachine = wifiStateMachine;
+ if (DBG) Log.d(TAG, "Creating WifiMonitor");
mWifiNative = wifiNative;
+ mInterfaceName = wifiNative.mInterfaceName;
+ mWifiStateMachine = wifiStateMachine;
+ mMonitoring = false;
+
+ WifiMonitorSingleton.getMonitor().registerInterfaceMonitor(mInterfaceName, this);
}
public void startMonitoring() {
- new MonitorThread().start();
+ WifiMonitorSingleton.getMonitor().startMonitoring(mInterfaceName);
}
- class MonitorThread extends Thread {
- public MonitorThread() {
- super("WifiMonitor");
+ public void stopMonitoring() {
+ WifiMonitorSingleton.getMonitor().stopMonitoring(mInterfaceName);
+ }
+
+ public void stopSupplicant() {
+ WifiMonitorSingleton.getMonitor().stopSupplicant();
+ }
+
+ public void killSupplicant(boolean p2pSupported) {
+ WifiMonitorSingleton.getMonitor().killSupplicant(p2pSupported);
+ }
+
+ private static class WifiMonitorSingleton {
+ private static Object sSingletonLock = new Object();
+ private static WifiMonitorSingleton sWifiMonitorSingleton = null;
+ private HashMap<String, WifiMonitor> mIfaceMap = new HashMap<String, WifiMonitor>();
+ private boolean mConnected = false;
+ private WifiNative mWifiNative;
+
+ private WifiMonitorSingleton() {
}
- public void run() {
+ static WifiMonitorSingleton getMonitor() {
+ if (DBG) Log.d(TAG, "WifiMonitorSingleton gotten");
+ synchronized (sSingletonLock) {
+ if (sWifiMonitorSingleton == null) {
+ if (DBG) Log.d(TAG, "WifiMonitorSingleton created");
+ sWifiMonitorSingleton = new WifiMonitorSingleton();
+ }
+ }
+ return sWifiMonitorSingleton;
+ }
- if (connectToSupplicant()) {
- // Send a message indicating that it is now possible to send commands
- // to the supplicant
- mStateMachine.sendMessage(SUP_CONNECTION_EVENT);
- } else {
- mStateMachine.sendMessage(SUP_DISCONNECTION_EVENT);
+ public synchronized void startMonitoring(String iface) {
+ WifiMonitor m = mIfaceMap.get(iface);
+ if (m == null) {
+ Log.e(TAG, "startMonitor called with unknown iface=" + iface);
return;
}
+ Log.d(TAG, "startMonitoring(" + iface + ") with mConnected = " + mConnected);
+
+ if (mConnected) {
+ m.mMonitoring = true;
+ m.mWifiStateMachine.sendMessage(SUP_CONNECTION_EVENT);
+ } else {
+ if (DBG) Log.d(TAG, "connecting to supplicant");
+ int connectTries = 0;
+ while (true) {
+ if (mWifiNative.connectToSupplicant()) {
+ m.mMonitoring = true;
+ m.mWifiStateMachine.sendMessage(SUP_CONNECTION_EVENT);
+ new MonitorThread(mWifiNative, this).start();
+ mConnected = true;
+ break;
+ }
+ if (connectTries++ < 5) {
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException ignore) {
+ }
+ } else {
+ mIfaceMap.remove(iface);
+ m.mWifiStateMachine.sendMessage(SUP_DISCONNECTION_EVENT);
+ break;
+ }
+ }
+ }
+ }
+
+ public synchronized void stopMonitoring(String iface) {
+ WifiMonitor m = mIfaceMap.get(iface);
+ if (DBG) Log.d(TAG, "stopMonitoring(" + iface + ") = " + m.mWifiStateMachine);
+ m.mMonitoring = false;
+ m.mWifiStateMachine.sendMessage(SUP_DISCONNECTION_EVENT);
+ }
+
+ public synchronized void registerInterfaceMonitor(String iface, WifiMonitor m) {
+ if (DBG) Log.d(TAG, "registerInterface(" + iface + "+" + m.mWifiStateMachine + ")");
+ mIfaceMap.put(iface, m);
+ if (mWifiNative == null) {
+ mWifiNative = m.mWifiNative;
+ }
+ }
+
+ public synchronized void unregisterInterfaceMonitor(String iface) {
+ // REVIEW: When should we call this? If this isn't called, then WifiMonitor
+ // objects will remain in the mIfaceMap; and won't ever get deleted
+
+ WifiMonitor m = mIfaceMap.remove(iface);
+ if (DBG) Log.d(TAG, "unregisterInterface(" + iface + "+" + m.mWifiStateMachine + ")");
+ }
+
+ public synchronized void stopSupplicant() {
+ mWifiNative.stopSupplicant();
+ }
+
+ public synchronized void killSupplicant(boolean p2pSupported) {
+ mWifiNative.killSupplicant(p2pSupported);
+ mConnected = false;
+ Iterator<Map.Entry<String, WifiMonitor>> it = mIfaceMap.entrySet().iterator();
+ while (it.hasNext()) {
+ Map.Entry<String, WifiMonitor> e = it.next();
+ WifiMonitor m = e.getValue();
+ m.mMonitoring = false;
+ }
+ }
+
+ private synchronized WifiMonitor getMonitor(String iface) {
+ return mIfaceMap.get(iface);
+ }
+ }
+
+ private static class MonitorThread extends Thread {
+ private final WifiNative mWifiNative;
+ private final WifiMonitorSingleton mWifiMonitorSingleton;
+ private int mRecvErrors = 0;
+ private StateMachine mStateMachine = null;
+
+ public MonitorThread(WifiNative wifiNative, WifiMonitorSingleton wifiMonitorSingleton) {
+ super("WifiMonitor");
+ mWifiNative = wifiNative;
+ mWifiMonitorSingleton = wifiMonitorSingleton;
+ }
+
+ public void run() {
//noinspection InfiniteLoopStatement
for (;;) {
String eventStr = mWifiNative.waitForEvent();
// Skip logging the common but mostly uninteresting scan-results event
- if (false && eventStr.indexOf(SCAN_RESULTS_STR) == -1) {
+ if (DBG && eventStr.indexOf(SCAN_RESULTS_STR) == -1) {
Log.d(TAG, "Event [" + eventStr + "]");
}
- if (!eventStr.startsWith(EVENT_PREFIX_STR)) {
- if (eventStr.startsWith(WPA_EVENT_PREFIX_STR) &&
- 0 < eventStr.indexOf(PASSWORD_MAY_BE_INCORRECT_STR)) {
- mStateMachine.sendMessage(AUTHENTICATION_FAILURE_EVENT);
- } else if (eventStr.startsWith(WPS_SUCCESS_STR)) {
- mStateMachine.sendMessage(WPS_SUCCESS_EVENT);
- } else if (eventStr.startsWith(WPS_FAIL_STR)) {
- handleWpsFailEvent(eventStr);
- } else if (eventStr.startsWith(WPS_OVERLAP_STR)) {
- mStateMachine.sendMessage(WPS_OVERLAP_EVENT);
- } else if (eventStr.startsWith(WPS_TIMEOUT_STR)) {
- mStateMachine.sendMessage(WPS_TIMEOUT_EVENT);
- } else if (eventStr.startsWith(P2P_EVENT_PREFIX_STR)) {
- handleP2pEvents(eventStr);
- } else if (eventStr.startsWith(HOST_AP_EVENT_PREFIX_STR)) {
- handleHostApEvents(eventStr);
+
+ WifiMonitor m = null;
+ mStateMachine = null;
+
+ if (eventStr.startsWith("IFNAME=")) {
+ int space = eventStr.indexOf(' ');
+ if (space != -1) {
+ String iface = eventStr.substring(7,space);
+ m = mWifiMonitorSingleton.getMonitor(iface);
+ if (m != null) {
+ if (m.mMonitoring) {
+ mStateMachine = m.mWifiStateMachine;
+ eventStr = eventStr.substring(space + 1);
+ }
+ else {
+ if (DBG) Log.d(TAG, "Dropping event because monitor (" + iface +
+ ") is stopped");
+ continue;
+ }
+ }
+ else {
+ eventStr = eventStr.substring(space + 1);
+ }
}
- continue;
}
- String eventName = eventStr.substring(EVENT_PREFIX_LEN_STR);
- int nameEnd = eventName.indexOf(' ');
- if (nameEnd != -1)
- eventName = eventName.substring(0, nameEnd);
- if (eventName.length() == 0) {
- if (false) Log.i(TAG, "Received wpa_supplicant event with empty event name");
- continue;
- }
- /*
- * Map event name into event enum
- */
- int event;
- if (eventName.equals(CONNECTED_STR))
- event = CONNECTED;
- else if (eventName.equals(DISCONNECTED_STR))
- event = DISCONNECTED;
- else if (eventName.equals(STATE_CHANGE_STR))
- event = STATE_CHANGE;
- else if (eventName.equals(SCAN_RESULTS_STR))
- event = SCAN_RESULTS;
- else if (eventName.equals(LINK_SPEED_STR))
- event = LINK_SPEED;
- else if (eventName.equals(TERMINATING_STR))
- event = TERMINATING;
- else if (eventName.equals(DRIVER_STATE_STR))
- event = DRIVER_STATE;
- else if (eventName.equals(EAP_FAILURE_STR))
- event = EAP_FAILURE;
- else if (eventName.equals(ASSOC_REJECT_STR))
- event = ASSOC_REJECT;
- else
- event = UNKNOWN;
-
- String eventData = eventStr;
- if (event == DRIVER_STATE || event == LINK_SPEED)
- eventData = eventData.split(" ")[1];
- else if (event == STATE_CHANGE || event == EAP_FAILURE) {
- int ind = eventStr.indexOf(" ");
- if (ind != -1) {
- eventData = eventStr.substring(ind + 1);
+ if (mStateMachine != null) {
+ if (dispatchEvent(eventStr)) {
+ break;
}
} else {
- int ind = eventStr.indexOf(" - ");
- if (ind != -1) {
- eventData = eventStr.substring(ind + 3);
- }
- }
-
- if (event == STATE_CHANGE) {
- handleSupplicantStateChange(eventData);
- } else if (event == DRIVER_STATE) {
- handleDriverEvent(eventData);
- } else if (event == TERMINATING) {
- /**
- * Close the supplicant connection if we see
- * too many recv errors
- */
- if (eventData.startsWith(WPA_RECV_ERROR_STR)) {
- if (++mRecvErrors > MAX_RECV_ERRORS) {
- if (false) {
- Log.d(TAG, "too many recv errors, closing connection");
- }
- } else {
- continue;
+ if (DBG) Log.d(TAG, "Sending to all monitors because there's no interface id");
+ boolean done = false;
+ Iterator<Map.Entry<String, WifiMonitor>> it =
+ mWifiMonitorSingleton.mIfaceMap.entrySet().iterator();
+ while (it.hasNext()) {
+ Map.Entry<String, WifiMonitor> e = it.next();
+ m = e.getValue();
+ mStateMachine = m.mWifiStateMachine;
+ if (dispatchEvent(eventStr)) {
+ done = true;
}
}
- // notify and exit
- mStateMachine.sendMessage(SUP_DISCONNECTION_EVENT);
- break;
- } else if (event == EAP_FAILURE) {
- if (eventData.startsWith(EAP_AUTH_FAILURE_STR)) {
- mStateMachine.sendMessage(AUTHENTICATION_FAILURE_EVENT);
+ if (done) {
+ // After this thread terminates, we'll no longer
+ // be connected to the supplicant
+ if (DBG) Log.d(TAG, "Disconnecting from the supplicant, no more events");
+ mWifiMonitorSingleton.mConnected = false;
+ break;
}
- } else if (event == ASSOC_REJECT) {
- mStateMachine.sendMessage(ASSOCIATION_REJECTION_EVENT);
- } else {
- handleEvent(event, eventData);
}
- mRecvErrors = 0;
}
}
- private boolean connectToSupplicant() {
- int connectTries = 0;
+ /* @return true if the event was supplicant disconnection */
+ private boolean dispatchEvent(String eventStr) {
- while (true) {
- if (mWifiNative.connectToSupplicant()) {
- return true;
+ if (!eventStr.startsWith(EVENT_PREFIX_STR)) {
+ if (eventStr.startsWith(WPA_EVENT_PREFIX_STR) &&
+ 0 < eventStr.indexOf(PASSWORD_MAY_BE_INCORRECT_STR)) {
+ mStateMachine.sendMessage(AUTHENTICATION_FAILURE_EVENT);
+ } else if (eventStr.startsWith(WPS_SUCCESS_STR)) {
+ mStateMachine.sendMessage(WPS_SUCCESS_EVENT);
+ } else if (eventStr.startsWith(WPS_FAIL_STR)) {
+ handleWpsFailEvent(eventStr);
+ } else if (eventStr.startsWith(WPS_OVERLAP_STR)) {
+ mStateMachine.sendMessage(WPS_OVERLAP_EVENT);
+ } else if (eventStr.startsWith(WPS_TIMEOUT_STR)) {
+ mStateMachine.sendMessage(WPS_TIMEOUT_EVENT);
+ } else if (eventStr.startsWith(P2P_EVENT_PREFIX_STR)) {
+ handleP2pEvents(eventStr);
+ } else if (eventStr.startsWith(HOST_AP_EVENT_PREFIX_STR)) {
+ handleHostApEvents(eventStr);
}
- if (connectTries++ < 5) {
- nap(1);
- } else {
- break;
+ else {
+ if (DBG) Log.w(TAG, "couldn't identify event type - " + eventStr);
+ }
+ return false;
+ }
+
+ String eventName = eventStr.substring(EVENT_PREFIX_LEN_STR);
+ int nameEnd = eventName.indexOf(' ');
+ if (nameEnd != -1)
+ eventName = eventName.substring(0, nameEnd);
+ if (eventName.length() == 0) {
+ if (DBG) Log.i(TAG, "Received wpa_supplicant event with empty event name");
+ return false;
+ }
+ /*
+ * Map event name into event enum
+ */
+ int event;
+ if (eventName.equals(CONNECTED_STR))
+ event = CONNECTED;
+ else if (eventName.equals(DISCONNECTED_STR))
+ event = DISCONNECTED;
+ else if (eventName.equals(STATE_CHANGE_STR))
+ event = STATE_CHANGE;
+ else if (eventName.equals(SCAN_RESULTS_STR))
+ event = SCAN_RESULTS;
+ else if (eventName.equals(LINK_SPEED_STR))
+ event = LINK_SPEED;
+ else if (eventName.equals(TERMINATING_STR))
+ event = TERMINATING;
+ else if (eventName.equals(DRIVER_STATE_STR))
+ event = DRIVER_STATE;
+ else if (eventName.equals(EAP_FAILURE_STR))
+ event = EAP_FAILURE;
+ else if (eventName.equals(ASSOC_REJECT_STR))
+ event = ASSOC_REJECT;
+ else
+ event = UNKNOWN;
+
+ String eventData = eventStr;
+ if (event == DRIVER_STATE || event == LINK_SPEED)
+ eventData = eventData.split(" ")[1];
+ else if (event == STATE_CHANGE || event == EAP_FAILURE) {
+ int ind = eventStr.indexOf(" ");
+ if (ind != -1) {
+ eventData = eventStr.substring(ind + 1);
+ }
+ } else {
+ int ind = eventStr.indexOf(" - ");
+ if (ind != -1) {
+ eventData = eventStr.substring(ind + 3);
}
}
+
+ if (event == STATE_CHANGE) {
+ handleSupplicantStateChange(eventData);
+ } else if (event == DRIVER_STATE) {
+ handleDriverEvent(eventData);
+ } else if (event == TERMINATING) {
+ /**
+ * Close the supplicant connection if we see
+ * too many recv errors
+ */
+ if (eventData.startsWith(WPA_RECV_ERROR_STR)) {
+ if (++mRecvErrors > MAX_RECV_ERRORS) {
+ if (DBG) {
+ Log.d(TAG, "too many recv errors, closing connection");
+ }
+ } else {
+ return false;
+ }
+ }
+
+ // notify and exit
+ mStateMachine.sendMessage(SUP_DISCONNECTION_EVENT);
+ return true;
+ } else if (event == EAP_FAILURE) {
+ if (eventData.startsWith(EAP_AUTH_FAILURE_STR)) {
+ mStateMachine.sendMessage(AUTHENTICATION_FAILURE_EVENT);
+ }
+ } else if (event == ASSOC_REJECT) {
+ mStateMachine.sendMessage(ASSOCIATION_REJECTION_EVENT);
+ } else {
+ handleEvent(event, eventData);
+ }
+ mRecvErrors = 0;
return false;
}
@@ -723,71 +884,60 @@
}
notifySupplicantStateChange(networkId, wifiSsid, BSSID, newSupplicantState);
}
- }
- private void handleNetworkStateChange(NetworkInfo.DetailedState newState, String data) {
- String BSSID = null;
- int networkId = -1;
- if (newState == NetworkInfo.DetailedState.CONNECTED) {
- Matcher match = mConnectedEventPattern.matcher(data);
- if (!match.find()) {
- if (false) Log.d(TAG, "Could not find BSSID in CONNECTED event string");
- } else {
- BSSID = match.group(1);
- try {
- networkId = Integer.parseInt(match.group(2));
- } catch (NumberFormatException e) {
- networkId = -1;
+ private void handleNetworkStateChange(NetworkInfo.DetailedState newState, String data) {
+ String BSSID = null;
+ int networkId = -1;
+ if (newState == NetworkInfo.DetailedState.CONNECTED) {
+ Matcher match = mConnectedEventPattern.matcher(data);
+ if (!match.find()) {
+ if (DBG) Log.d(TAG, "Could not find BSSID in CONNECTED event string");
+ } else {
+ BSSID = match.group(1);
+ try {
+ networkId = Integer.parseInt(match.group(2));
+ } catch (NumberFormatException e) {
+ networkId = -1;
+ }
}
+ notifyNetworkStateChange(newState, BSSID, networkId);
}
}
- notifyNetworkStateChange(newState, BSSID, networkId);
- }
- /**
- * Send the state machine a notification that the state of Wifi connectivity
- * has changed.
- * @param networkId the configured network on which the state change occurred
- * @param newState the new network state
- * @param BSSID when the new state is {@link DetailedState#CONNECTED
- * NetworkInfo.DetailedState.CONNECTED},
- * this is the MAC address of the access point. Otherwise, it
- * is {@code null}.
- */
- void notifyNetworkStateChange(NetworkInfo.DetailedState newState, String BSSID, int netId) {
- if (newState == NetworkInfo.DetailedState.CONNECTED) {
- Message m = mStateMachine.obtainMessage(NETWORK_CONNECTION_EVENT,
- netId, 0, BSSID);
- mStateMachine.sendMessage(m);
- } else {
- Message m = mStateMachine.obtainMessage(NETWORK_DISCONNECTION_EVENT,
- netId, 0, BSSID);
- mStateMachine.sendMessage(m);
+ /**
+ * Send the state machine a notification that the state of Wifi connectivity
+ * has changed.
+ * @param networkId the configured network on which the state change occurred
+ * @param newState the new network state
+ * @param BSSID when the new state is {@link DetailedState#CONNECTED
+ * NetworkInfo.DetailedState.CONNECTED},
+ * this is the MAC address of the access point. Otherwise, it
+ * is {@code null}.
+ */
+ void notifyNetworkStateChange(NetworkInfo.DetailedState newState, String BSSID, int netId) {
+ if (newState == NetworkInfo.DetailedState.CONNECTED) {
+ Message m = mStateMachine.obtainMessage(NETWORK_CONNECTION_EVENT,
+ netId, 0, BSSID);
+ mStateMachine.sendMessage(m);
+ } else {
+ Message m = mStateMachine.obtainMessage(NETWORK_DISCONNECTION_EVENT,
+ netId, 0, BSSID);
+ mStateMachine.sendMessage(m);
+ }
}
- }
- /**
- * Send the state machine a notification that the state of the supplicant
- * has changed.
- * @param networkId the configured network on which the state change occurred
- * @param wifiSsid network name
- * @param BSSID network address
- * @param newState the new {@code SupplicantState}
- */
- void notifySupplicantStateChange(int networkId, WifiSsid wifiSsid, String BSSID,
- SupplicantState newState) {
- mStateMachine.sendMessage(mStateMachine.obtainMessage(SUPPLICANT_STATE_CHANGE_EVENT,
- new StateChangeResult(networkId, wifiSsid, BSSID, newState)));
- }
-
- /**
- * Sleep for a period of time.
- * @param secs the number of seconds to sleep
- */
- private static void nap(int secs) {
- try {
- Thread.sleep(secs * 1000);
- } catch (InterruptedException ignore) {
+ /**
+ * Send the state machine a notification that the state of the supplicant
+ * has changed.
+ * @param networkId the configured network on which the state change occurred
+ * @param wifiSsid network name
+ * @param BSSID network address
+ * @param newState the new {@code SupplicantState}
+ */
+ void notifySupplicantStateChange(int networkId, WifiSsid wifiSsid, String BSSID,
+ SupplicantState newState) {
+ mStateMachine.sendMessage(mStateMachine.obtainMessage(SUPPLICANT_STATE_CHANGE_EVENT,
+ new StateChangeResult(networkId, wifiSsid, BSSID, newState)));
}
}
}
diff --git a/wifi/java/android/net/wifi/WifiNative.java b/wifi/java/android/net/wifi/WifiNative.java
index b1dd2ce..d30c7cf 100644
--- a/wifi/java/android/net/wifi/WifiNative.java
+++ b/wifi/java/android/net/wifi/WifiNative.java
@@ -47,7 +47,9 @@
static final int SCAN_WITHOUT_CONNECTION_SETUP = 1;
static final int SCAN_WITH_CONNECTION_SETUP = 2;
- String mInterface = "";
+ public final String mInterfaceName;
+ public final String mInterfacePrefix;
+
private boolean mSuspendOptEnabled = false;
public native static boolean loadDriver();
@@ -62,52 +64,53 @@
or when the supplicant is hung */
public native static boolean killSupplicant(boolean p2pSupported);
- private native boolean connectToSupplicant(String iface);
+ private native boolean connectToSupplicantNative();
- private native void closeSupplicantConnection(String iface);
+ private native void closeSupplicantConnectionNative();
/**
* Wait for the supplicant to send an event, returning the event string.
* @return the event string sent by the supplicant.
*/
- private native String waitForEvent(String iface);
+ private native String waitForEventNative();
- private native boolean doBooleanCommand(String iface, String command);
+ private native boolean doBooleanCommandNative(String command);
- private native int doIntCommand(String iface, String command);
+ private native int doIntCommandNative(String command);
- private native String doStringCommand(String iface, String command);
+ private native String doStringCommandNative(String command);
- public WifiNative(String iface) {
- mInterface = iface;
- mTAG = "WifiNative-" + iface;
+ public WifiNative(String interfaceName) {
+ mInterfaceName = interfaceName;
+ mInterfacePrefix = "IFNAME=" + interfaceName + " ";
+ mTAG = "WifiNative-" + interfaceName;
}
public boolean connectToSupplicant() {
- return connectToSupplicant(mInterface);
+ return connectToSupplicantNative();
}
public void closeSupplicantConnection() {
- closeSupplicantConnection(mInterface);
+ closeSupplicantConnectionNative();
}
public String waitForEvent() {
- return waitForEvent(mInterface);
+ return waitForEventNative();
}
private boolean doBooleanCommand(String command) {
if (DBG) Log.d(mTAG, "doBoolean: " + command);
- return doBooleanCommand(mInterface, command);
+ return doBooleanCommandNative(mInterfacePrefix + command);
}
private int doIntCommand(String command) {
if (DBG) Log.d(mTAG, "doInt: " + command);
- return doIntCommand(mInterface, command);
+ return doIntCommandNative(mInterfacePrefix + command);
}
private String doStringCommand(String command) {
if (DBG) Log.d(mTAG, "doString: " + command);
- return doStringCommand(mInterface, command);
+ return doStringCommandNative(mInterfacePrefix + command);
}
public boolean ping() {
@@ -411,9 +414,9 @@
public boolean startWpsPbc(String iface, String bssid) {
if (TextUtils.isEmpty(bssid)) {
- return doBooleanCommand("IFNAME=" + iface + " WPS_PBC");
+ return doBooleanCommandNative("IFNAME=" + iface + " WPS_PBC");
} else {
- return doBooleanCommand("IFNAME=" + iface + " WPS_PBC " + bssid);
+ return doBooleanCommandNative("IFNAME=" + iface + " WPS_PBC " + bssid);
}
}
@@ -424,7 +427,7 @@
public boolean startWpsPinKeypad(String iface, String pin) {
if (TextUtils.isEmpty(pin)) return false;
- return doBooleanCommand("IFNAME=" + iface + " WPS_PIN any " + pin);
+ return doBooleanCommandNative("IFNAME=" + iface + " WPS_PIN any " + pin);
}
@@ -438,9 +441,9 @@
public String startWpsPinDisplay(String iface, String bssid) {
if (TextUtils.isEmpty(bssid)) {
- return doStringCommand("IFNAME=" + iface + " WPS_PIN any");
+ return doStringCommandNative("IFNAME=" + iface + " WPS_PIN any");
} else {
- return doStringCommand("IFNAME=" + iface + " WPS_PIN " + bssid);
+ return doStringCommandNative("IFNAME=" + iface + " WPS_PIN " + bssid);
}
}
@@ -492,7 +495,7 @@
}
public boolean setP2pGroupIdle(String iface, int time) {
- return doBooleanCommand("IFNAME=" + iface + " SET p2p_group_idle " + time);
+ return doBooleanCommandNative("IFNAME=" + iface + " SET p2p_group_idle " + time);
}
public void setPowerSave(boolean enabled) {
@@ -505,9 +508,9 @@
public boolean setP2pPowerSave(String iface, boolean enabled) {
if (enabled) {
- return doBooleanCommand("IFNAME=" + iface + " P2P_SET ps 1");
+ return doBooleanCommandNative("IFNAME=" + iface + " P2P_SET ps 1");
} else {
- return doBooleanCommand("IFNAME=" + iface + " P2P_SET ps 0");
+ return doBooleanCommandNative("IFNAME=" + iface + " P2P_SET ps 0");
}
}
@@ -645,7 +648,7 @@
public boolean p2pGroupRemove(String iface) {
if (TextUtils.isEmpty(iface)) return false;
- return doBooleanCommand("P2P_GROUP_REMOVE " + iface);
+ return doBooleanCommandNative("IFNAME=" + iface + " P2P_GROUP_REMOVE " + iface);
}
public boolean p2pReject(String deviceAddress) {
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
index 4628c91..91702f9 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -68,6 +68,7 @@
import android.os.UserHandle;
import android.os.WorkSource;
import android.provider.Settings;
+import android.util.Log;
import android.util.LruCache;
import android.text.TextUtils;
@@ -543,7 +544,6 @@
public WifiStateMachine(Context context, String wlanInterface) {
super("WifiStateMachine");
-
mContext = context;
mInterfaceName = wlanInterface;
@@ -888,6 +888,7 @@
* TODO: doc
*/
public void setOperationalMode(int mode) {
+ if (DBG) log("setting operational mode to " + String.valueOf(mode));
sendMessage(CMD_SET_OPERATIONAL_MODE, mode, 0);
}
@@ -1756,8 +1757,7 @@
/* Socket connection can be lost when we do a graceful shutdown
* or when the driver is hung. Ensure supplicant is stopped here.
*/
- mWifiNative.killSupplicant(mP2pSupported);
- mWifiNative.closeSupplicantConnection();
+ mWifiMonitor.killSupplicant(mP2pSupported);
sendSupplicantConnectionChangedBroadcast(false);
setWifiState(WIFI_STATE_DISABLED);
}
@@ -2139,7 +2139,7 @@
* Avoids issues with drivers that do not handle interface down
* on a running supplicant properly.
*/
- mWifiNative.killSupplicant(mP2pSupported);
+ mWifiMonitor.killSupplicant(mP2pSupported);
if(mWifiNative.startSupplicant(mP2pSupported)) {
setWifiState(WIFI_STATE_ENABLING);
if (DBG) log("Supplicant start successful");
@@ -2222,7 +2222,7 @@
case WifiMonitor.SUP_DISCONNECTION_EVENT:
if (++mSupplicantRestartCount <= SUPPLICANT_RESTART_TRIES) {
loge("Failed to setup control channel, restart supplicant");
- mWifiNative.killSupplicant(mP2pSupported);
+ mWifiMonitor.killSupplicant(mP2pSupported);
transitionTo(mInitialState);
sendMessageDelayed(CMD_START_SUPPLICANT, SUPPLICANT_RESTART_INTERVAL_MSECS);
} else {
@@ -2329,9 +2329,7 @@
}
if (DBG) log("stopping supplicant");
- if (!mWifiNative.stopSupplicant()) {
- loge("Failed to stop supplicant");
- }
+ mWifiMonitor.stopSupplicant();
/* Send ourselves a delayed message to indicate failure after a wait time */
sendMessageDelayed(obtainMessage(CMD_STOP_SUPPLICANT_FAILED,
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pService.java b/wifi/java/android/net/wifi/p2p/WifiP2pService.java
index 68a082a..63b94a2 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pService.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pService.java
@@ -858,7 +858,7 @@
}
if (mGroups.clear()) sendP2pPersistentGroupsChangedBroadcast();
- mWifiNative.closeSupplicantConnection();
+ mWifiMonitor.stopMonitoring();
transitionTo(mP2pDisablingState);
break;
case WifiP2pManager.SET_DEVICE_NAME: